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