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