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