ole32/tests: Add a test for WM_DRAWCLIPBOARD during OleSetClipboard.
[wine.git] / dlls / ole32 / tests / clipboard.c
bloba30796cff5d55c5fb033a17c43d9769f730830fb
1 /*
2 * Clipboard unit tests
4 * Copyright 2006 Kevin Koltzau
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.
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.
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
21 #define COBJMACROS
22 #define CONST_VTABLE
23 #define NONAMELESSUNION
25 #include <stdarg.h>
26 #include <stdio.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
32 #include "wine/test.h"
34 #define InitFormatEtc(fe, cf, med) \
36 (fe).cfFormat=cf;\
37 (fe).dwAspect=DVASPECT_CONTENT;\
38 (fe).ptd=NULL;\
39 (fe).tymed=med;\
40 (fe).lindex=-1;\
43 static inline char *dump_fmtetc(FORMATETC *fmt)
45 static char buf[100];
47 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
48 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
49 return buf;
52 typedef struct DataObjectImpl {
53 IDataObject IDataObject_iface;
54 LONG ref;
56 FORMATETC *fmtetc;
57 UINT fmtetc_cnt;
59 HANDLE text;
60 IStream *stm;
61 IStorage *stg;
62 } DataObjectImpl;
64 typedef struct EnumFormatImpl {
65 IEnumFORMATETC IEnumFORMATETC_iface;
66 LONG ref;
68 FORMATETC *fmtetc;
69 UINT fmtetc_cnt;
71 UINT cur;
72 } EnumFormatImpl;
74 static BOOL expect_DataObjectImpl_QueryGetData = TRUE;
75 static ULONG DataObjectImpl_GetData_calls = 0;
76 static ULONG DataObjectImpl_GetDataHere_calls = 0;
77 static ULONG DataObjectImpl_EnumFormatEtc_calls = 0;
79 static UINT cf_stream, cf_storage, cf_global, cf_another, cf_onemore;
81 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
83 static inline DataObjectImpl *impl_from_IDataObject(IDataObject *iface)
85 return CONTAINING_RECORD(iface, DataObjectImpl, IDataObject_iface);
88 static inline EnumFormatImpl *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
90 return CONTAINING_RECORD(iface, EnumFormatImpl, IEnumFORMATETC_iface);
93 static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
95 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
97 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) {
98 IEnumFORMATETC_AddRef(iface);
99 *ppvObj = &This->IEnumFORMATETC_iface;
100 return S_OK;
102 *ppvObj = NULL;
103 return E_NOINTERFACE;
106 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
108 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
109 LONG ref = InterlockedIncrement(&This->ref);
110 return ref;
113 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
115 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
116 ULONG ref = InterlockedDecrement(&This->ref);
118 if(!ref) {
119 HeapFree(GetProcessHeap(), 0, This->fmtetc);
120 HeapFree(GetProcessHeap(), 0, This);
123 return ref;
126 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
127 FORMATETC *rgelt, ULONG *pceltFetched)
129 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
130 ULONG count, i;
132 if (winetest_debug > 1)
133 trace("next: count %d cur %d\n", celt, This->cur);
135 if(!rgelt)
136 return E_INVALIDARG;
138 count = min(celt, This->fmtetc_cnt - This->cur);
139 for(i = 0; i < count; i++, This->cur++, rgelt++)
141 *rgelt = This->fmtetc[This->cur];
142 if(rgelt->ptd)
144 DWORD size = This->fmtetc[This->cur].ptd->tdSize;
145 rgelt->ptd = CoTaskMemAlloc(size);
146 memcpy(rgelt->ptd, This->fmtetc[This->cur].ptd, size);
149 if(pceltFetched)
150 *pceltFetched = count;
151 return count == celt ? S_OK : S_FALSE;
154 static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt)
156 ok(0, "unexpected call\n");
157 return E_NOTIMPL;
160 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
162 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
164 This->cur = 0;
165 return S_OK;
168 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
170 ok(0, "unexpected call\n");
171 return E_NOTIMPL;
174 static const IEnumFORMATETCVtbl VT_EnumFormatImpl = {
175 EnumFormatImpl_QueryInterface,
176 EnumFormatImpl_AddRef,
177 EnumFormatImpl_Release,
178 EnumFormatImpl_Next,
179 EnumFormatImpl_Skip,
180 EnumFormatImpl_Reset,
181 EnumFormatImpl_Clone
184 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
186 EnumFormatImpl *ret;
188 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl));
189 ret->IEnumFORMATETC_iface.lpVtbl = &VT_EnumFormatImpl;
190 ret->ref = 1;
191 ret->cur = 0;
192 ret->fmtetc_cnt = fmtetc_cnt;
193 ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC));
194 memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
195 *lplpformatetc = &ret->IEnumFORMATETC_iface;
196 return S_OK;
199 static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj)
201 DataObjectImpl *This = impl_from_IDataObject(iface);
203 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) {
204 IDataObject_AddRef(iface);
205 *ppvObj = &This->IDataObject_iface;
206 return S_OK;
208 *ppvObj = NULL;
209 return E_NOINTERFACE;
212 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
214 DataObjectImpl *This = impl_from_IDataObject(iface);
215 ULONG ref = InterlockedIncrement(&This->ref);
216 return ref;
219 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
221 DataObjectImpl *This = impl_from_IDataObject(iface);
222 ULONG ref = InterlockedDecrement(&This->ref);
224 if(!ref)
226 int i;
227 if(This->text) GlobalFree(This->text);
228 for(i = 0; i < This->fmtetc_cnt; i++)
229 HeapFree(GetProcessHeap(), 0, This->fmtetc[i].ptd);
230 HeapFree(GetProcessHeap(), 0, This->fmtetc);
231 if(This->stm) IStream_Release(This->stm);
232 if(This->stg) IStorage_Release(This->stg);
233 HeapFree(GetProcessHeap(), 0, This);
236 return ref;
239 static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
241 DataObjectImpl *This = impl_from_IDataObject(iface);
242 UINT i;
243 BOOL foundFormat = FALSE;
245 trace("getdata: %s\n", dump_fmtetc(pformatetc));
247 DataObjectImpl_GetData_calls++;
249 if(pformatetc->lindex != -1)
250 return DV_E_FORMATETC;
252 for(i = 0; i < This->fmtetc_cnt; i++)
254 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat)
256 foundFormat = TRUE;
257 if(This->fmtetc[i].tymed & pformatetc->tymed)
259 pmedium->pUnkForRelease = (LPUNKNOWN)iface;
260 IUnknown_AddRef(pmedium->pUnkForRelease);
262 if(pformatetc->cfFormat == CF_TEXT || pformatetc->cfFormat == cf_global)
264 pmedium->tymed = TYMED_HGLOBAL;
265 U(*pmedium).hGlobal = This->text;
267 else if(pformatetc->cfFormat == cf_stream)
269 pmedium->tymed = TYMED_ISTREAM;
270 IStream_AddRef(This->stm);
271 U(*pmedium).pstm = This->stm;
273 else if(pformatetc->cfFormat == cf_storage || pformatetc->cfFormat == cf_another)
275 pmedium->tymed = TYMED_ISTORAGE;
276 IStorage_AddRef(This->stg);
277 U(*pmedium).pstg = This->stg;
279 return S_OK;
284 return foundFormat ? DV_E_TYMED : DV_E_FORMATETC;
287 static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
289 trace("getdatahere: %s\n", dump_fmtetc(pformatetc));
290 DataObjectImpl_GetDataHere_calls++;
292 return E_NOTIMPL;
295 static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc)
297 DataObjectImpl *This = impl_from_IDataObject(iface);
298 UINT i;
299 BOOL foundFormat = FALSE;
301 trace("querygetdata: %s\n", dump_fmtetc(pformatetc));
302 if (!expect_DataObjectImpl_QueryGetData)
303 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
305 if(pformatetc->lindex != -1)
306 return DV_E_LINDEX;
308 for(i=0; i<This->fmtetc_cnt; i++) {
309 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) {
310 foundFormat = TRUE;
311 if(This->fmtetc[i].tymed == pformatetc->tymed)
312 return S_OK;
315 return foundFormat?DV_E_FORMATETC:DV_E_TYMED;
318 static HRESULT WINAPI DataObjectImpl_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC *pformatectIn,
319 FORMATETC *pformatetcOut)
321 ok(0, "unexpected call\n");
322 return E_NOTIMPL;
325 static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc,
326 STGMEDIUM *pmedium, BOOL fRelease)
328 ok(0, "unexpected call\n");
329 return E_NOTIMPL;
332 static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwDirection,
333 IEnumFORMATETC **ppenumFormatEtc)
335 DataObjectImpl *This = impl_from_IDataObject(iface);
337 DataObjectImpl_EnumFormatEtc_calls++;
339 if(dwDirection != DATADIR_GET) {
340 ok(0, "unexpected direction %d\n", dwDirection);
341 return E_NOTIMPL;
343 return EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenumFormatEtc);
346 static HRESULT WINAPI DataObjectImpl_DAdvise(IDataObject* iface, FORMATETC *pformatetc, DWORD advf,
347 IAdviseSink *pAdvSink, DWORD *pdwConnection)
349 ok(0, "unexpected call\n");
350 return E_NOTIMPL;
353 static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection)
355 ok(0, "unexpected call\n");
356 return E_NOTIMPL;
359 static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise)
361 ok(0, "unexpected call\n");
362 return E_NOTIMPL;
365 static const IDataObjectVtbl VT_DataObjectImpl =
367 DataObjectImpl_QueryInterface,
368 DataObjectImpl_AddRef,
369 DataObjectImpl_Release,
370 DataObjectImpl_GetData,
371 DataObjectImpl_GetDataHere,
372 DataObjectImpl_QueryGetData,
373 DataObjectImpl_GetCanonicalFormatEtc,
374 DataObjectImpl_SetData,
375 DataObjectImpl_EnumFormatEtc,
376 DataObjectImpl_DAdvise,
377 DataObjectImpl_DUnadvise,
378 DataObjectImpl_EnumDAdvise
381 static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
383 DataObjectImpl *obj;
385 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
386 obj->IDataObject_iface.lpVtbl = &VT_DataObjectImpl;
387 obj->ref = 1;
388 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1);
389 strcpy(GlobalLock(obj->text), text);
390 GlobalUnlock(obj->text);
391 obj->stm = NULL;
392 obj->stg = NULL;
394 obj->fmtetc_cnt = 1;
395 obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
396 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
398 *lplpdataobj = &obj->IDataObject_iface;
399 return S_OK;
402 static const char *cmpl_stm_data = "complex stream";
403 static const char *cmpl_text_data = "complex text";
404 static const WCHAR device_name[] = {'m','y','d','e','v',0};
406 static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj)
408 DataObjectImpl *obj;
409 ILockBytes *lbs;
410 DEVMODEW dm;
412 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
413 obj->IDataObject_iface.lpVtbl = &VT_DataObjectImpl;
414 obj->ref = 1;
415 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(cmpl_text_data) + 1);
416 strcpy(GlobalLock(obj->text), cmpl_text_data);
417 GlobalUnlock(obj->text);
418 CreateStreamOnHGlobal(NULL, TRUE, &obj->stm);
419 IStream_Write(obj->stm, cmpl_stm_data, strlen(cmpl_stm_data), NULL);
421 CreateILockBytesOnHGlobal(NULL, TRUE, &lbs);
422 StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &obj->stg);
423 ILockBytes_Release(lbs);
425 obj->fmtetc_cnt = 8;
426 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
427 obj->fmtetc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, obj->fmtetc_cnt*sizeof(FORMATETC));
428 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
429 InitFormatEtc(obj->fmtetc[1], cf_stream, TYMED_ISTREAM);
430 InitFormatEtc(obj->fmtetc[2], cf_storage, TYMED_ISTORAGE);
431 InitFormatEtc(obj->fmtetc[3], cf_another, TYMED_ISTORAGE|TYMED_ISTREAM|TYMED_HGLOBAL);
432 if (0) /* Causes crashes on both Wine and Windows */
434 memset(&dm, 0, sizeof(dm));
435 dm.dmSize = sizeof(dm);
436 dm.dmDriverExtra = 0;
437 lstrcpyW(dm.dmDeviceName, device_name);
438 obj->fmtetc[3].ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
439 obj->fmtetc[3].ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
440 obj->fmtetc[3].ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
441 obj->fmtetc[3].ptd->tdDeviceNameOffset = 0;
442 obj->fmtetc[3].ptd->tdPortNameOffset = 0;
443 obj->fmtetc[3].ptd->tdExtDevmodeOffset = obj->fmtetc[3].ptd->tdDriverNameOffset + sizeof(device_name);
444 lstrcpyW((WCHAR*)obj->fmtetc[3].ptd->tdData, device_name);
445 memcpy(obj->fmtetc[3].ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
448 InitFormatEtc(obj->fmtetc[4], cf_global, TYMED_HGLOBAL);
449 InitFormatEtc(obj->fmtetc[5], cf_another, TYMED_HGLOBAL);
450 InitFormatEtc(obj->fmtetc[6], cf_another, 0xfffff);
451 InitFormatEtc(obj->fmtetc[7], cf_another, 0xfffff);
452 obj->fmtetc[7].dwAspect = DVASPECT_ICON;
454 *lplpdataobj = &obj->IDataObject_iface;
455 return S_OK;
458 static void test_get_clipboard_uninitialized(void)
460 HRESULT hr;
461 IDataObject *pDObj;
463 pDObj = (IDataObject *)0xdeadbeef;
464 hr = OleGetClipboard(&pDObj);
465 todo_wine ok(hr == S_OK, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr, S_OK);
466 if (pDObj && pDObj != (IDataObject *)0xdeadbeef) IDataObject_Release(pDObj);
469 static void test_get_clipboard(void)
471 HRESULT hr;
472 IDataObject *data_obj;
473 FORMATETC fmtetc;
474 STGMEDIUM stgmedium;
476 hr = OleGetClipboard(NULL);
477 ok(hr == E_INVALIDARG, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr);
479 hr = OleGetClipboard(&data_obj);
480 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
482 /* test IDataObject_QueryGetData */
484 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
485 expect_DataObjectImpl_QueryGetData = FALSE;
487 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
488 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
489 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
491 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
492 fmtetc.dwAspect = 0xdeadbeef;
493 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
494 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
496 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
497 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
498 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
499 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
501 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
502 fmtetc.lindex = 256;
503 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
504 ok(hr == DV_E_FORMATETC || broken(hr == S_OK),
505 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
507 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
508 fmtetc.cfFormat = CF_RIFF;
509 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
510 ok(hr == DV_E_CLIPFORMAT, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr);
512 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
513 fmtetc.tymed = TYMED_FILE;
514 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
515 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
517 expect_DataObjectImpl_QueryGetData = TRUE;
519 /* test IDataObject_GetData */
521 DataObjectImpl_GetData_calls = 0;
523 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
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);
528 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
529 fmtetc.dwAspect = 0xdeadbeef;
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);
534 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
535 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
536 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
537 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
538 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
540 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
541 fmtetc.lindex = 256;
542 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
543 ok(hr == DV_E_FORMATETC || broken(hr == S_OK), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
544 if (hr == S_OK)
546 /* undo the unexpected success */
547 DataObjectImpl_GetData_calls--;
548 ReleaseStgMedium(&stgmedium);
551 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
552 fmtetc.cfFormat = CF_RIFF;
553 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
554 ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
555 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
557 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
558 fmtetc.tymed = TYMED_FILE;
559 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
560 ok(hr == DV_E_TYMED, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr);
561 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
563 ok(DataObjectImpl_GetData_calls == 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls);
565 IDataObject_Release(data_obj);
568 static void test_enum_fmtetc(IDataObject *src)
570 HRESULT hr;
571 IDataObject *data;
572 IEnumFORMATETC *enum_fmt, *src_enum;
573 FORMATETC fmt, src_fmt;
574 DWORD count = 0;
576 hr = OleGetClipboard(&data);
577 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
579 hr = IDataObject_EnumFormatEtc(data, DATADIR_SET, &enum_fmt);
580 ok(hr == E_NOTIMPL ||
581 broken(hr == E_INVALIDARG), /* win98 (not win98SE) */
582 "got %08x\n", hr);
584 DataObjectImpl_EnumFormatEtc_calls = 0;
585 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
586 ok(hr == S_OK, "got %08x\n", hr);
587 ok(DataObjectImpl_EnumFormatEtc_calls == 0, "EnumFormatEtc was called\n");
589 if(src) IDataObject_EnumFormatEtc(src, DATADIR_GET, &src_enum);
591 while((hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL)) == S_OK)
593 ok(src != NULL, "shouldn't be here\n");
594 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
595 ok(hr == S_OK, "%d: got %08x\n", count, hr);
596 trace("%d: %s\n", count, dump_fmtetc(&fmt));
597 ok(fmt.cfFormat == src_fmt.cfFormat, "%d: %04x %04x\n", count, fmt.cfFormat, src_fmt.cfFormat);
598 ok(fmt.dwAspect == src_fmt.dwAspect, "%d: %08x %08x\n", count, fmt.dwAspect, src_fmt.dwAspect);
599 ok(fmt.lindex == src_fmt.lindex, "%d: %08x %08x\n", count, fmt.lindex, src_fmt.lindex);
600 ok(fmt.tymed == src_fmt.tymed, "%d: %08x %08x\n", count, fmt.tymed, src_fmt.tymed);
601 if(fmt.ptd)
603 ok(src_fmt.ptd != NULL, "%d: expected non-NULL\n", count);
604 CoTaskMemFree(fmt.ptd);
605 CoTaskMemFree(src_fmt.ptd);
607 count++;
610 ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
612 if(src)
614 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
615 ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
616 IEnumFORMATETC_Release(src_enum);
619 hr = IEnumFORMATETC_Reset(enum_fmt);
620 ok(hr == S_OK, "got %08x\n", hr);
622 if(src) /* Exercise the enumerator a bit */
624 IEnumFORMATETC *clone;
625 FORMATETC third_fmt;
627 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
628 ok(hr == S_OK, "got %08x\n", hr);
629 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
630 ok(hr == S_OK, "got %08x\n", hr);
631 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
632 ok(hr == S_OK, "got %08x\n", hr);
634 hr = IEnumFORMATETC_Reset(enum_fmt);
635 ok(hr == S_OK, "got %08x\n", hr);
636 hr = IEnumFORMATETC_Skip(enum_fmt, 2);
637 ok(hr == S_OK, "got %08x\n", hr);
639 hr = IEnumFORMATETC_Clone(enum_fmt, &clone);
640 ok(hr == S_OK, "got %08x\n", hr);
641 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
642 ok(hr == S_OK, "got %08x\n", hr);
643 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
644 hr = IEnumFORMATETC_Next(clone, 1, &fmt, NULL);
645 ok(hr == S_OK, "got %08x\n", hr);
646 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
647 IEnumFORMATETC_Release(clone);
650 IEnumFORMATETC_Release(enum_fmt);
651 IDataObject_Release(data);
654 static void test_no_cf_dataobject(void)
656 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
657 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
658 HANDLE h;
659 OpenClipboard(NULL);
661 h = GetClipboardData(cf_dataobject);
662 ok(!h, "got %p\n", h);
663 h = GetClipboardData(cf_ole_priv_data);
664 ok(!h, "got %p\n", h);
666 CloseClipboard();
669 static void test_cf_dataobject(IDataObject *data)
671 UINT cf = 0;
672 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
673 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
674 BOOL found_dataobject = FALSE, found_priv_data = FALSE;
676 OpenClipboard(NULL);
679 cf = EnumClipboardFormats(cf);
680 if(cf == cf_dataobject)
682 HGLOBAL h = GetClipboardData(cf);
683 HWND *ptr = GlobalLock(h);
684 DWORD size = GlobalSize(h);
685 HWND clip_owner = GetClipboardOwner();
687 found_dataobject = TRUE;
688 ok(size >= sizeof(*ptr), "size %d\n", size);
689 if(data)
690 ok(*ptr == clip_owner, "hwnd %p clip_owner %p\n", *ptr, clip_owner);
691 else /* ole clipboard flushed */
692 ok(*ptr == NULL, "hwnd %p\n", *ptr);
693 GlobalUnlock(h);
695 else if(cf == cf_ole_priv_data)
697 found_priv_data = TRUE;
698 if(data)
700 HGLOBAL h = GetClipboardData(cf);
701 DWORD *ptr = GlobalLock(h);
702 DWORD size = GlobalSize(h);
704 if(size != ptr[1])
705 win_skip("Ole Private Data in win9x format\n");
706 else
708 HRESULT hr;
709 IEnumFORMATETC *enum_fmt;
710 DWORD count = 0;
711 FORMATETC fmt;
712 struct formatetcetc
714 FORMATETC fmt;
715 BOOL first_use_of_cf;
716 DWORD res[2];
717 } *fmt_ptr;
718 struct priv_data
720 DWORD res1;
721 DWORD size;
722 DWORD res2;
723 DWORD count;
724 DWORD res3[2];
725 struct formatetcetc fmts[1];
726 } *priv = (struct priv_data*)ptr;
727 CLIPFORMAT cfs_seen[10];
729 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
730 ok(hr == S_OK, "got %08x\n", hr);
731 fmt_ptr = priv->fmts;
733 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
735 int i;
736 BOOL seen_cf = FALSE;
738 ok(fmt_ptr->fmt.cfFormat == fmt.cfFormat,
739 "got %08x expected %08x\n", fmt_ptr->fmt.cfFormat, fmt.cfFormat);
740 ok(fmt_ptr->fmt.dwAspect == fmt.dwAspect, "got %08x expected %08x\n",
741 fmt_ptr->fmt.dwAspect, fmt.dwAspect);
742 ok(fmt_ptr->fmt.lindex == fmt.lindex, "got %08x expected %08x\n",
743 fmt_ptr->fmt.lindex, fmt.lindex);
744 ok(fmt_ptr->fmt.tymed == fmt.tymed, "got %08x expected %08x\n",
745 fmt_ptr->fmt.tymed, fmt.tymed);
746 for(i = 0; i < count; i++)
747 if(fmt_ptr->fmt.cfFormat == cfs_seen[i])
749 seen_cf = TRUE;
750 break;
752 cfs_seen[count] = fmt.cfFormat;
753 ok(fmt_ptr->first_use_of_cf != seen_cf, "got %08x expected %08x\n",
754 fmt_ptr->first_use_of_cf, !seen_cf);
755 ok(fmt_ptr->res[0] == 0, "got %08x\n", fmt_ptr->res[0]);
756 ok(fmt_ptr->res[1] == 0, "got %08x\n", fmt_ptr->res[1]);
757 if(fmt.ptd)
759 DVTARGETDEVICE *target;
761 ok(fmt_ptr->fmt.ptd != NULL, "target device offset zero\n");
762 target = (DVTARGETDEVICE*)((char*)priv + (DWORD_PTR)fmt_ptr->fmt.ptd);
763 ok(!memcmp(target, fmt.ptd, fmt.ptd->tdSize), "target devices differ\n");
764 CoTaskMemFree(fmt.ptd);
766 fmt_ptr++;
767 count++;
769 ok(priv->res1 == 0, "got %08x\n", priv->res1);
770 ok(priv->res2 == 1, "got %08x\n", priv->res2);
771 ok(priv->count == count, "got %08x expected %08x\n", priv->count, count);
772 ok(priv->res3[0] == 0, "got %08x\n", priv->res3[0]);
774 /* win64 sets the lsb */
775 if(sizeof(fmt_ptr->fmt.ptd) == 8)
776 todo_wine ok(priv->res3[1] == 1, "got %08x\n", priv->res3[1]);
777 else
778 ok(priv->res3[1] == 0, "got %08x\n", priv->res3[1]);
780 GlobalUnlock(h);
781 IEnumFORMATETC_Release(enum_fmt);
785 else if(cf == cf_stream)
787 HGLOBAL h;
788 void *ptr;
789 DWORD size;
791 DataObjectImpl_GetDataHere_calls = 0;
792 h = GetClipboardData(cf);
793 ok(DataObjectImpl_GetDataHere_calls == 1, "got %d\n", DataObjectImpl_GetDataHere_calls);
794 ptr = GlobalLock(h);
795 size = GlobalSize(h);
796 ok(size == strlen(cmpl_stm_data),
797 "expected %d got %d\n", lstrlenA(cmpl_stm_data), size);
798 ok(!memcmp(ptr, cmpl_stm_data, strlen(cmpl_stm_data)), "mismatch\n");
799 GlobalUnlock(h);
801 else if(cf == cf_global)
803 HGLOBAL h;
804 void *ptr;
805 DWORD size;
807 DataObjectImpl_GetDataHere_calls = 0;
808 h = GetClipboardData(cf);
809 ok(DataObjectImpl_GetDataHere_calls == 0, "got %d\n", DataObjectImpl_GetDataHere_calls);
810 ptr = GlobalLock(h);
811 size = GlobalSize(h);
812 ok(size == strlen(cmpl_text_data) + 1,
813 "expected %d got %d\n", lstrlenA(cmpl_text_data) + 1, size);
814 ok(!memcmp(ptr, cmpl_text_data, strlen(cmpl_text_data) + 1), "mismatch\n");
815 GlobalUnlock(h);
817 } while(cf);
818 CloseClipboard();
819 ok(found_dataobject, "didn't find cf_dataobject\n");
820 ok(found_priv_data, "didn't find cf_ole_priv_data\n");
823 static void test_set_clipboard(void)
825 HRESULT hr;
826 ULONG ref;
827 LPDATAOBJECT data1, data2, data_cmpl;
828 HGLOBAL hblob, h;
829 void *ptr;
831 cf_stream = RegisterClipboardFormatA("stream format");
832 cf_storage = RegisterClipboardFormatA("storage format");
833 cf_global = RegisterClipboardFormatA("global format");
834 cf_another = RegisterClipboardFormatA("another format");
835 cf_onemore = RegisterClipboardFormatA("one more format");
837 hr = DataObjectImpl_CreateText("data1", &data1);
838 ok(hr == S_OK, "Failed to create data1 object: 0x%08x\n", hr);
839 if(FAILED(hr))
840 return;
841 hr = DataObjectImpl_CreateText("data2", &data2);
842 ok(hr == S_OK, "Failed to create data2 object: 0x%08x\n", hr);
843 if(FAILED(hr))
844 return;
845 hr = DataObjectImpl_CreateComplex(&data_cmpl);
846 ok(hr == S_OK, "Failed to create complex data object: 0x%08x\n", hr);
847 if(FAILED(hr))
848 return;
850 hr = OleSetClipboard(data1);
851 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
853 CoInitialize(NULL);
854 hr = OleSetClipboard(data1);
855 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard failed with 0x%08x\n", hr);
856 CoUninitialize();
858 hr = OleInitialize(NULL);
859 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
861 hr = OleSetClipboard(data1);
862 ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr);
864 test_cf_dataobject(data1);
866 hr = OleIsCurrentClipboard(data1);
867 ok(hr == S_OK, "expected current clipboard to be data1, hr = 0x%08x\n", hr);
868 hr = OleIsCurrentClipboard(data2);
869 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
870 hr = OleIsCurrentClipboard(NULL);
871 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
873 test_get_clipboard();
875 hr = OleSetClipboard(data2);
876 ok(hr == S_OK, "failed to set clipboard to data2, hr = 0x%08x\n", hr);
877 hr = OleIsCurrentClipboard(data1);
878 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
879 hr = OleIsCurrentClipboard(data2);
880 ok(hr == S_OK, "expected current clipboard to be data2, hr = 0x%08x\n", hr);
881 hr = OleIsCurrentClipboard(NULL);
882 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
884 /* put a format directly onto the clipboard to show
885 OleFlushClipboard doesn't empty the clipboard */
886 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
887 ptr = GlobalLock( hblob );
888 ok( ptr && ptr != hblob, "got fixed block %p / %p\n", ptr, hblob );
889 GlobalUnlock( hblob );
890 ok( OpenClipboard(NULL), "OpenClipboard failed\n" );
891 h = SetClipboardData(cf_onemore, hblob);
892 ok(h == hblob, "got %p\n", h);
893 h = GetClipboardData(cf_onemore);
894 ok(h == hblob, "got %p / %p\n", h, hblob);
895 ptr = GlobalLock( h );
896 ok( ptr && ptr != h, "got fixed block %p / %p\n", ptr, h );
897 GlobalUnlock( hblob );
898 ok( CloseClipboard(), "CloseClipboard failed\n" );
900 hr = OleFlushClipboard();
901 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
902 hr = OleIsCurrentClipboard(data1);
903 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
904 hr = OleIsCurrentClipboard(data2);
905 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
906 hr = OleIsCurrentClipboard(NULL);
907 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
909 /* format should survive the flush */
910 ok( OpenClipboard(NULL), "OpenClipboard failed\n" );
911 h = GetClipboardData(cf_onemore);
912 ok(h == hblob, "got %p\n", h);
913 ptr = GlobalLock( h );
914 ok( ptr && ptr != h, "got fixed block %p / %p\n", ptr, h );
915 GlobalUnlock( hblob );
916 ok( CloseClipboard(), "CloseClipboard failed\n" );
918 test_cf_dataobject(NULL);
920 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
922 OpenClipboard(NULL);
923 h = GetClipboardData(cf_onemore);
924 ok(h == NULL, "got %p\n", h);
925 CloseClipboard();
927 trace("setting complex\n");
928 hr = OleSetClipboard(data_cmpl);
929 ok(hr == S_OK, "failed to set clipboard to complex data, hr = 0x%08x\n", hr);
930 test_cf_dataobject(data_cmpl);
931 test_enum_fmtetc(data_cmpl);
933 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
935 test_no_cf_dataobject();
936 test_enum_fmtetc(NULL);
938 ref = IDataObject_Release(data1);
939 ok(ref == 0, "expected data1 ref=0, got %d\n", ref);
940 ref = IDataObject_Release(data2);
941 ok(ref == 0, "expected data2 ref=0, got %d\n", ref);
942 ref = IDataObject_Release(data_cmpl);
943 ok(ref == 0, "expected data_cmpl ref=0, got %d\n", ref);
945 OleUninitialize();
948 static LPDATAOBJECT clip_data;
949 static HWND next_wnd;
950 static UINT wm_drawclipboard;
952 static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
954 LRESULT ret;
956 switch (msg)
958 case WM_DRAWCLIPBOARD:
959 wm_drawclipboard++;
960 if (clip_data)
962 /* if this is the WM_DRAWCLIPBOARD of a previous change, the data isn't current yet */
963 /* this demonstrates an issue in Qt where it will free the data while it's being set */
964 HRESULT hr = OleIsCurrentClipboard( clip_data );
965 ok( hr == (wm_drawclipboard > 1) ? S_OK : S_FALSE,
966 "OleIsCurrentClipboard returned %x\n", hr );
968 break;
969 case WM_CHANGECBCHAIN:
970 if (next_wnd == (HWND)wp) next_wnd = (HWND)lp;
971 else if (next_wnd) SendMessageA( next_wnd, msg, wp, lp );
972 break;
973 case WM_USER:
974 ret = wm_drawclipboard;
975 wm_drawclipboard = 0;
976 return ret;
979 return DefWindowProcA(hwnd, msg, wp, lp);
982 static DWORD CALLBACK set_clipboard_thread(void *arg)
984 OpenClipboard( GetDesktopWindow() );
985 EmptyClipboard();
986 SetClipboardData( CF_WAVE, 0 );
987 CloseClipboard();
988 return 0;
991 /* test that WM_DRAWCLIPBOARD can be delivered for a previous change during OleSetClipboard */
992 static void test_set_clipboard_DRAWCLIPBOARD(void)
994 LPDATAOBJECT data;
995 HRESULT hr;
996 WNDCLASSA cls;
997 HWND viewer;
998 int ret;
999 HANDLE thread;
1001 hr = DataObjectImpl_CreateText("data", &data);
1002 ok(hr == S_OK, "Failed to create data object: 0x%08x\n", hr);
1004 memset(&cls, 0, sizeof(cls));
1005 cls.lpfnWndProc = clipboard_wnd_proc;
1006 cls.hInstance = GetModuleHandleA(NULL);
1007 cls.lpszClassName = "clipboard_test";
1008 RegisterClassA(&cls);
1010 viewer = CreateWindowA("clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0);
1011 ok(viewer != NULL, "CreateWindow failed: %d\n", GetLastError());
1012 next_wnd = SetClipboardViewer( viewer );
1014 ret = SendMessageA( viewer, WM_USER, 0, 0 );
1015 ok( ret == 1, "%u WM_DRAWCLIPBOARD received\n", ret );
1017 hr = OleInitialize(NULL);
1018 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
1020 ret = SendMessageA( viewer, WM_USER, 0, 0 );
1021 ok( !ret, "%u WM_DRAWCLIPBOARD received\n", ret );
1023 thread = CreateThread(NULL, 0, set_clipboard_thread, NULL, 0, NULL);
1024 ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError());
1025 ret = WaitForSingleObject(thread, 5000);
1026 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret);
1028 clip_data = data;
1029 hr = OleSetClipboard(data);
1030 ok(hr == S_OK, "failed to set clipboard to data, hr = 0x%08x\n", hr);
1032 ret = SendMessageA( viewer, WM_USER, 0, 0 );
1033 ok( ret == 2, "%u WM_DRAWCLIPBOARD received\n", ret );
1035 clip_data = NULL;
1036 hr = OleFlushClipboard();
1037 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
1038 ret = IDataObject_Release(data);
1039 ok(ret == 0, "got %d\n", ret);
1041 OleUninitialize();
1042 ChangeClipboardChain( viewer, next_wnd );
1043 DestroyWindow( viewer );
1046 static inline ULONG count_refs(IDataObject *d)
1048 IDataObject_AddRef(d);
1049 return IDataObject_Release(d);
1052 static void test_consumer_refs(void)
1054 HRESULT hr;
1055 IDataObject *src, *src2, *get1, *get2, *get3;
1056 ULONG refs, old_refs;
1057 FORMATETC fmt;
1058 STGMEDIUM med;
1060 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1062 OleInitialize(NULL);
1064 /* First show that each clipboard state results in
1065 a different data object */
1067 hr = DataObjectImpl_CreateText("data1", &src);
1068 ok(hr == S_OK, "got %08x\n", hr);
1069 hr = DataObjectImpl_CreateText("data2", &src2);
1070 ok(hr == S_OK, "got %08x\n", hr);
1072 hr = OleSetClipboard(src);
1073 ok(hr == S_OK, "got %08x\n", hr);
1075 hr = OleGetClipboard(&get1);
1076 ok(hr == S_OK, "got %08x\n", hr);
1078 hr = OleGetClipboard(&get2);
1079 ok(hr == S_OK, "got %08x\n", hr);
1081 ok(get1 == get2, "data objects differ\n");
1082 refs = IDataObject_Release(get2);
1083 ok(refs == (get1 == get2 ? 1 : 0), "got %d\n", refs);
1085 OleFlushClipboard();
1087 DataObjectImpl_GetData_calls = 0;
1088 hr = IDataObject_GetData(get1, &fmt, &med);
1089 ok(hr == S_OK, "got %08x\n", hr);
1090 ok(DataObjectImpl_GetData_calls == 0, "GetData called\n");
1091 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1093 hr = OleGetClipboard(&get2);
1094 ok(hr == S_OK, "got %08x\n", hr);
1096 ok(get1 != get2, "data objects match\n");
1098 OleSetClipboard(NULL);
1100 hr = OleGetClipboard(&get3);
1101 ok(hr == S_OK, "got %08x\n", hr);
1103 ok(get1 != get3, "data objects match\n");
1104 ok(get2 != get3, "data objects match\n");
1106 IDataObject_Release(get3);
1107 IDataObject_Release(get2);
1108 IDataObject_Release(get1);
1110 /* Now call GetData before the flush and show that this
1111 takes a ref on our src data obj. */
1113 hr = OleSetClipboard(src);
1114 ok(hr == S_OK, "got %08x\n", hr);
1116 old_refs = count_refs(src);
1118 hr = OleGetClipboard(&get1);
1119 ok(hr == S_OK, "got %08x\n", hr);
1121 refs = count_refs(src);
1122 ok(refs == old_refs, "%d %d\n", refs, old_refs);
1124 DataObjectImpl_GetData_calls = 0;
1125 hr = IDataObject_GetData(get1, &fmt, &med);
1126 ok(hr == S_OK, "got %08x\n", hr);
1127 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1128 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1129 refs = count_refs(src);
1130 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1132 OleFlushClipboard();
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);
1140 refs = count_refs(src);
1141 ok(refs == 2, "%d\n", refs);
1143 IDataObject_Release(get1);
1145 refs = count_refs(src);
1146 ok(refs == 1, "%d\n", refs);
1148 /* Now set a second src object before the call to GetData
1149 and show that GetData calls that second src. */
1151 hr = OleSetClipboard(src);
1152 ok(hr == S_OK, "got %08x\n", hr);
1154 old_refs = count_refs(src);
1156 hr = OleGetClipboard(&get1);
1157 ok(hr == S_OK, "got %08x\n", hr);
1159 refs = count_refs(src);
1160 ok(refs == old_refs, "%d %d\n", refs, old_refs);
1162 hr = OleSetClipboard(src2);
1163 ok(hr == S_OK, "got %08x\n", hr);
1165 old_refs = count_refs(src2);
1167 DataObjectImpl_GetData_calls = 0;
1168 hr = IDataObject_GetData(get1, &fmt, &med);
1169 ok(hr == S_OK, "got %08x\n", hr);
1170 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1171 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1173 refs = count_refs(src);
1174 ok(refs == 1, "%d\n", refs);
1175 refs = count_refs(src2);
1176 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1178 OleSetClipboard(NULL);
1180 refs = count_refs(src2);
1181 ok(refs == 2, "%d\n", refs);
1183 IDataObject_Release(get1);
1185 IDataObject_Release(src2);
1186 IDataObject_Release(src);
1188 OleUninitialize();
1191 static void test_flushed_getdata(void)
1193 HRESULT hr;
1194 IDataObject *src, *get;
1195 FORMATETC fmt;
1196 STGMEDIUM med;
1197 STATSTG stat;
1198 DEVMODEW dm;
1200 OleInitialize(NULL);
1202 hr = DataObjectImpl_CreateComplex(&src);
1203 ok(hr == S_OK, "got %08x\n", hr);
1205 hr = OleSetClipboard(src);
1206 ok(hr == S_OK, "got %08x\n", hr);
1208 hr = OleFlushClipboard();
1209 ok(hr == S_OK, "got %08x\n", hr);
1211 hr = OleGetClipboard(&get);
1212 ok(hr == S_OK, "got %08x\n", hr);
1214 /* global format -> global & stream */
1216 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1217 hr = IDataObject_GetData(get, &fmt, &med);
1218 ok(hr == S_OK, "got %08x\n", hr);
1219 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1220 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1222 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTREAM);
1223 hr = IDataObject_GetData(get, &fmt, &med);
1224 ok(hr == S_OK, "got %08x\n", hr);
1225 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1226 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1228 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTORAGE);
1229 hr = IDataObject_GetData(get, &fmt, &med);
1230 ok(hr == E_FAIL, "got %08x\n", hr);
1231 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1233 InitFormatEtc(fmt, CF_TEXT, 0xffff);
1234 hr = IDataObject_GetData(get, &fmt, &med);
1235 ok(hr == S_OK, "got %08x\n", hr);
1236 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1237 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1239 /* stream format -> global & stream */
1241 InitFormatEtc(fmt, cf_stream, TYMED_ISTREAM);
1242 hr = IDataObject_GetData(get, &fmt, &med);
1243 ok(hr == S_OK, "got %08x\n", hr);
1244 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1245 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1247 InitFormatEtc(fmt, cf_stream, TYMED_ISTORAGE);
1248 hr = IDataObject_GetData(get, &fmt, &med);
1249 ok(hr == E_FAIL, "got %08x\n", hr);
1250 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1252 InitFormatEtc(fmt, cf_stream, TYMED_HGLOBAL);
1253 hr = IDataObject_GetData(get, &fmt, &med);
1254 ok(hr == S_OK, "got %08x\n", hr);
1255 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1256 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1258 InitFormatEtc(fmt, cf_stream, 0xffff);
1259 hr = IDataObject_GetData(get, &fmt, &med);
1260 ok(hr == S_OK, "got %08x\n", hr);
1261 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1262 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1264 /* storage format -> global, stream & storage */
1266 InitFormatEtc(fmt, cf_storage, TYMED_ISTORAGE);
1267 hr = IDataObject_GetData(get, &fmt, &med);
1268 ok(hr == S_OK, "got %08x\n", hr);
1269 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1270 if(SUCCEEDED(hr)) {
1271 hr = IStorage_Stat(med.u.pstg, &stat, STATFLAG_NONAME);
1272 ok(hr == S_OK, "got %08x\n", hr);
1273 ok(stat.grfMode == (STGM_SHARE_EXCLUSIVE | STGM_READWRITE), "got %08x\n", stat.grfMode);
1274 ReleaseStgMedium(&med);
1277 InitFormatEtc(fmt, cf_storage, TYMED_ISTREAM);
1278 hr = IDataObject_GetData(get, &fmt, &med);
1279 ok(hr == S_OK, "got %08x\n", hr);
1280 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1281 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1283 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL);
1284 hr = IDataObject_GetData(get, &fmt, &med);
1285 ok(hr == S_OK, "got %08x\n", hr);
1286 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1287 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1289 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL | TYMED_ISTREAM);
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);
1295 InitFormatEtc(fmt, cf_storage, 0xffff);
1296 hr = IDataObject_GetData(get, &fmt, &med);
1297 ok(hr == S_OK, "got %08x\n", hr);
1298 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1299 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1301 /* complex format with target device */
1303 InitFormatEtc(fmt, cf_another, 0xffff);
1304 hr = IDataObject_GetData(get, &fmt, &med);
1305 ok(hr == S_OK, "got %08x\n", hr);
1306 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1308 if (0) /* Causes crashes on both Wine and Windows */
1310 InitFormatEtc(fmt, cf_another, 0xffff);
1311 memset(&dm, 0, sizeof(dm));
1312 dm.dmSize = sizeof(dm);
1313 dm.dmDriverExtra = 0;
1314 lstrcpyW(dm.dmDeviceName, device_name);
1315 fmt.ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
1316 fmt.ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
1317 fmt.ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
1318 fmt.ptd->tdDeviceNameOffset = 0;
1319 fmt.ptd->tdPortNameOffset = 0;
1320 fmt.ptd->tdExtDevmodeOffset = fmt.ptd->tdDriverNameOffset + sizeof(device_name);
1321 lstrcpyW((WCHAR*)fmt.ptd->tdData, device_name);
1322 memcpy(fmt.ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
1324 hr = IDataObject_GetData(get, &fmt, &med);
1325 ok(hr == S_OK, "got %08x\n", hr);
1326 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1327 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1329 HeapFree(GetProcessHeap(), 0, fmt.ptd);
1333 IDataObject_Release(get);
1334 IDataObject_Release(src);
1335 OleUninitialize();
1338 static HGLOBAL create_text(void)
1340 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5);
1341 char *p = GlobalLock(h);
1342 strcpy(p, "test");
1343 GlobalUnlock(h);
1344 return h;
1347 static HENHMETAFILE create_emf(void)
1349 const RECT rect = {0, 0, 100, 100};
1350 HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1351 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
1352 return CloseEnhMetaFile(hdc);
1355 static void test_nonole_clipboard(void)
1357 HRESULT hr;
1358 BOOL r;
1359 IDataObject *get;
1360 IEnumFORMATETC *enum_fmt;
1361 FORMATETC fmt;
1362 HGLOBAL h, hblob, htext;
1363 HENHMETAFILE emf;
1364 STGMEDIUM med;
1365 DWORD obj_type;
1367 r = OpenClipboard(NULL);
1368 ok(r, "gle %d\n", GetLastError());
1369 r = EmptyClipboard();
1370 ok(r, "gle %d\n", GetLastError());
1371 r = CloseClipboard();
1372 ok(r, "gle %d\n", GetLastError());
1374 OleInitialize(NULL);
1376 /* empty clipboard */
1377 hr = OleGetClipboard(&get);
1378 ok(hr == S_OK, "got %08x\n", hr);
1379 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1380 ok(hr == S_OK, "got %08x\n", hr);
1382 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1383 ok(hr == S_FALSE, "got %08x\n", hr);
1384 IEnumFORMATETC_Release(enum_fmt);
1386 IDataObject_Release(get);
1388 /* set a user defined clipboard type */
1390 htext = create_text();
1391 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
1392 emf = create_emf();
1394 r = OpenClipboard(NULL);
1395 ok(r, "gle %d\n", GetLastError());
1396 h = SetClipboardData(CF_TEXT, htext);
1397 ok(h == htext, "got %p\n", h);
1398 h = SetClipboardData(cf_onemore, hblob);
1399 ok(h == hblob, "got %p\n", h);
1400 h = SetClipboardData(CF_ENHMETAFILE, emf);
1401 ok(h == emf, "got %p\n", h);
1402 r = CloseClipboard();
1403 ok(r, "gle %d\n", GetLastError());
1405 hr = OleGetClipboard(&get);
1406 ok(hr == S_OK, "got %08x\n", hr);
1407 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1408 ok(hr == S_OK, "got %08x\n", hr);
1410 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1411 ok(hr == S_OK, "got %08x\n", hr);
1412 ok(fmt.cfFormat == CF_TEXT, "cf %04x\n", fmt.cfFormat);
1413 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1414 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1415 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1416 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1418 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1419 ok(hr == S_OK, "got %08x\n", hr);
1420 ok(fmt.cfFormat == cf_onemore, "cf %04x\n", fmt.cfFormat);
1421 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1422 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1423 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1424 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1426 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1427 ok(hr == S_OK, "got %08x\n", hr);
1428 ok(fmt.cfFormat == CF_ENHMETAFILE, "cf %04x\n", fmt.cfFormat);
1429 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1430 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1431 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1432 ok(fmt.tymed == TYMED_ENHMF, "tymed %x\n", fmt.tymed);
1434 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1435 ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */
1437 ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
1438 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1439 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1440 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1441 todo_wine ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1443 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1444 ok(hr == S_OK, "got %08x\n", hr);
1446 ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat);
1447 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1448 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1449 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1450 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1452 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1453 ok(hr == S_OK, "got %08x\n", hr);
1454 ok(fmt.cfFormat == CF_UNICODETEXT, "cf %04x\n", fmt.cfFormat);
1455 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1456 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1457 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1458 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1460 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1461 ok(hr == S_OK, "got %08x\n", hr);
1462 ok(fmt.cfFormat == CF_METAFILEPICT, "cf %04x\n", fmt.cfFormat);
1463 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1464 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1465 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1466 ok(fmt.tymed == TYMED_MFPICT, "tymed %x\n", fmt.tymed);
1468 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1469 ok(hr == S_FALSE, "got %08x\n", hr);
1470 IEnumFORMATETC_Release(enum_fmt);
1472 InitFormatEtc(fmt, CF_ENHMETAFILE, TYMED_ENHMF);
1473 hr = IDataObject_GetData(get, &fmt, &med);
1474 ok(hr == S_OK, "got %08x\n", hr);
1475 obj_type = GetObjectType(U(med).hEnhMetaFile);
1476 ok(obj_type == OBJ_ENHMETAFILE, "got %d\n", obj_type);
1477 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1479 IDataObject_Release(get);
1481 r = OpenClipboard(NULL);
1482 ok(r, "gle %d\n", GetLastError());
1483 r = EmptyClipboard();
1484 ok(r, "gle %d\n", GetLastError());
1485 r = CloseClipboard();
1486 ok(r, "gle %d\n", GetLastError());
1488 OleUninitialize();
1491 static void test_getdatahere(void)
1493 HRESULT hr;
1494 IDataObject *src, *get;
1495 FORMATETC fmt;
1496 STGMEDIUM med;
1498 OleInitialize(NULL);
1500 hr = DataObjectImpl_CreateComplex(&src);
1501 ok(hr == S_OK, "got %08x\n", hr);
1503 hr = OleSetClipboard(src);
1504 ok(hr == S_OK, "got %08x\n", hr);
1506 hr = OleGetClipboard(&get);
1507 ok(hr == S_OK, "got %08x\n", hr);
1509 /* global format -> global & stream */
1511 DataObjectImpl_GetData_calls = 0;
1512 DataObjectImpl_GetDataHere_calls = 0;
1514 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1516 med.pUnkForRelease = NULL;
1517 med.tymed = TYMED_HGLOBAL;
1518 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1519 hr = IDataObject_GetDataHere(get, &fmt, &med);
1520 ok(hr == S_OK, "got %08x\n", hr);
1521 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1522 ReleaseStgMedium(&med);
1523 ok(DataObjectImpl_GetDataHere_calls == 1, "called %d\n", DataObjectImpl_GetDataHere_calls);
1524 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1526 InitFormatEtc(fmt, CF_TEXT, 0);
1528 med.pUnkForRelease = NULL;
1529 med.tymed = TYMED_HGLOBAL;
1530 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1531 hr = IDataObject_GetDataHere(get, &fmt, &med);
1532 ok(hr == S_OK, "got %08x\n", hr);
1533 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1534 ReleaseStgMedium(&med);
1535 ok(DataObjectImpl_GetDataHere_calls == 2, "called %d\n", DataObjectImpl_GetDataHere_calls);
1536 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1538 med.pUnkForRelease = NULL;
1539 med.tymed = TYMED_HGLOBAL;
1540 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 1);
1541 hr = IDataObject_GetDataHere(get, &fmt, &med);
1542 ok(hr == E_FAIL, "got %08x\n", hr);
1543 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1544 ReleaseStgMedium(&med);
1545 ok(DataObjectImpl_GetDataHere_calls == 3, "called %d\n", DataObjectImpl_GetDataHere_calls);
1546 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1548 med.pUnkForRelease = NULL;
1549 med.tymed = TYMED_ISTREAM;
1550 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1551 hr = IDataObject_GetDataHere(get, &fmt, &med);
1552 ok(hr == S_OK, "got %08x\n", hr);
1553 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1554 ReleaseStgMedium(&med);
1555 ok(DataObjectImpl_GetDataHere_calls == 4, "called %d\n", DataObjectImpl_GetDataHere_calls);
1556 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1558 med.pUnkForRelease = NULL;
1559 med.tymed = TYMED_ISTORAGE;
1560 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1561 hr = IDataObject_GetDataHere(get, &fmt, &med);
1562 ok(hr == E_FAIL, "got %08x\n", hr);
1563 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1564 ReleaseStgMedium(&med);
1565 ok(DataObjectImpl_GetDataHere_calls == 5, "called %d\n", DataObjectImpl_GetDataHere_calls);
1566 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1568 InitFormatEtc(fmt, cf_stream, 0);
1570 med.pUnkForRelease = NULL;
1571 med.tymed = TYMED_HGLOBAL;
1572 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1573 hr = IDataObject_GetDataHere(get, &fmt, &med);
1574 ok(hr == S_OK, "got %08x\n", hr);
1575 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1576 ReleaseStgMedium(&med);
1577 ok(DataObjectImpl_GetDataHere_calls == 7, "called %d\n", DataObjectImpl_GetDataHere_calls);
1578 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1580 med.pUnkForRelease = NULL;
1581 med.tymed = TYMED_ISTREAM;
1582 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1583 hr = IDataObject_GetDataHere(get, &fmt, &med);
1584 ok(hr == S_OK, "got %08x\n", hr);
1585 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1586 ReleaseStgMedium(&med);
1587 ok(DataObjectImpl_GetDataHere_calls == 8, "called %d\n", DataObjectImpl_GetDataHere_calls);
1588 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1590 med.pUnkForRelease = NULL;
1591 med.tymed = TYMED_ISTORAGE;
1592 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1593 hr = IDataObject_GetDataHere(get, &fmt, &med);
1594 ok(hr == E_FAIL, "got %08x\n", hr);
1595 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1596 ReleaseStgMedium(&med);
1597 ok(DataObjectImpl_GetDataHere_calls == 9, "called %d\n", DataObjectImpl_GetDataHere_calls);
1598 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1600 InitFormatEtc(fmt, cf_storage, 0);
1602 med.pUnkForRelease = NULL;
1603 med.tymed = TYMED_HGLOBAL;
1604 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 3000);
1605 hr = IDataObject_GetDataHere(get, &fmt, &med);
1606 ok(hr == S_OK, "got %08x\n", hr);
1607 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1608 ReleaseStgMedium(&med);
1609 ok(DataObjectImpl_GetDataHere_calls == 11, "called %d\n", DataObjectImpl_GetDataHere_calls);
1610 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1612 med.pUnkForRelease = NULL;
1613 med.tymed = TYMED_ISTREAM;
1614 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1615 hr = IDataObject_GetDataHere(get, &fmt, &med);
1616 ok(hr == S_OK, "got %08x\n", hr);
1617 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1618 ReleaseStgMedium(&med);
1619 ok(DataObjectImpl_GetDataHere_calls == 12, "called %d\n", DataObjectImpl_GetDataHere_calls);
1620 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1622 med.pUnkForRelease = NULL;
1623 med.tymed = TYMED_ISTORAGE;
1624 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1625 hr = IDataObject_GetDataHere(get, &fmt, &med);
1626 ok(hr == S_OK, "got %08x\n", hr);
1627 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1628 ReleaseStgMedium(&med);
1629 ok(DataObjectImpl_GetDataHere_calls == 13, "called %d\n", DataObjectImpl_GetDataHere_calls);
1630 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1633 IDataObject_Release(get);
1634 IDataObject_Release(src);
1636 OleUninitialize();
1640 static DWORD CALLBACK test_data_obj(void *arg)
1642 IDataObject *data_obj = arg;
1644 IDataObject_Release(data_obj);
1645 return 0;
1648 static void test_multithreaded_clipboard(void)
1650 IDataObject *data_obj;
1651 HANDLE thread;
1652 HRESULT hr;
1653 DWORD ret;
1655 OleInitialize(NULL);
1657 hr = OleGetClipboard(&data_obj);
1658 ok(hr == S_OK, "OleGetClipboard returned %x\n", hr);
1660 thread = CreateThread(NULL, 0, test_data_obj, data_obj, 0, NULL);
1661 ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError());
1662 ret = WaitForSingleObject(thread, 5000);
1663 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret);
1665 hr = OleGetClipboard(&data_obj);
1666 ok(hr == S_OK, "OleGetClipboard returned %x\n", hr);
1667 IDataObject_Release(data_obj);
1669 OleUninitialize();
1672 static void test_get_clipboard_locked(void)
1674 HRESULT hr;
1675 IDataObject *pDObj;
1677 OleInitialize(NULL);
1679 pDObj = (IDataObject *)0xdeadbeef;
1680 /* lock clipboard */
1681 OpenClipboard(NULL);
1682 hr = OleGetClipboard(&pDObj);
1683 todo_wine ok(hr == CLIPBRD_E_CANT_OPEN, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr, CLIPBRD_E_CANT_OPEN);
1684 todo_wine ok(pDObj == NULL, "OleGetClipboard() got 0x%p instead of NULL\n",pDObj);
1685 if (pDObj) IDataObject_Release(pDObj);
1686 CloseClipboard();
1688 OleUninitialize();
1691 START_TEST(clipboard)
1693 test_get_clipboard_uninitialized();
1694 test_set_clipboard();
1695 test_set_clipboard_DRAWCLIPBOARD();
1696 test_consumer_refs();
1697 test_flushed_getdata();
1698 test_nonole_clipboard();
1699 test_getdatahere();
1700 test_multithreaded_clipboard();
1701 test_get_clipboard_locked();