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