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