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