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