ole32: Fix crash when calling CreateStream on read only storage.
[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     if (hr == S_OK)
481         ReleaseStgMedium(&stgmedium);
482
483     InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
484     fmtetc.cfFormat = CF_RIFF;
485     hr = IDataObject_QueryGetData(data_obj, &fmtetc);
486     ok(hr == DV_E_CLIPFORMAT, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr);
487
488     InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
489     fmtetc.tymed = TYMED_FILE;
490     hr = IDataObject_QueryGetData(data_obj, &fmtetc);
491     ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
492
493     expect_DataObjectImpl_QueryGetData = TRUE;
494
495     /* test IDataObject_GetData */
496
497     DataObjectImpl_GetData_calls = 0;
498
499     InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
500     hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
501     ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
502     ReleaseStgMedium(&stgmedium);
503
504     InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
505     fmtetc.dwAspect = 0xdeadbeef;
506     hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
507     ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
508     ReleaseStgMedium(&stgmedium);
509
510     InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
511     fmtetc.dwAspect = DVASPECT_THUMBNAIL;
512     hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
513     ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
514     ReleaseStgMedium(&stgmedium);
515
516     InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
517     fmtetc.lindex = 256;
518     hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
519     ok(hr == DV_E_FORMATETC || broken(hr == S_OK), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
520     if (hr == S_OK)
521     {
522         /* undo the unexpected success */
523         DataObjectImpl_GetData_calls--;
524         ReleaseStgMedium(&stgmedium);
525     }
526
527     InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
528     fmtetc.cfFormat = CF_RIFF;
529     hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
530     ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
531
532     InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
533     fmtetc.tymed = TYMED_FILE;
534     hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
535     ok(hr == DV_E_TYMED, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr);
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     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     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     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     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     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     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
1111     InitFormatEtc(fmt, CF_TEXT, 0xffff);
1112     hr = IDataObject_GetData(get, &fmt, &med);
1113     ok(hr == S_OK, "got %08x\n", hr);
1114     ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1115     ReleaseStgMedium(&med);
1116
1117     /* stream format -> global & stream */
1118
1119     InitFormatEtc(fmt, cf_stream, TYMED_ISTREAM);
1120     hr = IDataObject_GetData(get, &fmt, &med);
1121     ok(hr == S_OK, "got %08x\n", hr);
1122     ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1123     ReleaseStgMedium(&med);
1124
1125     InitFormatEtc(fmt, cf_stream, TYMED_ISTORAGE);
1126     hr = IDataObject_GetData(get, &fmt, &med);
1127     ok(hr == E_FAIL, "got %08x\n", hr);
1128
1129     InitFormatEtc(fmt, cf_stream, TYMED_HGLOBAL);
1130     hr = IDataObject_GetData(get, &fmt, &med);
1131     ok(hr == S_OK, "got %08x\n", hr);
1132     ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1133     ReleaseStgMedium(&med);
1134
1135     InitFormatEtc(fmt, cf_stream, 0xffff);
1136     hr = IDataObject_GetData(get, &fmt, &med);
1137     ok(hr == S_OK, "got %08x\n", hr);
1138     ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1139     ReleaseStgMedium(&med);
1140
1141     /* storage format -> global, stream & storage */
1142
1143     InitFormatEtc(fmt, cf_storage, TYMED_ISTORAGE);
1144     hr = IDataObject_GetData(get, &fmt, &med);
1145     ok(hr == S_OK, "got %08x\n", hr);
1146     ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1147     hr = IStorage_Stat(med.u.pstg, &stat, STATFLAG_NONAME);
1148     ok(hr == S_OK, "got %08x\n", hr);
1149     ok(stat.grfMode == (STGM_SHARE_EXCLUSIVE | STGM_READWRITE), "got %08x\n", stat.grfMode);
1150     ReleaseStgMedium(&med);
1151
1152     InitFormatEtc(fmt, cf_storage, TYMED_ISTREAM);
1153     hr = IDataObject_GetData(get, &fmt, &med);
1154     ok(hr == S_OK, "got %08x\n", hr);
1155     ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1156     ReleaseStgMedium(&med);
1157
1158     InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL);
1159     hr = IDataObject_GetData(get, &fmt, &med);
1160     ok(hr == S_OK, "got %08x\n", hr);
1161     ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1162     ReleaseStgMedium(&med);
1163
1164     InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL | TYMED_ISTREAM);
1165     hr = IDataObject_GetData(get, &fmt, &med);
1166     ok(hr == S_OK, "got %08x\n", hr);
1167     ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1168     ReleaseStgMedium(&med);
1169
1170     InitFormatEtc(fmt, cf_storage, 0xffff);
1171     hr = IDataObject_GetData(get, &fmt, &med);
1172     ok(hr == S_OK, "got %08x\n", hr);
1173     ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1174     ReleaseStgMedium(&med);
1175
1176     /* complex format with target device */
1177
1178     InitFormatEtc(fmt, cf_another, 0xffff);
1179     hr = IDataObject_GetData(get, &fmt, &med);
1180     ok(hr == DV_E_FORMATETC ||
1181        broken(hr == S_OK), /* win9x, winme & nt4 */
1182        "got %08x\n", hr);
1183     if(hr == S_OK) ReleaseStgMedium(&med);
1184
1185     InitFormatEtc(fmt, cf_another, 0xffff);
1186     memset(&dm, 0, sizeof(dm));
1187     dm.dmSize = sizeof(dm);
1188     dm.dmDriverExtra = 0;
1189     lstrcpyW(dm.dmDeviceName, device_name);
1190     fmt.ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
1191     fmt.ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
1192     fmt.ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
1193     fmt.ptd->tdDeviceNameOffset = 0;
1194     fmt.ptd->tdPortNameOffset   = 0;
1195     fmt.ptd->tdExtDevmodeOffset = fmt.ptd->tdDriverNameOffset + sizeof(device_name);
1196     lstrcpyW((WCHAR*)fmt.ptd->tdData, device_name);
1197     memcpy(fmt.ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
1198
1199     hr = IDataObject_GetData(get, &fmt, &med);
1200     ok(hr == S_OK, "got %08x\n", hr);
1201     ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1202     ReleaseStgMedium(&med);
1203
1204     HeapFree(GetProcessHeap(), 0, fmt.ptd);
1205
1206
1207     IDataObject_Release(get);
1208     IDataObject_Release(src);
1209     OleUninitialize();
1210 }
1211
1212 static HGLOBAL create_text(void)
1213 {
1214     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5);
1215     char *p = GlobalLock(h);
1216     strcpy(p, "test");
1217     GlobalUnlock(h);
1218     return h;
1219 }
1220
1221 static HENHMETAFILE create_emf(void)
1222 {
1223     const RECT rect = {0, 0, 100, 100};
1224     HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1225     ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
1226     return CloseEnhMetaFile(hdc);
1227 }
1228
1229 static void test_nonole_clipboard(void)
1230 {
1231     HRESULT hr;
1232     BOOL r;
1233     IDataObject *get;
1234     IEnumFORMATETC *enum_fmt;
1235     FORMATETC fmt;
1236     HGLOBAL h, hblob, htext;
1237     HENHMETAFILE emf;
1238
1239     r = OpenClipboard(NULL);
1240     ok(r, "gle %d\n", GetLastError());
1241     r = EmptyClipboard();
1242     ok(r, "gle %d\n", GetLastError());
1243     r = CloseClipboard();
1244     ok(r, "gle %d\n", GetLastError());
1245
1246     OleInitialize(NULL);
1247
1248     /* empty clipboard */
1249     hr = OleGetClipboard(&get);
1250     ok(hr == S_OK, "got %08x\n", hr);
1251     hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1252     ok(hr == S_OK, "got %08x\n", hr);
1253
1254     hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1255     ok(hr == S_FALSE, "got %08x\n", hr);
1256     IEnumFORMATETC_Release(enum_fmt);
1257
1258     IDataObject_Release(get);
1259
1260     /* set a user defined clipboard type */
1261
1262     htext = create_text();
1263     hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
1264     emf = create_emf();
1265
1266     r = OpenClipboard(NULL);
1267     ok(r, "gle %d\n", GetLastError());
1268     h = SetClipboardData(CF_TEXT, htext);
1269     ok(h == htext, "got %p\n", h);
1270     h = SetClipboardData(cf_onemore, hblob);
1271     ok(h == hblob, "got %p\n", h);
1272     h = SetClipboardData(CF_ENHMETAFILE, emf);
1273     ok(h == emf, "got %p\n", h);
1274     r = CloseClipboard();
1275     ok(r, "gle %d\n", GetLastError());
1276
1277     hr = OleGetClipboard(&get);
1278     ok(hr == S_OK, "got %08x\n", hr);
1279     hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1280     ok(hr == S_OK, "got %08x\n", hr);
1281
1282     hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1283     ok(hr == S_OK, "got %08x\n", hr);
1284     ok(fmt.cfFormat == CF_TEXT, "cf %04x\n", fmt.cfFormat);
1285     ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1286     ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1287     ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1288     ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1289
1290     hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1291     ok(hr == S_OK, "got %08x\n", hr);
1292     ok(fmt.cfFormat == cf_onemore, "cf %04x\n", fmt.cfFormat);
1293     ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1294     ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1295     ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1296     ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1297
1298     hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1299     ok(hr == S_OK, "got %08x\n", hr);
1300     ok(fmt.cfFormat == CF_ENHMETAFILE, "cf %04x\n", fmt.cfFormat);
1301     ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1302     ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1303     ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1304     ok(fmt.tymed == TYMED_ENHMF, "tymed %x\n", fmt.tymed);
1305
1306     hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1307     ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */
1308
1309     todo_wine ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
1310     if(fmt.cfFormat == CF_LOCALE)
1311     {
1312         ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1313         ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1314         ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1315         ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1316
1317         hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1318         ok(hr == S_OK, "got %08x\n", hr);
1319     }
1320
1321     ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat);
1322     ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1323     ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1324     ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1325     ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1326
1327     hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1328     ok(hr == S_OK, "got %08x\n", hr);
1329     ok(fmt.cfFormat == CF_UNICODETEXT ||
1330        broken(fmt.cfFormat == CF_METAFILEPICT), /* win9x and winme don't have CF_UNICODETEXT */
1331        "cf %04x\n", fmt.cfFormat);
1332     if(fmt.cfFormat == CF_UNICODETEXT)
1333     {
1334         ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1335         ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1336         ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1337         ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1338
1339         hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1340         ok(hr == S_OK, "got %08x\n", hr);
1341     }
1342     ok(fmt.cfFormat == CF_METAFILEPICT, "cf %04x\n", fmt.cfFormat);
1343     ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1344     ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1345     ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1346     ok(fmt.tymed == TYMED_MFPICT, "tymed %x\n", fmt.tymed);
1347
1348     hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1349     ok(hr == S_FALSE, "got %08x\n", hr);
1350     IEnumFORMATETC_Release(enum_fmt);
1351
1352     IDataObject_Release(get);
1353
1354     r = OpenClipboard(NULL);
1355     ok(r, "gle %d\n", GetLastError());
1356     r = EmptyClipboard();
1357     ok(r, "gle %d\n", GetLastError());
1358     r = CloseClipboard();
1359     ok(r, "gle %d\n", GetLastError());
1360
1361     OleUninitialize();
1362 }
1363
1364 static void test_getdatahere(void)
1365 {
1366     HRESULT hr;
1367     IDataObject *src, *get;
1368     FORMATETC fmt;
1369     STGMEDIUM med;
1370
1371     OleInitialize(NULL);
1372
1373     hr = DataObjectImpl_CreateComplex(&src);
1374     ok(hr == S_OK, "got %08x\n", hr);
1375
1376     hr = OleSetClipboard(src);
1377     ok(hr == S_OK, "got %08x\n", hr);
1378
1379     hr = OleGetClipboard(&get);
1380     ok(hr == S_OK, "got %08x\n", hr);
1381
1382     /* global format -> global & stream */
1383
1384     DataObjectImpl_GetData_calls = 0;
1385     DataObjectImpl_GetDataHere_calls = 0;
1386
1387     InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1388
1389     med.pUnkForRelease = NULL;
1390     med.tymed = TYMED_HGLOBAL;
1391     U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1392     hr = IDataObject_GetDataHere(get, &fmt, &med);
1393     ok(hr == S_OK, "got %08x\n", hr);
1394     ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1395     ReleaseStgMedium(&med);
1396     ok(DataObjectImpl_GetDataHere_calls == 1, "called %d\n", DataObjectImpl_GetDataHere_calls);
1397     ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1398
1399     InitFormatEtc(fmt, CF_TEXT, 0);
1400
1401     med.pUnkForRelease = NULL;
1402     med.tymed = TYMED_HGLOBAL;
1403     U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1404     hr = IDataObject_GetDataHere(get, &fmt, &med);
1405     ok(hr == S_OK, "got %08x\n", hr);
1406     ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1407     ReleaseStgMedium(&med);
1408     ok(DataObjectImpl_GetDataHere_calls == 2, "called %d\n", DataObjectImpl_GetDataHere_calls);
1409     ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1410
1411     med.pUnkForRelease = NULL;
1412     med.tymed = TYMED_HGLOBAL;
1413     U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 1);
1414     hr = IDataObject_GetDataHere(get, &fmt, &med);
1415     ok(hr == E_FAIL, "got %08x\n", hr);
1416     ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1417     ReleaseStgMedium(&med);
1418     ok(DataObjectImpl_GetDataHere_calls == 3, "called %d\n", DataObjectImpl_GetDataHere_calls);
1419     ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1420
1421     med.pUnkForRelease = NULL;
1422     med.tymed = TYMED_ISTREAM;
1423     CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1424     hr = IDataObject_GetDataHere(get, &fmt, &med);
1425     ok(hr == S_OK, "got %08x\n", hr);
1426     ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1427     ReleaseStgMedium(&med);
1428     ok(DataObjectImpl_GetDataHere_calls == 4, "called %d\n", DataObjectImpl_GetDataHere_calls);
1429     ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1430
1431     med.pUnkForRelease = NULL;
1432     med.tymed = TYMED_ISTORAGE;
1433     StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1434     hr = IDataObject_GetDataHere(get, &fmt, &med);
1435     ok(hr == E_FAIL, "got %08x\n", hr);
1436     ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1437     ReleaseStgMedium(&med);
1438     ok(DataObjectImpl_GetDataHere_calls == 5, "called %d\n", DataObjectImpl_GetDataHere_calls);
1439     ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1440
1441     InitFormatEtc(fmt, cf_stream, 0);
1442
1443     med.pUnkForRelease = NULL;
1444     med.tymed = TYMED_HGLOBAL;
1445     U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1446     hr = IDataObject_GetDataHere(get, &fmt, &med);
1447     ok(hr == S_OK, "got %08x\n", hr);
1448     ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1449     ReleaseStgMedium(&med);
1450     ok(DataObjectImpl_GetDataHere_calls == 7, "called %d\n", DataObjectImpl_GetDataHere_calls);
1451     ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1452
1453     med.pUnkForRelease = NULL;
1454     med.tymed = TYMED_ISTREAM;
1455     CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1456     hr = IDataObject_GetDataHere(get, &fmt, &med);
1457     ok(hr == S_OK, "got %08x\n", hr);
1458     ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1459     ReleaseStgMedium(&med);
1460     ok(DataObjectImpl_GetDataHere_calls == 8, "called %d\n", DataObjectImpl_GetDataHere_calls);
1461     ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1462
1463     med.pUnkForRelease = NULL;
1464     med.tymed = TYMED_ISTORAGE;
1465     StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1466     hr = IDataObject_GetDataHere(get, &fmt, &med);
1467     ok(hr == E_FAIL, "got %08x\n", hr);
1468     ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1469     ReleaseStgMedium(&med);
1470     ok(DataObjectImpl_GetDataHere_calls == 9, "called %d\n", DataObjectImpl_GetDataHere_calls);
1471     ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1472
1473     InitFormatEtc(fmt, cf_storage, 0);
1474
1475     med.pUnkForRelease = NULL;
1476     med.tymed = TYMED_HGLOBAL;
1477     U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 3000);
1478     hr = IDataObject_GetDataHere(get, &fmt, &med);
1479     ok(hr == S_OK, "got %08x\n", hr);
1480     ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1481     ReleaseStgMedium(&med);
1482     ok(DataObjectImpl_GetDataHere_calls == 11, "called %d\n", DataObjectImpl_GetDataHere_calls);
1483     ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1484
1485     med.pUnkForRelease = NULL;
1486     med.tymed = TYMED_ISTREAM;
1487     CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1488     hr = IDataObject_GetDataHere(get, &fmt, &med);
1489     ok(hr == S_OK, "got %08x\n", hr);
1490     ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1491     ReleaseStgMedium(&med);
1492     ok(DataObjectImpl_GetDataHere_calls == 12, "called %d\n", DataObjectImpl_GetDataHere_calls);
1493     ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1494
1495     med.pUnkForRelease = NULL;
1496     med.tymed = TYMED_ISTORAGE;
1497     StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1498     hr = IDataObject_GetDataHere(get, &fmt, &med);
1499     ok(hr == S_OK, "got %08x\n", hr);
1500     ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1501     ReleaseStgMedium(&med);
1502     ok(DataObjectImpl_GetDataHere_calls == 13, "called %d\n", DataObjectImpl_GetDataHere_calls);
1503     ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1504
1505
1506     IDataObject_Release(get);
1507     IDataObject_Release(src);
1508
1509     OleUninitialize();
1510
1511 }
1512
1513 START_TEST(clipboard)
1514 {
1515     test_set_clipboard();
1516     test_consumer_refs();
1517     test_flushed_getdata();
1518     test_nonole_clipboard();
1519     test_getdatahere();
1520 }