1 /* 2 * Clipboard unit tests 3 * 4 * Copyright 2006 Kevin Koltzau 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #define COBJMACROS 22 #define CONST_VTABLE 23 #ifndef __REACTOS__ 24 #define NONAMELESSUNION 25 #endif 26 27 #include <stdarg.h> 28 #include <stdio.h> 29 30 #include "windef.h" 31 #include "winbase.h" 32 #include "objbase.h" 33 34 #include "wine/test.h" 35 36 #define InitFormatEtc(fe, cf, med) \ 37 {\ 38 (fe).cfFormat=cf;\ 39 (fe).dwAspect=DVASPECT_CONTENT;\ 40 (fe).ptd=NULL;\ 41 (fe).tymed=med;\ 42 (fe).lindex=-1;\ 43 }; 44 45 static inline char *dump_fmtetc(FORMATETC *fmt) 46 { 47 static char buf[100]; 48 49 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x", 50 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed); 51 return buf; 52 } 53 54 typedef struct DataObjectImpl { 55 IDataObject IDataObject_iface; 56 LONG ref; 57 58 FORMATETC *fmtetc; 59 UINT fmtetc_cnt; 60 61 HANDLE text; 62 IStream *stm; 63 IStorage *stg; 64 HMETAFILEPICT hmfp; 65 } DataObjectImpl; 66 67 typedef struct EnumFormatImpl { 68 IEnumFORMATETC IEnumFORMATETC_iface; 69 LONG ref; 70 71 FORMATETC *fmtetc; 72 UINT fmtetc_cnt; 73 74 UINT cur; 75 } EnumFormatImpl; 76 77 static BOOL expect_DataObjectImpl_QueryGetData = TRUE; 78 static ULONG DataObjectImpl_GetData_calls = 0; 79 static ULONG DataObjectImpl_GetDataHere_calls = 0; 80 static ULONG DataObjectImpl_EnumFormatEtc_calls = 0; 81 82 static UINT cf_stream, cf_storage, cf_global, cf_another, cf_onemore; 83 84 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc); 85 86 static HMETAFILE create_mf(void) 87 { 88 RECT rect = {0, 0, 100, 100}; 89 HDC hdc = CreateMetaFileA(NULL); 90 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL); 91 return CloseMetaFile(hdc); 92 } 93 94 static HMETAFILEPICT create_metafilepict(void) 95 { 96 HGLOBAL ret = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT)); 97 METAFILEPICT *mf = GlobalLock(ret); 98 mf->mm = MM_ANISOTROPIC; 99 mf->xExt = 100; 100 mf->yExt = 200; 101 mf->hMF = create_mf(); 102 GlobalUnlock(ret); 103 return ret; 104 } 105 106 static inline DataObjectImpl *impl_from_IDataObject(IDataObject *iface) 107 { 108 return CONTAINING_RECORD(iface, DataObjectImpl, IDataObject_iface); 109 } 110 111 static inline EnumFormatImpl *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface) 112 { 113 return CONTAINING_RECORD(iface, EnumFormatImpl, IEnumFORMATETC_iface); 114 } 115 116 static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj) 117 { 118 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface); 119 120 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) { 121 IEnumFORMATETC_AddRef(iface); 122 *ppvObj = &This->IEnumFORMATETC_iface; 123 return S_OK; 124 } 125 *ppvObj = NULL; 126 return E_NOINTERFACE; 127 } 128 129 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface) 130 { 131 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface); 132 LONG ref = InterlockedIncrement(&This->ref); 133 return ref; 134 } 135 136 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface) 137 { 138 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface); 139 ULONG ref = InterlockedDecrement(&This->ref); 140 141 if(!ref) { 142 HeapFree(GetProcessHeap(), 0, This->fmtetc); 143 HeapFree(GetProcessHeap(), 0, This); 144 } 145 146 return ref; 147 } 148 149 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt, 150 FORMATETC *rgelt, ULONG *pceltFetched) 151 { 152 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface); 153 ULONG count, i; 154 155 if (winetest_debug > 1) 156 trace("next: count %d cur %d\n", celt, This->cur); 157 158 if(!rgelt) 159 return E_INVALIDARG; 160 161 count = min(celt, This->fmtetc_cnt - This->cur); 162 for(i = 0; i < count; i++, This->cur++, rgelt++) 163 { 164 *rgelt = This->fmtetc[This->cur]; 165 if(rgelt->ptd) 166 { 167 DWORD size = This->fmtetc[This->cur].ptd->tdSize; 168 rgelt->ptd = CoTaskMemAlloc(size); 169 memcpy(rgelt->ptd, This->fmtetc[This->cur].ptd, size); 170 } 171 } 172 if(pceltFetched) 173 *pceltFetched = count; 174 return count == celt ? S_OK : S_FALSE; 175 } 176 177 static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt) 178 { 179 ok(0, "unexpected call\n"); 180 return E_NOTIMPL; 181 } 182 183 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface) 184 { 185 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface); 186 187 This->cur = 0; 188 return S_OK; 189 } 190 191 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum) 192 { 193 ok(0, "unexpected call\n"); 194 return E_NOTIMPL; 195 } 196 197 static const IEnumFORMATETCVtbl VT_EnumFormatImpl = { 198 EnumFormatImpl_QueryInterface, 199 EnumFormatImpl_AddRef, 200 EnumFormatImpl_Release, 201 EnumFormatImpl_Next, 202 EnumFormatImpl_Skip, 203 EnumFormatImpl_Reset, 204 EnumFormatImpl_Clone 205 }; 206 207 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc) 208 { 209 EnumFormatImpl *ret; 210 211 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl)); 212 ret->IEnumFORMATETC_iface.lpVtbl = &VT_EnumFormatImpl; 213 ret->ref = 1; 214 ret->cur = 0; 215 ret->fmtetc_cnt = fmtetc_cnt; 216 ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC)); 217 memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC)); 218 *lplpformatetc = &ret->IEnumFORMATETC_iface; 219 return S_OK; 220 } 221 222 static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj) 223 { 224 DataObjectImpl *This = impl_from_IDataObject(iface); 225 226 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) { 227 IDataObject_AddRef(iface); 228 *ppvObj = &This->IDataObject_iface; 229 return S_OK; 230 } 231 *ppvObj = NULL; 232 return E_NOINTERFACE; 233 } 234 235 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface) 236 { 237 DataObjectImpl *This = impl_from_IDataObject(iface); 238 ULONG ref = InterlockedIncrement(&This->ref); 239 return ref; 240 } 241 242 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface) 243 { 244 DataObjectImpl *This = impl_from_IDataObject(iface); 245 ULONG ref = InterlockedDecrement(&This->ref); 246 247 if(!ref) 248 { 249 int i; 250 if(This->text) GlobalFree(This->text); 251 for(i = 0; i < This->fmtetc_cnt; i++) 252 HeapFree(GetProcessHeap(), 0, This->fmtetc[i].ptd); 253 HeapFree(GetProcessHeap(), 0, This->fmtetc); 254 if(This->stm) IStream_Release(This->stm); 255 if(This->stg) IStorage_Release(This->stg); 256 if(This->hmfp) { 257 METAFILEPICT *mfp = GlobalLock(This->hmfp); 258 DeleteMetaFile(mfp->hMF); 259 GlobalUnlock(This->hmfp); 260 GlobalFree(This->hmfp); 261 } 262 HeapFree(GetProcessHeap(), 0, This); 263 } 264 265 return ref; 266 } 267 268 static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium) 269 { 270 DataObjectImpl *This = impl_from_IDataObject(iface); 271 UINT i; 272 273 trace("getdata: %s\n", dump_fmtetc(pformatetc)); 274 275 DataObjectImpl_GetData_calls++; 276 277 ok(pmedium->tymed == 0, "pmedium->tymed = %u\n", pmedium->tymed); 278 ok(U(*pmedium).hGlobal == NULL, "pmedium->hGlobal = %p\n", U(*pmedium).hGlobal); 279 ok(pmedium->pUnkForRelease == NULL, "pmedium->pUnkForRelease = %p\n", pmedium->pUnkForRelease); 280 281 if(pformatetc->lindex != -1) 282 return DV_E_FORMATETC; 283 284 for(i = 0; i < This->fmtetc_cnt; i++) 285 { 286 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) 287 { 288 if(This->fmtetc[i].tymed & pformatetc->tymed) 289 { 290 pmedium->pUnkForRelease = (LPUNKNOWN)iface; 291 IUnknown_AddRef(pmedium->pUnkForRelease); 292 293 if(pformatetc->cfFormat == CF_TEXT || pformatetc->cfFormat == cf_global) 294 { 295 pmedium->tymed = TYMED_HGLOBAL; 296 U(*pmedium).hGlobal = This->text; 297 } 298 else if(pformatetc->cfFormat == cf_stream) 299 { 300 pmedium->tymed = TYMED_ISTREAM; 301 IStream_AddRef(This->stm); 302 U(*pmedium).pstm = This->stm; 303 } 304 else if(pformatetc->cfFormat == cf_storage || pformatetc->cfFormat == cf_another) 305 { 306 pmedium->tymed = TYMED_ISTORAGE; 307 IStorage_AddRef(This->stg); 308 U(*pmedium).pstg = This->stg; 309 } 310 else if(pformatetc->cfFormat == CF_METAFILEPICT) 311 { 312 pmedium->tymed = TYMED_MFPICT; 313 U(*pmedium).hMetaFilePict = This->hmfp; 314 } 315 return S_OK; 316 } 317 } 318 } 319 320 return E_FAIL; 321 } 322 323 static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium) 324 { 325 trace("getdatahere: %s\n", dump_fmtetc(pformatetc)); 326 DataObjectImpl_GetDataHere_calls++; 327 328 return E_NOTIMPL; 329 } 330 331 static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc) 332 { 333 DataObjectImpl *This = impl_from_IDataObject(iface); 334 UINT i; 335 BOOL foundFormat = FALSE; 336 337 trace("querygetdata: %s\n", dump_fmtetc(pformatetc)); 338 if (!expect_DataObjectImpl_QueryGetData) 339 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n"); 340 341 if(pformatetc->lindex != -1) 342 return DV_E_LINDEX; 343 344 for(i=0; i<This->fmtetc_cnt; i++) { 345 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) { 346 foundFormat = TRUE; 347 if(This->fmtetc[i].tymed == pformatetc->tymed) 348 return S_OK; 349 } 350 } 351 return foundFormat?DV_E_FORMATETC:DV_E_TYMED; 352 } 353 354 static HRESULT WINAPI DataObjectImpl_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC *pformatectIn, 355 FORMATETC *pformatetcOut) 356 { 357 ok(0, "unexpected call\n"); 358 return E_NOTIMPL; 359 } 360 361 static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc, 362 STGMEDIUM *pmedium, BOOL fRelease) 363 { 364 ok(0, "unexpected call\n"); 365 return E_NOTIMPL; 366 } 367 368 static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwDirection, 369 IEnumFORMATETC **ppenumFormatEtc) 370 { 371 DataObjectImpl *This = impl_from_IDataObject(iface); 372 373 DataObjectImpl_EnumFormatEtc_calls++; 374 375 if(dwDirection != DATADIR_GET) { 376 ok(0, "unexpected direction %d\n", dwDirection); 377 return E_NOTIMPL; 378 } 379 return EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenumFormatEtc); 380 } 381 382 static HRESULT WINAPI DataObjectImpl_DAdvise(IDataObject* iface, FORMATETC *pformatetc, DWORD advf, 383 IAdviseSink *pAdvSink, DWORD *pdwConnection) 384 { 385 ok(0, "unexpected call\n"); 386 return E_NOTIMPL; 387 } 388 389 static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection) 390 { 391 ok(0, "unexpected call\n"); 392 return E_NOTIMPL; 393 } 394 395 static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise) 396 { 397 ok(0, "unexpected call\n"); 398 return E_NOTIMPL; 399 } 400 401 static const IDataObjectVtbl VT_DataObjectImpl = 402 { 403 DataObjectImpl_QueryInterface, 404 DataObjectImpl_AddRef, 405 DataObjectImpl_Release, 406 DataObjectImpl_GetData, 407 DataObjectImpl_GetDataHere, 408 DataObjectImpl_QueryGetData, 409 DataObjectImpl_GetCanonicalFormatEtc, 410 DataObjectImpl_SetData, 411 DataObjectImpl_EnumFormatEtc, 412 DataObjectImpl_DAdvise, 413 DataObjectImpl_DUnadvise, 414 DataObjectImpl_EnumDAdvise 415 }; 416 417 static HRESULT DataObjectImpl_CreateFromHGlobal(HGLOBAL text, LPDATAOBJECT *dataobj) 418 { 419 DataObjectImpl *obj; 420 421 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl)); 422 obj->IDataObject_iface.lpVtbl = &VT_DataObjectImpl; 423 obj->ref = 1; 424 obj->text = text; 425 obj->stm = NULL; 426 obj->stg = NULL; 427 obj->hmfp = NULL; 428 429 obj->fmtetc_cnt = 1; 430 obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC)); 431 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL); 432 433 *dataobj = &obj->IDataObject_iface; 434 return S_OK; 435 } 436 437 static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj) 438 { 439 HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1); 440 strcpy(GlobalLock(h), text); 441 GlobalUnlock(h); 442 return DataObjectImpl_CreateFromHGlobal(h, lplpdataobj); 443 } 444 445 static const char *cmpl_stm_data = "complex stream"; 446 static const char *cmpl_text_data = "complex text"; 447 static const WCHAR device_name[] = {'m','y','d','e','v',0}; 448 449 static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj) 450 { 451 DataObjectImpl *obj; 452 ILockBytes *lbs; 453 DEVMODEW dm; 454 455 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl)); 456 obj->IDataObject_iface.lpVtbl = &VT_DataObjectImpl; 457 obj->ref = 1; 458 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(cmpl_text_data) + 1); 459 strcpy(GlobalLock(obj->text), cmpl_text_data); 460 GlobalUnlock(obj->text); 461 CreateStreamOnHGlobal(NULL, TRUE, &obj->stm); 462 IStream_Write(obj->stm, cmpl_stm_data, strlen(cmpl_stm_data), NULL); 463 464 CreateILockBytesOnHGlobal(NULL, TRUE, &lbs); 465 StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &obj->stg); 466 ILockBytes_Release(lbs); 467 468 obj->hmfp = create_metafilepict(); 469 470 obj->fmtetc_cnt = 9; 471 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */ 472 obj->fmtetc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, obj->fmtetc_cnt*sizeof(FORMATETC)); 473 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL); 474 InitFormatEtc(obj->fmtetc[1], cf_stream, TYMED_ISTREAM); 475 InitFormatEtc(obj->fmtetc[2], cf_storage, TYMED_ISTORAGE); 476 InitFormatEtc(obj->fmtetc[3], cf_another, TYMED_ISTORAGE|TYMED_ISTREAM|TYMED_HGLOBAL); 477 if (0) /* Causes crashes on both Wine and Windows */ 478 { 479 memset(&dm, 0, sizeof(dm)); 480 dm.dmSize = sizeof(dm); 481 dm.dmDriverExtra = 0; 482 lstrcpyW(dm.dmDeviceName, device_name); 483 obj->fmtetc[3].ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra); 484 obj->fmtetc[3].ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra; 485 obj->fmtetc[3].ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData); 486 obj->fmtetc[3].ptd->tdDeviceNameOffset = 0; 487 obj->fmtetc[3].ptd->tdPortNameOffset = 0; 488 obj->fmtetc[3].ptd->tdExtDevmodeOffset = obj->fmtetc[3].ptd->tdDriverNameOffset + sizeof(device_name); 489 lstrcpyW((WCHAR*)obj->fmtetc[3].ptd->tdData, device_name); 490 memcpy(obj->fmtetc[3].ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra); 491 } 492 493 InitFormatEtc(obj->fmtetc[4], cf_global, TYMED_HGLOBAL); 494 InitFormatEtc(obj->fmtetc[5], cf_another, TYMED_HGLOBAL); 495 InitFormatEtc(obj->fmtetc[6], cf_another, 0xfffff); 496 InitFormatEtc(obj->fmtetc[7], cf_another, 0xfffff); 497 obj->fmtetc[7].dwAspect = DVASPECT_ICON; 498 InitFormatEtc(obj->fmtetc[8], CF_METAFILEPICT, TYMED_MFPICT); 499 500 *lplpdataobj = &obj->IDataObject_iface; 501 return S_OK; 502 } 503 504 static void test_get_clipboard_uninitialized(void) 505 { 506 HRESULT hr; 507 IDataObject *pDObj; 508 509 pDObj = (IDataObject *)0xdeadbeef; 510 hr = OleGetClipboard(&pDObj); 511 todo_wine ok(hr == S_OK, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr, S_OK); 512 if (pDObj && pDObj != (IDataObject *)0xdeadbeef) IDataObject_Release(pDObj); 513 } 514 515 static void test_get_clipboard(void) 516 { 517 HRESULT hr; 518 IDataObject *data_obj; 519 FORMATETC fmtetc; 520 STGMEDIUM stgmedium; 521 522 hr = OleGetClipboard(NULL); 523 ok(hr == E_INVALIDARG, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr); 524 525 hr = OleGetClipboard(&data_obj); 526 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr); 527 528 /* test IDataObject_QueryGetData */ 529 530 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */ 531 expect_DataObjectImpl_QueryGetData = FALSE; 532 533 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); 534 hr = IDataObject_QueryGetData(data_obj, &fmtetc); 535 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr); 536 537 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); 538 fmtetc.dwAspect = 0xdeadbeef; 539 hr = IDataObject_QueryGetData(data_obj, &fmtetc); 540 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); 541 542 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); 543 fmtetc.dwAspect = DVASPECT_THUMBNAIL; 544 hr = IDataObject_QueryGetData(data_obj, &fmtetc); 545 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); 546 547 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); 548 fmtetc.lindex = 256; 549 hr = IDataObject_QueryGetData(data_obj, &fmtetc); 550 ok(hr == DV_E_FORMATETC || broken(hr == S_OK), 551 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); 552 553 InitFormatEtc(fmtetc, CF_RIFF, TYMED_HGLOBAL); 554 hr = IDataObject_QueryGetData(data_obj, &fmtetc); 555 ok(hr == DV_E_CLIPFORMAT, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr); 556 557 InitFormatEtc(fmtetc, CF_TEXT, TYMED_FILE); 558 hr = IDataObject_QueryGetData(data_obj, &fmtetc); 559 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr); 560 561 expect_DataObjectImpl_QueryGetData = TRUE; 562 563 /* test IDataObject_GetData */ 564 565 DataObjectImpl_GetData_calls = 0; 566 567 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); 568 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); 569 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr); 570 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium); 571 572 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); 573 fmtetc.dwAspect = 0xdeadbeef; 574 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); 575 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr); 576 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium); 577 578 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); 579 fmtetc.dwAspect = DVASPECT_THUMBNAIL; 580 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); 581 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr); 582 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium); 583 584 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); 585 fmtetc.lindex = 256; 586 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); 587 ok(hr == DV_E_FORMATETC || broken(hr == S_OK), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); 588 if (hr == S_OK) 589 { 590 /* undo the unexpected success */ 591 DataObjectImpl_GetData_calls--; 592 ReleaseStgMedium(&stgmedium); 593 } 594 595 InitFormatEtc(fmtetc, CF_RIFF, TYMED_HGLOBAL); 596 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); 597 ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); 598 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium); 599 600 InitFormatEtc(fmtetc, CF_TEXT, TYMED_FILE); 601 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); 602 ok(hr == DV_E_TYMED, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr); 603 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium); 604 605 ok(DataObjectImpl_GetData_calls == 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls); 606 607 IDataObject_Release(data_obj); 608 } 609 610 static void test_enum_fmtetc(IDataObject *src) 611 { 612 HRESULT hr; 613 IDataObject *data; 614 IEnumFORMATETC *enum_fmt, *src_enum; 615 FORMATETC fmt, src_fmt; 616 DWORD count = 0; 617 618 hr = OleGetClipboard(&data); 619 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr); 620 621 hr = IDataObject_EnumFormatEtc(data, DATADIR_SET, &enum_fmt); 622 ok(hr == E_NOTIMPL || 623 broken(hr == E_INVALIDARG), /* win98 (not win98SE) */ 624 "got %08x\n", hr); 625 626 DataObjectImpl_EnumFormatEtc_calls = 0; 627 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt); 628 ok(hr == S_OK, "got %08x\n", hr); 629 ok(DataObjectImpl_EnumFormatEtc_calls == 0, "EnumFormatEtc was called\n"); 630 if (FAILED(hr)) 631 { 632 skip("EnumFormatEtc failed, skipping tests.\n"); 633 return; 634 } 635 636 if(src) IDataObject_EnumFormatEtc(src, DATADIR_GET, &src_enum); 637 638 while((hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL)) == S_OK) 639 { 640 ok(src != NULL, "shouldn't be here\n"); 641 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL); 642 ok(hr == S_OK, "%d: got %08x\n", count, hr); 643 trace("%d: %s\n", count, dump_fmtetc(&fmt)); 644 ok(fmt.cfFormat == src_fmt.cfFormat, "%d: %04x %04x\n", count, fmt.cfFormat, src_fmt.cfFormat); 645 ok(fmt.dwAspect == src_fmt.dwAspect, "%d: %08x %08x\n", count, fmt.dwAspect, src_fmt.dwAspect); 646 ok(fmt.lindex == src_fmt.lindex, "%d: %08x %08x\n", count, fmt.lindex, src_fmt.lindex); 647 ok(fmt.tymed == src_fmt.tymed, "%d: %08x %08x\n", count, fmt.tymed, src_fmt.tymed); 648 if(fmt.ptd) 649 { 650 ok(src_fmt.ptd != NULL, "%d: expected non-NULL\n", count); 651 CoTaskMemFree(fmt.ptd); 652 CoTaskMemFree(src_fmt.ptd); 653 } 654 count++; 655 } 656 657 ok(hr == S_FALSE, "%d: got %08x\n", count, hr); 658 659 if(src) 660 { 661 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL); 662 ok(hr == S_FALSE, "%d: got %08x\n", count, hr); 663 IEnumFORMATETC_Release(src_enum); 664 } 665 666 hr = IEnumFORMATETC_Reset(enum_fmt); 667 ok(hr == S_OK, "got %08x\n", hr); 668 669 if(src) /* Exercise the enumerator a bit */ 670 { 671 IEnumFORMATETC *clone; 672 FORMATETC third_fmt; 673 674 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL); 675 ok(hr == S_OK, "got %08x\n", hr); 676 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL); 677 ok(hr == S_OK, "got %08x\n", hr); 678 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL); 679 ok(hr == S_OK, "got %08x\n", hr); 680 681 hr = IEnumFORMATETC_Reset(enum_fmt); 682 ok(hr == S_OK, "got %08x\n", hr); 683 hr = IEnumFORMATETC_Skip(enum_fmt, 2); 684 ok(hr == S_OK, "got %08x\n", hr); 685 686 hr = IEnumFORMATETC_Clone(enum_fmt, &clone); 687 ok(hr == S_OK, "got %08x\n", hr); 688 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); 689 ok(hr == S_OK, "got %08x\n", hr); 690 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n"); 691 hr = IEnumFORMATETC_Next(clone, 1, &fmt, NULL); 692 ok(hr == S_OK, "got %08x\n", hr); 693 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n"); 694 IEnumFORMATETC_Release(clone); 695 } 696 697 IEnumFORMATETC_Release(enum_fmt); 698 IDataObject_Release(data); 699 } 700 701 static void test_no_cf_dataobject(void) 702 { 703 UINT cf_dataobject = RegisterClipboardFormatA("DataObject"); 704 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data"); 705 HANDLE h; 706 OpenClipboard(NULL); 707 708 h = GetClipboardData(cf_dataobject); 709 ok(!h, "got %p\n", h); 710 h = GetClipboardData(cf_ole_priv_data); 711 ok(!h, "got %p\n", h); 712 713 CloseClipboard(); 714 } 715 716 static void test_cf_dataobject(IDataObject *data) 717 { 718 UINT cf = 0; 719 UINT cf_dataobject = RegisterClipboardFormatA("DataObject"); 720 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data"); 721 BOOL found_dataobject = FALSE, found_priv_data = FALSE; 722 723 OpenClipboard(NULL); 724 do 725 { 726 cf = EnumClipboardFormats(cf); 727 if(cf == cf_dataobject) 728 { 729 HGLOBAL h = GetClipboardData(cf); 730 HWND *ptr = GlobalLock(h); 731 DWORD size = GlobalSize(h); 732 HWND clip_owner = GetClipboardOwner(); 733 734 found_dataobject = TRUE; 735 ok(size >= sizeof(*ptr), "size %d\n", size); 736 if(data) 737 ok(*ptr == clip_owner, "hwnd %p clip_owner %p\n", *ptr, clip_owner); 738 else /* ole clipboard flushed */ 739 ok(*ptr == NULL, "hwnd %p\n", *ptr); 740 GlobalUnlock(h); 741 } 742 else if(cf == cf_ole_priv_data) 743 { 744 found_priv_data = TRUE; 745 if(data) 746 { 747 HGLOBAL h = GetClipboardData(cf); 748 DWORD *ptr = GlobalLock(h); 749 DWORD size = GlobalSize(h); 750 751 if(size != ptr[1]) 752 win_skip("Ole Private Data in win9x format\n"); 753 else 754 { 755 HRESULT hr; 756 IEnumFORMATETC *enum_fmt; 757 DWORD count = 0; 758 FORMATETC fmt; 759 struct formatetcetc 760 { 761 FORMATETC fmt; 762 BOOL first_use_of_cf; 763 DWORD res[2]; 764 } *fmt_ptr; 765 struct priv_data 766 { 767 DWORD res1; 768 DWORD size; 769 DWORD res2; 770 DWORD count; 771 DWORD res3[2]; 772 struct formatetcetc fmts[1]; 773 } *priv = (struct priv_data*)ptr; 774 CLIPFORMAT cfs_seen[10]; 775 776 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt); 777 ok(hr == S_OK, "got %08x\n", hr); 778 fmt_ptr = priv->fmts; 779 780 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK) 781 { 782 int i; 783 BOOL seen_cf = FALSE; 784 785 ok(fmt_ptr->fmt.cfFormat == fmt.cfFormat, 786 "got %08x expected %08x\n", fmt_ptr->fmt.cfFormat, fmt.cfFormat); 787 ok(fmt_ptr->fmt.dwAspect == fmt.dwAspect, "got %08x expected %08x\n", 788 fmt_ptr->fmt.dwAspect, fmt.dwAspect); 789 ok(fmt_ptr->fmt.lindex == fmt.lindex, "got %08x expected %08x\n", 790 fmt_ptr->fmt.lindex, fmt.lindex); 791 ok(fmt_ptr->fmt.tymed == fmt.tymed, "got %08x expected %08x\n", 792 fmt_ptr->fmt.tymed, fmt.tymed); 793 for(i = 0; i < count; i++) 794 if(fmt_ptr->fmt.cfFormat == cfs_seen[i]) 795 { 796 seen_cf = TRUE; 797 break; 798 } 799 cfs_seen[count] = fmt.cfFormat; 800 ok(fmt_ptr->first_use_of_cf != seen_cf, "got %08x expected %08x\n", 801 fmt_ptr->first_use_of_cf, !seen_cf); 802 ok(fmt_ptr->res[0] == 0, "got %08x\n", fmt_ptr->res[0]); 803 ok(fmt_ptr->res[1] == 0, "got %08x\n", fmt_ptr->res[1]); 804 if(fmt.ptd) 805 { 806 DVTARGETDEVICE *target; 807 808 ok(fmt_ptr->fmt.ptd != NULL, "target device offset zero\n"); 809 target = (DVTARGETDEVICE*)((char*)priv + (DWORD_PTR)fmt_ptr->fmt.ptd); 810 ok(!memcmp(target, fmt.ptd, fmt.ptd->tdSize), "target devices differ\n"); 811 CoTaskMemFree(fmt.ptd); 812 } 813 fmt_ptr++; 814 count++; 815 } 816 ok(priv->res1 == 0, "got %08x\n", priv->res1); 817 ok(priv->res2 == 1, "got %08x\n", priv->res2); 818 ok(priv->count == count, "got %08x expected %08x\n", priv->count, count); 819 ok(priv->res3[0] == 0, "got %08x\n", priv->res3[0]); 820 821 /* win64 sets the lsb */ 822 if(sizeof(fmt_ptr->fmt.ptd) == 8) 823 todo_wine ok(priv->res3[1] == 1, "got %08x\n", priv->res3[1]); 824 else 825 ok(priv->res3[1] == 0, "got %08x\n", priv->res3[1]); 826 827 GlobalUnlock(h); 828 IEnumFORMATETC_Release(enum_fmt); 829 } 830 } 831 } 832 else if(cf == cf_stream) 833 { 834 HGLOBAL h; 835 void *ptr; 836 DWORD size; 837 838 DataObjectImpl_GetDataHere_calls = 0; 839 h = GetClipboardData(cf); 840 ok(DataObjectImpl_GetDataHere_calls == 1, "got %d\n", DataObjectImpl_GetDataHere_calls); 841 ptr = GlobalLock(h); 842 size = GlobalSize(h); 843 ok(size == strlen(cmpl_stm_data), 844 "expected %d got %d\n", lstrlenA(cmpl_stm_data), size); 845 ok(!memcmp(ptr, cmpl_stm_data, strlen(cmpl_stm_data)), "mismatch\n"); 846 GlobalUnlock(h); 847 } 848 else if(cf == cf_global) 849 { 850 HGLOBAL h; 851 void *ptr; 852 DWORD size; 853 854 DataObjectImpl_GetDataHere_calls = 0; 855 h = GetClipboardData(cf); 856 ok(DataObjectImpl_GetDataHere_calls == 0, "got %d\n", DataObjectImpl_GetDataHere_calls); 857 ptr = GlobalLock(h); 858 size = GlobalSize(h); 859 ok(size == strlen(cmpl_text_data) + 1, 860 "expected %d got %d\n", lstrlenA(cmpl_text_data) + 1, size); 861 ok(!memcmp(ptr, cmpl_text_data, strlen(cmpl_text_data) + 1), "mismatch\n"); 862 GlobalUnlock(h); 863 } 864 } while(cf); 865 CloseClipboard(); 866 ok(found_dataobject, "didn't find cf_dataobject\n"); 867 ok(found_priv_data, "didn't find cf_ole_priv_data\n"); 868 } 869 870 static void test_complex_get_clipboard(void) 871 { 872 HRESULT hr; 873 IDataObject *data_obj; 874 FORMATETC fmtetc; 875 STGMEDIUM stgmedium; 876 877 hr = OleGetClipboard(&data_obj); 878 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr); 879 880 DataObjectImpl_GetData_calls = 0; 881 882 InitFormatEtc(fmtetc, CF_METAFILEPICT, TYMED_MFPICT); 883 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); 884 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr); 885 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium); 886 887 InitFormatEtc(fmtetc, CF_METAFILEPICT, TYMED_HGLOBAL); 888 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); 889 ok(hr == DV_E_TYMED, "IDataObject_GetData failed with error 0x%08x\n", hr); 890 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium); 891 892 InitFormatEtc(fmtetc, CF_ENHMETAFILE, TYMED_HGLOBAL); 893 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); 894 ok(hr == DV_E_TYMED, "IDataObject_GetData failed with error 0x%08x\n", hr); 895 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium); 896 897 InitFormatEtc(fmtetc, CF_ENHMETAFILE, TYMED_ENHMF); 898 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); 899 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr); 900 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium); 901 902 ok(DataObjectImpl_GetData_calls == 5, 903 "DataObjectImpl_GetData called 5 times instead of %d times\n", 904 DataObjectImpl_GetData_calls); 905 IDataObject_Release(data_obj); 906 } 907 908 static void test_set_clipboard(void) 909 { 910 HRESULT hr; 911 ULONG ref; 912 LPDATAOBJECT data1, data2, data_cmpl; 913 HGLOBAL hblob, h; 914 void *ptr; 915 916 cf_stream = RegisterClipboardFormatA("stream format"); 917 cf_storage = RegisterClipboardFormatA("storage format"); 918 cf_global = RegisterClipboardFormatA("global format"); 919 cf_another = RegisterClipboardFormatA("another format"); 920 cf_onemore = RegisterClipboardFormatA("one more format"); 921 922 hr = DataObjectImpl_CreateText("data1", &data1); 923 ok(hr == S_OK, "Failed to create data1 object: 0x%08x\n", hr); 924 if(FAILED(hr)) 925 return; 926 hr = DataObjectImpl_CreateText("data2", &data2); 927 ok(hr == S_OK, "Failed to create data2 object: 0x%08x\n", hr); 928 if(FAILED(hr)) 929 return; 930 hr = DataObjectImpl_CreateComplex(&data_cmpl); 931 ok(hr == S_OK, "Failed to create complex data object: 0x%08x\n", hr); 932 if(FAILED(hr)) 933 return; 934 935 hr = OleSetClipboard(data1); 936 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr); 937 938 CoInitialize(NULL); 939 hr = OleSetClipboard(data1); 940 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard failed with 0x%08x\n", hr); 941 CoUninitialize(); 942 943 hr = OleInitialize(NULL); 944 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr); 945 946 hr = OleSetClipboard(data1); 947 ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr); 948 949 test_cf_dataobject(data1); 950 951 hr = OleIsCurrentClipboard(data1); 952 ok(hr == S_OK, "expected current clipboard to be data1, hr = 0x%08x\n", hr); 953 hr = OleIsCurrentClipboard(data2); 954 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr); 955 hr = OleIsCurrentClipboard(NULL); 956 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr); 957 958 test_get_clipboard(); 959 960 hr = OleSetClipboard(data2); 961 ok(hr == S_OK, "failed to set clipboard to data2, hr = 0x%08x\n", hr); 962 hr = OleIsCurrentClipboard(data1); 963 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr); 964 hr = OleIsCurrentClipboard(data2); 965 ok(hr == S_OK, "expected current clipboard to be data2, hr = 0x%08x\n", hr); 966 hr = OleIsCurrentClipboard(NULL); 967 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr); 968 969 /* put a format directly onto the clipboard to show 970 OleFlushClipboard doesn't empty the clipboard */ 971 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10); 972 ptr = GlobalLock( hblob ); 973 ok( ptr && ptr != hblob, "got fixed block %p / %p\n", ptr, hblob ); 974 GlobalUnlock( hblob ); 975 ok( OpenClipboard(NULL), "OpenClipboard failed\n" ); 976 h = SetClipboardData(cf_onemore, hblob); 977 ok(h == hblob, "got %p\n", h); 978 h = GetClipboardData(cf_onemore); 979 ok(h == hblob, "got %p / %p\n", h, hblob); 980 ptr = GlobalLock( h ); 981 ok( ptr && ptr != h, "got fixed block %p / %p\n", ptr, h ); 982 GlobalUnlock( hblob ); 983 ok( CloseClipboard(), "CloseClipboard failed\n" ); 984 985 hr = OleFlushClipboard(); 986 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr); 987 hr = OleIsCurrentClipboard(data1); 988 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr); 989 hr = OleIsCurrentClipboard(data2); 990 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr); 991 hr = OleIsCurrentClipboard(NULL); 992 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr); 993 994 /* format should survive the flush */ 995 ok( OpenClipboard(NULL), "OpenClipboard failed\n" ); 996 h = GetClipboardData(cf_onemore); 997 ok(h == hblob, "got %p\n", h); 998 ptr = GlobalLock( h ); 999 ok( ptr && ptr != h, "got fixed block %p / %p\n", ptr, h ); 1000 GlobalUnlock( hblob ); 1001 ok( CloseClipboard(), "CloseClipboard failed\n" ); 1002 1003 test_cf_dataobject(NULL); 1004 1005 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr); 1006 1007 OpenClipboard(NULL); 1008 h = GetClipboardData(cf_onemore); 1009 ok(h == NULL, "got %p\n", h); 1010 CloseClipboard(); 1011 1012 trace("setting complex\n"); 1013 hr = OleSetClipboard(data_cmpl); 1014 ok(hr == S_OK, "failed to set clipboard to complex data, hr = 0x%08x\n", hr); 1015 test_complex_get_clipboard(); 1016 test_cf_dataobject(data_cmpl); 1017 test_enum_fmtetc(data_cmpl); 1018 1019 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr); 1020 1021 test_no_cf_dataobject(); 1022 test_enum_fmtetc(NULL); 1023 1024 ref = IDataObject_Release(data1); 1025 ok(ref == 0, "expected data1 ref=0, got %d\n", ref); 1026 ref = IDataObject_Release(data2); 1027 ok(ref == 0, "expected data2 ref=0, got %d\n", ref); 1028 ref = IDataObject_Release(data_cmpl); 1029 ok(ref == 0, "expected data_cmpl ref=0, got %d\n", ref); 1030 1031 OleUninitialize(); 1032 } 1033 1034 static LPDATAOBJECT clip_data; 1035 static HWND next_wnd; 1036 static UINT wm_drawclipboard; 1037 1038 static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) 1039 { 1040 LRESULT ret; 1041 1042 switch (msg) 1043 { 1044 case WM_DRAWCLIPBOARD: 1045 wm_drawclipboard++; 1046 if (clip_data) 1047 { 1048 /* if this is the WM_DRAWCLIPBOARD of a previous change, the data isn't current yet */ 1049 /* this demonstrates an issue in Qt where it will free the data while it's being set */ 1050 HRESULT hr = OleIsCurrentClipboard( clip_data ); 1051 ok( hr == (wm_drawclipboard > 1) ? S_OK : S_FALSE, 1052 "OleIsCurrentClipboard returned %x\n", hr ); 1053 } 1054 break; 1055 case WM_CHANGECBCHAIN: 1056 if (next_wnd == (HWND)wp) next_wnd = (HWND)lp; 1057 else if (next_wnd) SendMessageA( next_wnd, msg, wp, lp ); 1058 break; 1059 case WM_USER: 1060 ret = wm_drawclipboard; 1061 wm_drawclipboard = 0; 1062 return ret; 1063 } 1064 1065 return DefWindowProcA(hwnd, msg, wp, lp); 1066 } 1067 1068 static DWORD CALLBACK set_clipboard_thread(void *arg) 1069 { 1070 OpenClipboard( GetDesktopWindow() ); 1071 EmptyClipboard(); 1072 SetClipboardData( CF_WAVE, 0 ); 1073 CloseClipboard(); 1074 return 0; 1075 } 1076 1077 /* test that WM_DRAWCLIPBOARD can be delivered for a previous change during OleSetClipboard */ 1078 static void test_set_clipboard_DRAWCLIPBOARD(void) 1079 { 1080 LPDATAOBJECT data; 1081 HRESULT hr; 1082 WNDCLASSA cls; 1083 HWND viewer; 1084 int ret; 1085 HANDLE thread; 1086 1087 hr = DataObjectImpl_CreateText("data", &data); 1088 ok(hr == S_OK, "Failed to create data object: 0x%08x\n", hr); 1089 1090 memset(&cls, 0, sizeof(cls)); 1091 cls.lpfnWndProc = clipboard_wnd_proc; 1092 cls.hInstance = GetModuleHandleA(NULL); 1093 cls.lpszClassName = "clipboard_test"; 1094 RegisterClassA(&cls); 1095 1096 viewer = CreateWindowA("clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0); 1097 ok(viewer != NULL, "CreateWindow failed: %d\n", GetLastError()); 1098 next_wnd = SetClipboardViewer( viewer ); 1099 1100 ret = SendMessageA( viewer, WM_USER, 0, 0 ); 1101 ok( ret == 1, "%u WM_DRAWCLIPBOARD received\n", ret ); 1102 1103 hr = OleInitialize(NULL); 1104 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr); 1105 1106 ret = SendMessageA( viewer, WM_USER, 0, 0 ); 1107 ok( !ret, "%u WM_DRAWCLIPBOARD received\n", ret ); 1108 1109 thread = CreateThread(NULL, 0, set_clipboard_thread, NULL, 0, NULL); 1110 ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError()); 1111 ret = WaitForSingleObject(thread, 5000); 1112 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret); 1113 1114 clip_data = data; 1115 hr = OleSetClipboard(data); 1116 ok(hr == S_OK, "failed to set clipboard to data, hr = 0x%08x\n", hr); 1117 1118 ret = SendMessageA( viewer, WM_USER, 0, 0 ); 1119 ok( ret == 2, "%u WM_DRAWCLIPBOARD received\n", ret ); 1120 1121 clip_data = NULL; 1122 hr = OleFlushClipboard(); 1123 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr); 1124 ret = IDataObject_Release(data); 1125 ok(ret == 0, "got %d\n", ret); 1126 1127 OleUninitialize(); 1128 ChangeClipboardChain( viewer, next_wnd ); 1129 DestroyWindow( viewer ); 1130 } 1131 1132 static inline ULONG count_refs(IDataObject *d) 1133 { 1134 IDataObject_AddRef(d); 1135 return IDataObject_Release(d); 1136 } 1137 1138 static void test_consumer_refs(void) 1139 { 1140 HRESULT hr; 1141 IDataObject *src, *src2, *get1, *get2, *get3; 1142 ULONG refs, old_refs; 1143 FORMATETC fmt; 1144 STGMEDIUM med; 1145 1146 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL); 1147 1148 OleInitialize(NULL); 1149 1150 /* First show that each clipboard state results in 1151 a different data object */ 1152 1153 hr = DataObjectImpl_CreateText("data1", &src); 1154 ok(hr == S_OK, "got %08x\n", hr); 1155 hr = DataObjectImpl_CreateText("data2", &src2); 1156 ok(hr == S_OK, "got %08x\n", hr); 1157 1158 hr = OleSetClipboard(src); 1159 ok(hr == S_OK, "got %08x\n", hr); 1160 1161 hr = OleGetClipboard(&get1); 1162 ok(hr == S_OK, "got %08x\n", hr); 1163 1164 hr = OleGetClipboard(&get2); 1165 ok(hr == S_OK, "got %08x\n", hr); 1166 1167 ok(get1 == get2, "data objects differ\n"); 1168 refs = IDataObject_Release(get2); 1169 ok(refs == (get1 == get2 ? 1 : 0), "got %d\n", refs); 1170 1171 OleFlushClipboard(); 1172 1173 DataObjectImpl_GetData_calls = 0; 1174 hr = IDataObject_GetData(get1, &fmt, &med); 1175 ok(hr == S_OK, "got %08x\n", hr); 1176 ok(DataObjectImpl_GetData_calls == 0, "GetData called\n"); 1177 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1178 1179 hr = OleGetClipboard(&get2); 1180 ok(hr == S_OK, "got %08x\n", hr); 1181 1182 ok(get1 != get2, "data objects match\n"); 1183 1184 OleSetClipboard(NULL); 1185 1186 hr = OleGetClipboard(&get3); 1187 ok(hr == S_OK, "got %08x\n", hr); 1188 1189 ok(get1 != get3, "data objects match\n"); 1190 ok(get2 != get3, "data objects match\n"); 1191 1192 IDataObject_Release(get3); 1193 IDataObject_Release(get2); 1194 IDataObject_Release(get1); 1195 1196 /* Now call GetData before the flush and show that this 1197 takes a ref on our src data obj. */ 1198 1199 hr = OleSetClipboard(src); 1200 ok(hr == S_OK, "got %08x\n", hr); 1201 1202 old_refs = count_refs(src); 1203 1204 hr = OleGetClipboard(&get1); 1205 ok(hr == S_OK, "got %08x\n", hr); 1206 1207 refs = count_refs(src); 1208 ok(refs == old_refs, "%d %d\n", refs, old_refs); 1209 1210 DataObjectImpl_GetData_calls = 0; 1211 hr = IDataObject_GetData(get1, &fmt, &med); 1212 ok(hr == S_OK, "got %08x\n", hr); 1213 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n"); 1214 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1215 refs = count_refs(src); 1216 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs); 1217 1218 OleFlushClipboard(); 1219 1220 DataObjectImpl_GetData_calls = 0; 1221 hr = IDataObject_GetData(get1, &fmt, &med); 1222 ok(hr == S_OK, "got %08x\n", hr); 1223 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n"); 1224 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1225 1226 refs = count_refs(src); 1227 ok(refs == 2, "%d\n", refs); 1228 1229 IDataObject_Release(get1); 1230 1231 refs = count_refs(src); 1232 ok(refs == 1, "%d\n", refs); 1233 1234 /* Now set a second src object before the call to GetData 1235 and show that GetData calls that second src. */ 1236 1237 hr = OleSetClipboard(src); 1238 ok(hr == S_OK, "got %08x\n", hr); 1239 1240 old_refs = count_refs(src); 1241 1242 hr = OleGetClipboard(&get1); 1243 ok(hr == S_OK, "got %08x\n", hr); 1244 1245 refs = count_refs(src); 1246 ok(refs == old_refs, "%d %d\n", refs, old_refs); 1247 1248 hr = OleSetClipboard(src2); 1249 ok(hr == S_OK, "got %08x\n", hr); 1250 1251 old_refs = count_refs(src2); 1252 1253 DataObjectImpl_GetData_calls = 0; 1254 hr = IDataObject_GetData(get1, &fmt, &med); 1255 ok(hr == S_OK, "got %08x\n", hr); 1256 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n"); 1257 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1258 1259 refs = count_refs(src); 1260 ok(refs == 1, "%d\n", refs); 1261 refs = count_refs(src2); 1262 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs); 1263 1264 OleSetClipboard(NULL); 1265 1266 refs = count_refs(src2); 1267 ok(refs == 2, "%d\n", refs); 1268 1269 IDataObject_Release(get1); 1270 1271 IDataObject_Release(src2); 1272 1273 /* Show that OleUninitialize() doesn't release the 1274 dataobject's ref, and thus the object is leaked. */ 1275 old_refs = count_refs(src); 1276 ok(old_refs == 1, "%d\n", old_refs); 1277 1278 OleSetClipboard(src); 1279 refs = count_refs(src); 1280 ok(refs > old_refs, "%d %d\n", refs, old_refs); 1281 1282 OleUninitialize(); 1283 refs = count_refs(src); 1284 ok(refs == 2, "%d\n", refs); 1285 1286 IDataObject_Release(src); 1287 } 1288 1289 static HGLOBAL create_storage(void) 1290 { 1291 ILockBytes *ilb; 1292 IStorage *stg; 1293 HGLOBAL hg; 1294 HRESULT hr; 1295 1296 hr = CreateILockBytesOnHGlobal(NULL, FALSE, &ilb); 1297 ok(hr == S_OK, "got %08x\n", hr); 1298 hr = StgCreateDocfileOnILockBytes(ilb, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg); 1299 ok(hr == S_OK, "got %08x\n", hr); 1300 IStorage_Release(stg); 1301 hr = GetHGlobalFromILockBytes(ilb, &hg); 1302 ok(hr == S_OK, "got %08x\n", hr); 1303 ILockBytes_Release(ilb); 1304 return hg; 1305 } 1306 1307 static void test_flushed_getdata(void) 1308 { 1309 HRESULT hr; 1310 IDataObject *src, *get; 1311 FORMATETC fmt; 1312 STGMEDIUM med; 1313 STATSTG stat; 1314 DEVMODEW dm; 1315 1316 OleInitialize(NULL); 1317 1318 hr = DataObjectImpl_CreateComplex(&src); 1319 ok(hr == S_OK, "got %08x\n", hr); 1320 1321 hr = OleSetClipboard(src); 1322 ok(hr == S_OK, "got %08x\n", hr); 1323 1324 hr = OleFlushClipboard(); 1325 ok(hr == S_OK, "got %08x\n", hr); 1326 1327 hr = OleGetClipboard(&get); 1328 ok(hr == S_OK, "got %08x\n", hr); 1329 1330 /* global format -> global & stream */ 1331 1332 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL); 1333 hr = IDataObject_GetData(get, &fmt, &med); 1334 ok(hr == S_OK, "got %08x\n", hr); 1335 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); 1336 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1337 1338 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTREAM); 1339 hr = IDataObject_GetData(get, &fmt, &med); 1340 ok(hr == S_OK, "got %08x\n", hr); 1341 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); 1342 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1343 1344 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTORAGE); 1345 hr = IDataObject_GetData(get, &fmt, &med); 1346 ok(hr == E_FAIL, "got %08x\n", hr); 1347 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1348 1349 InitFormatEtc(fmt, CF_TEXT, 0xffff); 1350 hr = IDataObject_GetData(get, &fmt, &med); 1351 ok(hr == S_OK, "got %08x\n", hr); 1352 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); 1353 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1354 1355 /* stream format -> global & stream */ 1356 1357 InitFormatEtc(fmt, cf_stream, TYMED_ISTREAM); 1358 hr = IDataObject_GetData(get, &fmt, &med); 1359 ok(hr == S_OK, "got %08x\n", hr); 1360 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); 1361 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1362 1363 InitFormatEtc(fmt, cf_stream, TYMED_ISTORAGE); 1364 hr = IDataObject_GetData(get, &fmt, &med); 1365 ok(hr == E_FAIL, "got %08x\n", hr); 1366 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1367 1368 InitFormatEtc(fmt, cf_stream, TYMED_HGLOBAL); 1369 hr = IDataObject_GetData(get, &fmt, &med); 1370 ok(hr == S_OK, "got %08x\n", hr); 1371 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); 1372 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1373 1374 InitFormatEtc(fmt, cf_stream, 0xffff); 1375 hr = IDataObject_GetData(get, &fmt, &med); 1376 ok(hr == S_OK, "got %08x\n", hr); 1377 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); 1378 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1379 1380 /* storage format -> global, stream & storage */ 1381 1382 InitFormatEtc(fmt, cf_storage, TYMED_ISTORAGE); 1383 hr = IDataObject_GetData(get, &fmt, &med); 1384 ok(hr == S_OK, "got %08x\n", hr); 1385 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); 1386 if(SUCCEEDED(hr)) { 1387 hr = IStorage_Stat(med.pstg, &stat, STATFLAG_NONAME); 1388 ok(hr == S_OK, "got %08x\n", hr); 1389 ok(stat.grfMode == (STGM_SHARE_EXCLUSIVE | STGM_READWRITE), "got %08x\n", stat.grfMode); 1390 ReleaseStgMedium(&med); 1391 } 1392 1393 InitFormatEtc(fmt, cf_storage, TYMED_ISTREAM); 1394 hr = IDataObject_GetData(get, &fmt, &med); 1395 ok(hr == S_OK, "got %08x\n", hr); 1396 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); 1397 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1398 1399 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL); 1400 hr = IDataObject_GetData(get, &fmt, &med); 1401 ok(hr == S_OK, "got %08x\n", hr); 1402 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); 1403 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1404 1405 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL | TYMED_ISTREAM); 1406 hr = IDataObject_GetData(get, &fmt, &med); 1407 ok(hr == S_OK, "got %08x\n", hr); 1408 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); 1409 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1410 1411 InitFormatEtc(fmt, cf_storage, 0xffff); 1412 hr = IDataObject_GetData(get, &fmt, &med); 1413 ok(hr == S_OK, "got %08x\n", hr); 1414 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); 1415 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1416 1417 /* complex format with target device */ 1418 1419 InitFormatEtc(fmt, cf_another, 0xffff); 1420 hr = IDataObject_GetData(get, &fmt, &med); 1421 ok(hr == S_OK, "got %08x\n", hr); 1422 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1423 1424 if (0) /* Causes crashes on both Wine and Windows */ 1425 { 1426 InitFormatEtc(fmt, cf_another, 0xffff); 1427 memset(&dm, 0, sizeof(dm)); 1428 dm.dmSize = sizeof(dm); 1429 dm.dmDriverExtra = 0; 1430 lstrcpyW(dm.dmDeviceName, device_name); 1431 fmt.ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra); 1432 fmt.ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra; 1433 fmt.ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData); 1434 fmt.ptd->tdDeviceNameOffset = 0; 1435 fmt.ptd->tdPortNameOffset = 0; 1436 fmt.ptd->tdExtDevmodeOffset = fmt.ptd->tdDriverNameOffset + sizeof(device_name); 1437 lstrcpyW((WCHAR*)fmt.ptd->tdData, device_name); 1438 memcpy(fmt.ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra); 1439 1440 hr = IDataObject_GetData(get, &fmt, &med); 1441 ok(hr == S_OK, "got %08x\n", hr); 1442 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); 1443 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1444 1445 HeapFree(GetProcessHeap(), 0, fmt.ptd); 1446 } 1447 1448 /* CF_ENHMETAFILE format */ 1449 InitFormatEtc(fmt, CF_ENHMETAFILE, TYMED_ENHMF); 1450 hr = IDataObject_GetData(get, &fmt, &med); 1451 ok(hr == S_OK, "got %08x\n", hr); 1452 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1453 1454 IDataObject_Release(get); 1455 IDataObject_Release(src); 1456 1457 hr = DataObjectImpl_CreateFromHGlobal(create_storage(), &src); 1458 ok(hr == S_OK, "got %08x\n", hr); 1459 1460 hr = OleSetClipboard(src); 1461 ok(hr == S_OK, "got %08x\n", hr); 1462 1463 hr = OleGetClipboard(&get); 1464 ok(hr == S_OK, "got %08x\n", hr); 1465 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTORAGE); 1466 hr = IDataObject_GetData(get, &fmt, &med); 1467 ok(hr == S_OK, "got %08x\n", hr); 1468 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); 1469 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1470 IDataObject_Release(get); 1471 1472 hr = OleFlushClipboard(); 1473 ok(hr == S_OK, "got %08x\n", hr); 1474 1475 hr = OleGetClipboard(&get); 1476 ok(hr == S_OK, "got %08x\n", hr); 1477 1478 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTORAGE); 1479 hr = IDataObject_GetData(get, &fmt, &med); 1480 ok(hr == S_OK, "got %08x\n", hr); 1481 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); 1482 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1483 1484 InitFormatEtc(fmt, CF_TEXT, 0xffff); 1485 hr = IDataObject_GetData(get, &fmt, &med); 1486 ok(hr == S_OK, "got %08x\n", hr); 1487 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); 1488 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1489 1490 IDataObject_Release(get); 1491 IDataObject_Release(src); 1492 1493 OleUninitialize(); 1494 } 1495 1496 static HGLOBAL create_text(void) 1497 { 1498 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5); 1499 char *p = GlobalLock(h); 1500 strcpy(p, "test"); 1501 GlobalUnlock(h); 1502 return h; 1503 } 1504 1505 static HENHMETAFILE create_emf(void) 1506 { 1507 const RECT rect = {0, 0, 100, 100}; 1508 HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Ole Clipboard Test\0Test\0\0"); 1509 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL); 1510 return CloseEnhMetaFile(hdc); 1511 } 1512 1513 static void test_nonole_clipboard(void) 1514 { 1515 HRESULT hr; 1516 BOOL r; 1517 IDataObject *get; 1518 IEnumFORMATETC *enum_fmt; 1519 FORMATETC fmt; 1520 HGLOBAL h, hblob, htext, hstorage; 1521 HENHMETAFILE emf; 1522 STGMEDIUM med; 1523 DWORD obj_type; 1524 1525 r = OpenClipboard(NULL); 1526 ok(r, "gle %d\n", GetLastError()); 1527 r = EmptyClipboard(); 1528 ok(r, "gle %d\n", GetLastError()); 1529 r = CloseClipboard(); 1530 ok(r, "gle %d\n", GetLastError()); 1531 1532 OleInitialize(NULL); 1533 1534 /* empty clipboard */ 1535 hr = OleGetClipboard(&get); 1536 ok(hr == S_OK, "got %08x\n", hr); 1537 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt); 1538 ok(hr == S_OK, "got %08x\n", hr); 1539 1540 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); 1541 ok(hr == S_FALSE, "got %08x\n", hr); 1542 IEnumFORMATETC_Release(enum_fmt); 1543 1544 IDataObject_Release(get); 1545 1546 /* set a user defined clipboard type */ 1547 1548 htext = create_text(); 1549 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10); 1550 emf = create_emf(); 1551 hstorage = create_storage(); 1552 1553 r = OpenClipboard(NULL); 1554 ok(r, "gle %d\n", GetLastError()); 1555 h = SetClipboardData(CF_TEXT, htext); 1556 ok(h == htext, "got %p\n", h); 1557 h = SetClipboardData(cf_onemore, hblob); 1558 ok(h == hblob, "got %p\n", h); 1559 h = SetClipboardData(CF_ENHMETAFILE, emf); 1560 ok(h == emf, "got %p\n", h); 1561 h = SetClipboardData(cf_storage, hstorage); 1562 ok(h == hstorage, "got %p\n", h); 1563 r = CloseClipboard(); 1564 ok(r, "gle %d\n", GetLastError()); 1565 1566 hr = OleGetClipboard(&get); 1567 ok(hr == S_OK, "got %08x\n", hr); 1568 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt); 1569 ok(hr == S_OK, "got %08x\n", hr); 1570 if (FAILED(hr)) 1571 { 1572 skip("EnumFormatEtc failed, skipping tests.\n"); 1573 return; 1574 } 1575 1576 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); 1577 ok(hr == S_OK, "got %08x\n", hr); 1578 ok(fmt.cfFormat == CF_TEXT, "cf %04x\n", fmt.cfFormat); 1579 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); 1580 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); 1581 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); 1582 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed); 1583 1584 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); 1585 ok(hr == S_OK, "got %08x\n", hr); 1586 ok(fmt.cfFormat == cf_onemore, "cf %04x\n", fmt.cfFormat); 1587 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); 1588 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); 1589 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); 1590 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed); 1591 1592 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); 1593 ok(hr == S_OK, "got %08x\n", hr); 1594 ok(fmt.cfFormat == CF_ENHMETAFILE, "cf %04x\n", fmt.cfFormat); 1595 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); 1596 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); 1597 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); 1598 ok(fmt.tymed == TYMED_ENHMF, "tymed %x\n", fmt.tymed); 1599 1600 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); 1601 ok(hr == S_OK, "got %08x\n", hr); 1602 ok(fmt.cfFormat == cf_storage, "cf %04x\n", fmt.cfFormat); 1603 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); 1604 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); 1605 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); 1606 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed); 1607 1608 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); 1609 ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */ 1610 1611 ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat); 1612 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); 1613 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); 1614 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); 1615 todo_wine ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed); 1616 1617 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); 1618 ok(hr == S_OK, "got %08x\n", hr); 1619 1620 ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat); 1621 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); 1622 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); 1623 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); 1624 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed); 1625 1626 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); 1627 ok(hr == S_OK, "got %08x\n", hr); 1628 ok(fmt.cfFormat == CF_UNICODETEXT, "cf %04x\n", fmt.cfFormat); 1629 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); 1630 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); 1631 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); 1632 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed); 1633 1634 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); 1635 ok(hr == S_OK, "got %08x\n", hr); 1636 ok(fmt.cfFormat == CF_METAFILEPICT, "cf %04x\n", fmt.cfFormat); 1637 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); 1638 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); 1639 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); 1640 ok(fmt.tymed == TYMED_MFPICT, "tymed %x\n", fmt.tymed); 1641 1642 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); 1643 ok(hr == S_FALSE, "got %08x\n", hr); 1644 IEnumFORMATETC_Release(enum_fmt); 1645 1646 InitFormatEtc(fmt, CF_ENHMETAFILE, TYMED_ENHMF); 1647 hr = IDataObject_GetData(get, &fmt, &med); 1648 ok(hr == S_OK, "got %08x\n", hr); 1649 obj_type = GetObjectType(U(med).hEnhMetaFile); 1650 ok(obj_type == OBJ_ENHMETAFILE, "got %d\n", obj_type); 1651 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1652 1653 InitFormatEtc(fmt, cf_storage, TYMED_ISTORAGE); 1654 hr = IDataObject_GetData(get, &fmt, &med); 1655 ok(hr == S_OK, "got %08x\n", hr); 1656 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); 1657 if(SUCCEEDED(hr)) ReleaseStgMedium(&med); 1658 1659 IDataObject_Release(get); 1660 1661 r = OpenClipboard(NULL); 1662 ok(r, "gle %d\n", GetLastError()); 1663 r = EmptyClipboard(); 1664 ok(r, "gle %d\n", GetLastError()); 1665 r = CloseClipboard(); 1666 ok(r, "gle %d\n", GetLastError()); 1667 1668 OleUninitialize(); 1669 } 1670 1671 static void test_getdatahere(void) 1672 { 1673 HRESULT hr; 1674 IDataObject *src, *get; 1675 FORMATETC fmt; 1676 STGMEDIUM med; 1677 1678 OleInitialize(NULL); 1679 1680 hr = DataObjectImpl_CreateComplex(&src); 1681 ok(hr == S_OK, "got %08x\n", hr); 1682 1683 hr = OleSetClipboard(src); 1684 ok(hr == S_OK, "got %08x\n", hr); 1685 1686 hr = OleGetClipboard(&get); 1687 ok(hr == S_OK, "got %08x\n", hr); 1688 1689 /* global format -> global & stream */ 1690 1691 DataObjectImpl_GetData_calls = 0; 1692 DataObjectImpl_GetDataHere_calls = 0; 1693 1694 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL); 1695 1696 med.pUnkForRelease = NULL; 1697 med.tymed = TYMED_HGLOBAL; 1698 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100); 1699 hr = IDataObject_GetDataHere(get, &fmt, &med); 1700 ok(hr == S_OK, "got %08x\n", hr); 1701 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); 1702 ReleaseStgMedium(&med); 1703 ok(DataObjectImpl_GetDataHere_calls == 1, "called %d\n", DataObjectImpl_GetDataHere_calls); 1704 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls); 1705 1706 InitFormatEtc(fmt, CF_TEXT, 0); 1707 1708 med.pUnkForRelease = NULL; 1709 med.tymed = TYMED_HGLOBAL; 1710 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100); 1711 hr = IDataObject_GetDataHere(get, &fmt, &med); 1712 ok(hr == S_OK, "got %08x\n", hr); 1713 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); 1714 ReleaseStgMedium(&med); 1715 ok(DataObjectImpl_GetDataHere_calls == 2, "called %d\n", DataObjectImpl_GetDataHere_calls); 1716 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls); 1717 1718 med.pUnkForRelease = NULL; 1719 med.tymed = TYMED_HGLOBAL; 1720 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 1); 1721 hr = IDataObject_GetDataHere(get, &fmt, &med); 1722 ok(hr == E_FAIL, "got %08x\n", hr); 1723 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); 1724 ReleaseStgMedium(&med); 1725 ok(DataObjectImpl_GetDataHere_calls == 3, "called %d\n", DataObjectImpl_GetDataHere_calls); 1726 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls); 1727 1728 med.pUnkForRelease = NULL; 1729 med.tymed = TYMED_ISTREAM; 1730 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm); 1731 hr = IDataObject_GetDataHere(get, &fmt, &med); 1732 ok(hr == S_OK, "got %08x\n", hr); 1733 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); 1734 ReleaseStgMedium(&med); 1735 ok(DataObjectImpl_GetDataHere_calls == 4, "called %d\n", DataObjectImpl_GetDataHere_calls); 1736 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls); 1737 1738 med.pUnkForRelease = NULL; 1739 med.tymed = TYMED_ISTORAGE; 1740 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg); 1741 hr = IDataObject_GetDataHere(get, &fmt, &med); 1742 ok(hr == E_FAIL, "got %08x\n", hr); 1743 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); 1744 ReleaseStgMedium(&med); 1745 ok(DataObjectImpl_GetDataHere_calls == 5, "called %d\n", DataObjectImpl_GetDataHere_calls); 1746 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls); 1747 1748 InitFormatEtc(fmt, cf_stream, 0); 1749 1750 med.pUnkForRelease = NULL; 1751 med.tymed = TYMED_HGLOBAL; 1752 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100); 1753 hr = IDataObject_GetDataHere(get, &fmt, &med); 1754 ok(hr == S_OK, "got %08x\n", hr); 1755 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); 1756 ReleaseStgMedium(&med); 1757 ok(DataObjectImpl_GetDataHere_calls == 7, "called %d\n", DataObjectImpl_GetDataHere_calls); 1758 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls); 1759 1760 med.pUnkForRelease = NULL; 1761 med.tymed = TYMED_ISTREAM; 1762 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm); 1763 hr = IDataObject_GetDataHere(get, &fmt, &med); 1764 ok(hr == S_OK, "got %08x\n", hr); 1765 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); 1766 ReleaseStgMedium(&med); 1767 ok(DataObjectImpl_GetDataHere_calls == 8, "called %d\n", DataObjectImpl_GetDataHere_calls); 1768 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls); 1769 1770 med.pUnkForRelease = NULL; 1771 med.tymed = TYMED_ISTORAGE; 1772 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg); 1773 hr = IDataObject_GetDataHere(get, &fmt, &med); 1774 ok(hr == E_FAIL, "got %08x\n", hr); 1775 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); 1776 ReleaseStgMedium(&med); 1777 ok(DataObjectImpl_GetDataHere_calls == 9, "called %d\n", DataObjectImpl_GetDataHere_calls); 1778 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls); 1779 1780 InitFormatEtc(fmt, cf_storage, 0); 1781 1782 med.pUnkForRelease = NULL; 1783 med.tymed = TYMED_HGLOBAL; 1784 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 3000); 1785 hr = IDataObject_GetDataHere(get, &fmt, &med); 1786 ok(hr == S_OK, "got %08x\n", hr); 1787 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); 1788 ReleaseStgMedium(&med); 1789 ok(DataObjectImpl_GetDataHere_calls == 11, "called %d\n", DataObjectImpl_GetDataHere_calls); 1790 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls); 1791 1792 med.pUnkForRelease = NULL; 1793 med.tymed = TYMED_ISTREAM; 1794 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm); 1795 hr = IDataObject_GetDataHere(get, &fmt, &med); 1796 ok(hr == S_OK, "got %08x\n", hr); 1797 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); 1798 ReleaseStgMedium(&med); 1799 ok(DataObjectImpl_GetDataHere_calls == 12, "called %d\n", DataObjectImpl_GetDataHere_calls); 1800 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls); 1801 1802 med.pUnkForRelease = NULL; 1803 med.tymed = TYMED_ISTORAGE; 1804 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg); 1805 hr = IDataObject_GetDataHere(get, &fmt, &med); 1806 ok(hr == S_OK, "got %08x\n", hr); 1807 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); 1808 ReleaseStgMedium(&med); 1809 ok(DataObjectImpl_GetDataHere_calls == 13, "called %d\n", DataObjectImpl_GetDataHere_calls); 1810 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls); 1811 1812 1813 IDataObject_Release(get); 1814 IDataObject_Release(src); 1815 1816 OleUninitialize(); 1817 1818 } 1819 1820 static DWORD CALLBACK test_data_obj(void *arg) 1821 { 1822 IDataObject *data_obj = arg; 1823 1824 IDataObject_Release(data_obj); 1825 return 0; 1826 } 1827 1828 static void test_multithreaded_clipboard(void) 1829 { 1830 IDataObject *data_obj; 1831 HANDLE thread; 1832 HRESULT hr; 1833 DWORD ret; 1834 1835 OleInitialize(NULL); 1836 1837 hr = OleGetClipboard(&data_obj); 1838 ok(hr == S_OK, "OleGetClipboard returned %x\n", hr); 1839 1840 thread = CreateThread(NULL, 0, test_data_obj, data_obj, 0, NULL); 1841 ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError()); 1842 ret = WaitForSingleObject(thread, 5000); 1843 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret); 1844 1845 hr = OleGetClipboard(&data_obj); 1846 ok(hr == S_OK, "OleGetClipboard returned %x\n", hr); 1847 IDataObject_Release(data_obj); 1848 1849 OleUninitialize(); 1850 } 1851 1852 static void test_get_clipboard_locked(void) 1853 { 1854 HRESULT hr; 1855 IDataObject *pDObj; 1856 1857 OleInitialize(NULL); 1858 1859 pDObj = (IDataObject *)0xdeadbeef; 1860 /* lock clipboard */ 1861 OpenClipboard(NULL); 1862 hr = OleGetClipboard(&pDObj); 1863 todo_wine ok(hr == CLIPBRD_E_CANT_OPEN, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr, CLIPBRD_E_CANT_OPEN); 1864 todo_wine ok(pDObj == NULL, "OleGetClipboard() got 0x%p instead of NULL\n",pDObj); 1865 if (pDObj) IDataObject_Release(pDObj); 1866 CloseClipboard(); 1867 1868 OleUninitialize(); 1869 } 1870 1871 START_TEST(clipboard) 1872 { 1873 test_get_clipboard_uninitialized(); 1874 test_set_clipboard(); 1875 test_set_clipboard_DRAWCLIPBOARD(); 1876 test_consumer_refs(); 1877 test_flushed_getdata(); 1878 test_nonole_clipboard(); 1879 test_getdatahere(); 1880 test_multithreaded_clipboard(); 1881 test_get_clipboard_locked(); 1882 } 1883