f06a4823ac081d8628838e29229a8ec7f81dfe6d
[reactos.git] / rostests / winetests / ole32 / 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)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 }