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