386f568e26d0afa4b35d8adbfc99636ef722a72d
[reactos.git] / rostests / winetests / ole32 / clipboard.c
1 /*
2 * Clipboard unit tests
3 *
4 * Copyright 2006 Kevin Koltzau
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #define WIN32_NO_STATUS
22 #define _INC_WINDOWS
23 #define COM_NO_WINDOWS_H
24
25 #define COBJMACROS
26 #define CONST_VTABLE
27 #define NONAMELESSUNION
28
29 //#include <stdarg.h>
30 #include <stdio.h>
31
32 #include <windef.h>
33 #include <winbase.h>
34 #include <wingdi.h>
35 #include <ole2.h>
36 //#include "objbase.h"
37
38 #include <wine/test.h>
39
40 #define InitFormatEtc(fe, cf, med) \
41 {\
42 (fe).cfFormat=cf;\
43 (fe).dwAspect=DVASPECT_CONTENT;\
44 (fe).ptd=NULL;\
45 (fe).tymed=med;\
46 (fe).lindex=-1;\
47 };
48
49 static inline char *dump_fmtetc(FORMATETC *fmt)
50 {
51 static char buf[100];
52
53 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
54 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
55 return buf;
56 }
57
58 typedef struct DataObjectImpl {
59 IDataObject IDataObject_iface;
60 LONG ref;
61
62 FORMATETC *fmtetc;
63 UINT fmtetc_cnt;
64
65 HANDLE text;
66 IStream *stm;
67 IStorage *stg;
68 } DataObjectImpl;
69
70 typedef struct EnumFormatImpl {
71 IEnumFORMATETC IEnumFORMATETC_iface;
72 LONG ref;
73
74 FORMATETC *fmtetc;
75 UINT fmtetc_cnt;
76
77 UINT cur;
78 } EnumFormatImpl;
79
80 static BOOL expect_DataObjectImpl_QueryGetData = TRUE;
81 static ULONG DataObjectImpl_GetData_calls = 0;
82 static ULONG DataObjectImpl_GetDataHere_calls = 0;
83 static ULONG DataObjectImpl_EnumFormatEtc_calls = 0;
84
85 static UINT cf_stream, cf_storage, cf_global, cf_another, cf_onemore;
86
87 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
88
89 static inline DataObjectImpl *impl_from_IDataObject(IDataObject *iface)
90 {
91 return CONTAINING_RECORD(iface, DataObjectImpl, IDataObject_iface);
92 }
93
94 static inline EnumFormatImpl *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
95 {
96 return CONTAINING_RECORD(iface, EnumFormatImpl, IEnumFORMATETC_iface);
97 }
98
99 static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
100 {
101 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
102
103 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) {
104 IEnumFORMATETC_AddRef(iface);
105 *ppvObj = &This->IEnumFORMATETC_iface;
106 return S_OK;
107 }
108 *ppvObj = NULL;
109 return E_NOINTERFACE;
110 }
111
112 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
113 {
114 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
115 LONG ref = InterlockedIncrement(&This->ref);
116 return ref;
117 }
118
119 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
120 {
121 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
122 ULONG ref = InterlockedDecrement(&This->ref);
123
124 if(!ref) {
125 HeapFree(GetProcessHeap(), 0, This->fmtetc);
126 HeapFree(GetProcessHeap(), 0, This);
127 }
128
129 return ref;
130 }
131
132 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
133 FORMATETC *rgelt, ULONG *pceltFetched)
134 {
135 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
136 ULONG count, i;
137
138 if (winetest_debug > 1)
139 trace("next: count %d cur %d\n", celt, This->cur);
140
141 if(!rgelt)
142 return E_INVALIDARG;
143
144 count = min(celt, This->fmtetc_cnt - This->cur);
145 for(i = 0; i < count; i++, This->cur++, rgelt++)
146 {
147 *rgelt = This->fmtetc[This->cur];
148 if(rgelt->ptd)
149 {
150 DWORD size = This->fmtetc[This->cur].ptd->tdSize;
151 rgelt->ptd = CoTaskMemAlloc(size);
152 memcpy(rgelt->ptd, This->fmtetc[This->cur].ptd, size);
153 }
154 }
155 if(pceltFetched)
156 *pceltFetched = count;
157 return count == celt ? S_OK : S_FALSE;
158 }
159
160 static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt)
161 {
162 ok(0, "unexpected call\n");
163 return E_NOTIMPL;
164 }
165
166 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
167 {
168 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
169
170 This->cur = 0;
171 return S_OK;
172 }
173
174 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
175 {
176 ok(0, "unexpected call\n");
177 return E_NOTIMPL;
178 }
179
180 static const IEnumFORMATETCVtbl VT_EnumFormatImpl = {
181 EnumFormatImpl_QueryInterface,
182 EnumFormatImpl_AddRef,
183 EnumFormatImpl_Release,
184 EnumFormatImpl_Next,
185 EnumFormatImpl_Skip,
186 EnumFormatImpl_Reset,
187 EnumFormatImpl_Clone
188 };
189
190 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
191 {
192 EnumFormatImpl *ret;
193
194 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl));
195 ret->IEnumFORMATETC_iface.lpVtbl = &VT_EnumFormatImpl;
196 ret->ref = 1;
197 ret->cur = 0;
198 ret->fmtetc_cnt = fmtetc_cnt;
199 ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC));
200 memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
201 *lplpformatetc = &ret->IEnumFORMATETC_iface;
202 return S_OK;
203 }
204
205 static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj)
206 {
207 DataObjectImpl *This = impl_from_IDataObject(iface);
208
209 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) {
210 IDataObject_AddRef(iface);
211 *ppvObj = &This->IDataObject_iface;
212 return S_OK;
213 }
214 *ppvObj = NULL;
215 return E_NOINTERFACE;
216 }
217
218 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
219 {
220 DataObjectImpl *This = impl_from_IDataObject(iface);
221 ULONG ref = InterlockedIncrement(&This->ref);
222 return ref;
223 }
224
225 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
226 {
227 DataObjectImpl *This = impl_from_IDataObject(iface);
228 ULONG ref = InterlockedDecrement(&This->ref);
229
230 if(!ref)
231 {
232 int i;
233 if(This->text) GlobalFree(This->text);
234 for(i = 0; i < This->fmtetc_cnt; i++)
235 HeapFree(GetProcessHeap(), 0, This->fmtetc[i].ptd);
236 HeapFree(GetProcessHeap(), 0, This->fmtetc);
237 if(This->stm) IStream_Release(This->stm);
238 if(This->stg) IStorage_Release(This->stg);
239 HeapFree(GetProcessHeap(), 0, This);
240 }
241
242 return ref;
243 }
244
245 static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
246 {
247 DataObjectImpl *This = impl_from_IDataObject(iface);
248 UINT i;
249 BOOL foundFormat = FALSE;
250
251 trace("getdata: %s\n", dump_fmtetc(pformatetc));
252
253 DataObjectImpl_GetData_calls++;
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 IDataObject_Release(src);
1193
1194 OleUninitialize();
1195 }
1196
1197 static void test_flushed_getdata(void)
1198 {
1199 HRESULT hr;
1200 IDataObject *src, *get;
1201 FORMATETC fmt;
1202 STGMEDIUM med;
1203 STATSTG stat;
1204 DEVMODEW dm;
1205
1206 OleInitialize(NULL);
1207
1208 hr = DataObjectImpl_CreateComplex(&src);
1209 ok(hr == S_OK, "got %08x\n", hr);
1210
1211 hr = OleSetClipboard(src);
1212 ok(hr == S_OK, "got %08x\n", hr);
1213
1214 hr = OleFlushClipboard();
1215 ok(hr == S_OK, "got %08x\n", hr);
1216
1217 hr = OleGetClipboard(&get);
1218 ok(hr == S_OK, "got %08x\n", hr);
1219
1220 /* global format -> global & stream */
1221
1222 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1223 hr = IDataObject_GetData(get, &fmt, &med);
1224 ok(hr == S_OK, "got %08x\n", hr);
1225 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1226 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1227
1228 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTREAM);
1229 hr = IDataObject_GetData(get, &fmt, &med);
1230 ok(hr == S_OK, "got %08x\n", hr);
1231 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1232 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1233
1234 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTORAGE);
1235 hr = IDataObject_GetData(get, &fmt, &med);
1236 ok(hr == E_FAIL, "got %08x\n", hr);
1237 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1238
1239 InitFormatEtc(fmt, CF_TEXT, 0xffff);
1240 hr = IDataObject_GetData(get, &fmt, &med);
1241 ok(hr == S_OK, "got %08x\n", hr);
1242 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1243 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1244
1245 /* stream format -> global & stream */
1246
1247 InitFormatEtc(fmt, cf_stream, TYMED_ISTREAM);
1248 hr = IDataObject_GetData(get, &fmt, &med);
1249 ok(hr == S_OK, "got %08x\n", hr);
1250 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1251 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1252
1253 InitFormatEtc(fmt, cf_stream, TYMED_ISTORAGE);
1254 hr = IDataObject_GetData(get, &fmt, &med);
1255 ok(hr == E_FAIL, "got %08x\n", hr);
1256 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1257
1258 InitFormatEtc(fmt, cf_stream, TYMED_HGLOBAL);
1259 hr = IDataObject_GetData(get, &fmt, &med);
1260 ok(hr == S_OK, "got %08x\n", hr);
1261 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1262 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1263
1264 InitFormatEtc(fmt, cf_stream, 0xffff);
1265 hr = IDataObject_GetData(get, &fmt, &med);
1266 ok(hr == S_OK, "got %08x\n", hr);
1267 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1268 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1269
1270 /* storage format -> global, stream & storage */
1271
1272 InitFormatEtc(fmt, cf_storage, TYMED_ISTORAGE);
1273 hr = IDataObject_GetData(get, &fmt, &med);
1274 ok(hr == S_OK, "got %08x\n", hr);
1275 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1276 if(SUCCEEDED(hr)) {
1277 hr = IStorage_Stat(med.u.pstg, &stat, STATFLAG_NONAME);
1278 ok(hr == S_OK, "got %08x\n", hr);
1279 ok(stat.grfMode == (STGM_SHARE_EXCLUSIVE | STGM_READWRITE), "got %08x\n", stat.grfMode);
1280 ReleaseStgMedium(&med);
1281 }
1282
1283 InitFormatEtc(fmt, cf_storage, TYMED_ISTREAM);
1284 hr = IDataObject_GetData(get, &fmt, &med);
1285 ok(hr == S_OK, "got %08x\n", hr);
1286 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1287 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1288
1289 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL);
1290 hr = IDataObject_GetData(get, &fmt, &med);
1291 ok(hr == S_OK, "got %08x\n", hr);
1292 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1293 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1294
1295 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL | TYMED_ISTREAM);
1296 hr = IDataObject_GetData(get, &fmt, &med);
1297 ok(hr == S_OK, "got %08x\n", hr);
1298 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1299 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1300
1301 InitFormatEtc(fmt, cf_storage, 0xffff);
1302 hr = IDataObject_GetData(get, &fmt, &med);
1303 ok(hr == S_OK, "got %08x\n", hr);
1304 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1305 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1306
1307 /* complex format with target device */
1308
1309 InitFormatEtc(fmt, cf_another, 0xffff);
1310 hr = IDataObject_GetData(get, &fmt, &med);
1311 ok(hr == S_OK, "got %08x\n", hr);
1312 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1313
1314 if (0) /* Causes crashes on both Wine and Windows */
1315 {
1316 InitFormatEtc(fmt, cf_another, 0xffff);
1317 memset(&dm, 0, sizeof(dm));
1318 dm.dmSize = sizeof(dm);
1319 dm.dmDriverExtra = 0;
1320 lstrcpyW(dm.dmDeviceName, device_name);
1321 fmt.ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
1322 fmt.ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
1323 fmt.ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
1324 fmt.ptd->tdDeviceNameOffset = 0;
1325 fmt.ptd->tdPortNameOffset = 0;
1326 fmt.ptd->tdExtDevmodeOffset = fmt.ptd->tdDriverNameOffset + sizeof(device_name);
1327 lstrcpyW((WCHAR*)fmt.ptd->tdData, device_name);
1328 memcpy(fmt.ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
1329
1330 hr = IDataObject_GetData(get, &fmt, &med);
1331 ok(hr == S_OK, "got %08x\n", hr);
1332 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1333 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1334
1335 HeapFree(GetProcessHeap(), 0, fmt.ptd);
1336 }
1337
1338
1339 IDataObject_Release(get);
1340 IDataObject_Release(src);
1341 OleUninitialize();
1342 }
1343
1344 static HGLOBAL create_text(void)
1345 {
1346 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5);
1347 char *p = GlobalLock(h);
1348 strcpy(p, "test");
1349 GlobalUnlock(h);
1350 return h;
1351 }
1352
1353 static HENHMETAFILE create_emf(void)
1354 {
1355 const RECT rect = {0, 0, 100, 100};
1356 HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1357 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
1358 return CloseEnhMetaFile(hdc);
1359 }
1360
1361 static void test_nonole_clipboard(void)
1362 {
1363 HRESULT hr;
1364 BOOL r;
1365 IDataObject *get;
1366 IEnumFORMATETC *enum_fmt;
1367 FORMATETC fmt;
1368 HGLOBAL h, hblob, htext;
1369 HENHMETAFILE emf;
1370 STGMEDIUM med;
1371 DWORD obj_type;
1372
1373 r = OpenClipboard(NULL);
1374 ok(r, "gle %d\n", GetLastError());
1375 r = EmptyClipboard();
1376 ok(r, "gle %d\n", GetLastError());
1377 r = CloseClipboard();
1378 ok(r, "gle %d\n", GetLastError());
1379
1380 OleInitialize(NULL);
1381
1382 /* empty clipboard */
1383 hr = OleGetClipboard(&get);
1384 ok(hr == S_OK, "got %08x\n", hr);
1385 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1386 ok(hr == S_OK, "got %08x\n", hr);
1387
1388 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1389 ok(hr == S_FALSE, "got %08x\n", hr);
1390 IEnumFORMATETC_Release(enum_fmt);
1391
1392 IDataObject_Release(get);
1393
1394 /* set a user defined clipboard type */
1395
1396 htext = create_text();
1397 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
1398 emf = create_emf();
1399
1400 r = OpenClipboard(NULL);
1401 ok(r, "gle %d\n", GetLastError());
1402 h = SetClipboardData(CF_TEXT, htext);
1403 ok(h == htext, "got %p\n", h);
1404 h = SetClipboardData(cf_onemore, hblob);
1405 ok(h == hblob, "got %p\n", h);
1406 h = SetClipboardData(CF_ENHMETAFILE, emf);
1407 ok(h == emf, "got %p\n", h);
1408 r = CloseClipboard();
1409 ok(r, "gle %d\n", GetLastError());
1410
1411 hr = OleGetClipboard(&get);
1412 ok(hr == S_OK, "got %08x\n", hr);
1413 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1414 ok(hr == S_OK, "got %08x\n", hr);
1415
1416 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1417 ok(hr == S_OK, "got %08x\n", hr);
1418 ok(fmt.cfFormat == CF_TEXT, "cf %04x\n", fmt.cfFormat);
1419 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1420 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1421 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1422 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1423
1424 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1425 ok(hr == S_OK, "got %08x\n", hr);
1426 ok(fmt.cfFormat == cf_onemore, "cf %04x\n", fmt.cfFormat);
1427 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1428 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1429 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1430 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1431
1432 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1433 ok(hr == S_OK, "got %08x\n", hr);
1434 ok(fmt.cfFormat == CF_ENHMETAFILE, "cf %04x\n", fmt.cfFormat);
1435 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1436 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1437 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1438 ok(fmt.tymed == TYMED_ENHMF, "tymed %x\n", fmt.tymed);
1439
1440 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1441 ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */
1442
1443 ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
1444 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1445 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1446 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1447 todo_wine ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1448
1449 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1450 ok(hr == S_OK, "got %08x\n", hr);
1451
1452 ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat);
1453 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1454 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1455 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1456 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1457
1458 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1459 ok(hr == S_OK, "got %08x\n", hr);
1460 ok(fmt.cfFormat == CF_UNICODETEXT, "cf %04x\n", fmt.cfFormat);
1461 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1462 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1463 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1464 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1465
1466 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1467 ok(hr == S_OK, "got %08x\n", hr);
1468 ok(fmt.cfFormat == CF_METAFILEPICT, "cf %04x\n", fmt.cfFormat);
1469 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1470 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1471 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1472 ok(fmt.tymed == TYMED_MFPICT, "tymed %x\n", fmt.tymed);
1473
1474 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1475 ok(hr == S_FALSE, "got %08x\n", hr);
1476 IEnumFORMATETC_Release(enum_fmt);
1477
1478 InitFormatEtc(fmt, CF_ENHMETAFILE, TYMED_ENHMF);
1479 hr = IDataObject_GetData(get, &fmt, &med);
1480 ok(hr == S_OK, "got %08x\n", hr);
1481 obj_type = GetObjectType(U(med).hEnhMetaFile);
1482 ok(obj_type == OBJ_ENHMETAFILE, "got %d\n", obj_type);
1483 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1484
1485 IDataObject_Release(get);
1486
1487 r = OpenClipboard(NULL);
1488 ok(r, "gle %d\n", GetLastError());
1489 r = EmptyClipboard();
1490 ok(r, "gle %d\n", GetLastError());
1491 r = CloseClipboard();
1492 ok(r, "gle %d\n", GetLastError());
1493
1494 OleUninitialize();
1495 }
1496
1497 static void test_getdatahere(void)
1498 {
1499 HRESULT hr;
1500 IDataObject *src, *get;
1501 FORMATETC fmt;
1502 STGMEDIUM med;
1503
1504 OleInitialize(NULL);
1505
1506 hr = DataObjectImpl_CreateComplex(&src);
1507 ok(hr == S_OK, "got %08x\n", hr);
1508
1509 hr = OleSetClipboard(src);
1510 ok(hr == S_OK, "got %08x\n", hr);
1511
1512 hr = OleGetClipboard(&get);
1513 ok(hr == S_OK, "got %08x\n", hr);
1514
1515 /* global format -> global & stream */
1516
1517 DataObjectImpl_GetData_calls = 0;
1518 DataObjectImpl_GetDataHere_calls = 0;
1519
1520 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1521
1522 med.pUnkForRelease = NULL;
1523 med.tymed = TYMED_HGLOBAL;
1524 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1525 hr = IDataObject_GetDataHere(get, &fmt, &med);
1526 ok(hr == S_OK, "got %08x\n", hr);
1527 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1528 ReleaseStgMedium(&med);
1529 ok(DataObjectImpl_GetDataHere_calls == 1, "called %d\n", DataObjectImpl_GetDataHere_calls);
1530 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1531
1532 InitFormatEtc(fmt, CF_TEXT, 0);
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 == 2, "called %d\n", DataObjectImpl_GetDataHere_calls);
1542 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1543
1544 med.pUnkForRelease = NULL;
1545 med.tymed = TYMED_HGLOBAL;
1546 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 1);
1547 hr = IDataObject_GetDataHere(get, &fmt, &med);
1548 ok(hr == E_FAIL, "got %08x\n", hr);
1549 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1550 ReleaseStgMedium(&med);
1551 ok(DataObjectImpl_GetDataHere_calls == 3, "called %d\n", DataObjectImpl_GetDataHere_calls);
1552 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1553
1554 med.pUnkForRelease = NULL;
1555 med.tymed = TYMED_ISTREAM;
1556 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1557 hr = IDataObject_GetDataHere(get, &fmt, &med);
1558 ok(hr == S_OK, "got %08x\n", hr);
1559 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1560 ReleaseStgMedium(&med);
1561 ok(DataObjectImpl_GetDataHere_calls == 4, "called %d\n", DataObjectImpl_GetDataHere_calls);
1562 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1563
1564 med.pUnkForRelease = NULL;
1565 med.tymed = TYMED_ISTORAGE;
1566 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1567 hr = IDataObject_GetDataHere(get, &fmt, &med);
1568 ok(hr == E_FAIL, "got %08x\n", hr);
1569 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1570 ReleaseStgMedium(&med);
1571 ok(DataObjectImpl_GetDataHere_calls == 5, "called %d\n", DataObjectImpl_GetDataHere_calls);
1572 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1573
1574 InitFormatEtc(fmt, cf_stream, 0);
1575
1576 med.pUnkForRelease = NULL;
1577 med.tymed = TYMED_HGLOBAL;
1578 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1579 hr = IDataObject_GetDataHere(get, &fmt, &med);
1580 ok(hr == S_OK, "got %08x\n", hr);
1581 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1582 ReleaseStgMedium(&med);
1583 ok(DataObjectImpl_GetDataHere_calls == 7, "called %d\n", DataObjectImpl_GetDataHere_calls);
1584 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1585
1586 med.pUnkForRelease = NULL;
1587 med.tymed = TYMED_ISTREAM;
1588 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1589 hr = IDataObject_GetDataHere(get, &fmt, &med);
1590 ok(hr == S_OK, "got %08x\n", hr);
1591 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1592 ReleaseStgMedium(&med);
1593 ok(DataObjectImpl_GetDataHere_calls == 8, "called %d\n", DataObjectImpl_GetDataHere_calls);
1594 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1595
1596 med.pUnkForRelease = NULL;
1597 med.tymed = TYMED_ISTORAGE;
1598 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1599 hr = IDataObject_GetDataHere(get, &fmt, &med);
1600 ok(hr == E_FAIL, "got %08x\n", hr);
1601 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1602 ReleaseStgMedium(&med);
1603 ok(DataObjectImpl_GetDataHere_calls == 9, "called %d\n", DataObjectImpl_GetDataHere_calls);
1604 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1605
1606 InitFormatEtc(fmt, cf_storage, 0);
1607
1608 med.pUnkForRelease = NULL;
1609 med.tymed = TYMED_HGLOBAL;
1610 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 3000);
1611 hr = IDataObject_GetDataHere(get, &fmt, &med);
1612 ok(hr == S_OK, "got %08x\n", hr);
1613 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1614 ReleaseStgMedium(&med);
1615 ok(DataObjectImpl_GetDataHere_calls == 11, "called %d\n", DataObjectImpl_GetDataHere_calls);
1616 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1617
1618 med.pUnkForRelease = NULL;
1619 med.tymed = TYMED_ISTREAM;
1620 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1621 hr = IDataObject_GetDataHere(get, &fmt, &med);
1622 ok(hr == S_OK, "got %08x\n", hr);
1623 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1624 ReleaseStgMedium(&med);
1625 ok(DataObjectImpl_GetDataHere_calls == 12, "called %d\n", DataObjectImpl_GetDataHere_calls);
1626 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1627
1628 med.pUnkForRelease = NULL;
1629 med.tymed = TYMED_ISTORAGE;
1630 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1631 hr = IDataObject_GetDataHere(get, &fmt, &med);
1632 ok(hr == S_OK, "got %08x\n", hr);
1633 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1634 ReleaseStgMedium(&med);
1635 ok(DataObjectImpl_GetDataHere_calls == 13, "called %d\n", DataObjectImpl_GetDataHere_calls);
1636 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1637
1638
1639 IDataObject_Release(get);
1640 IDataObject_Release(src);
1641
1642 OleUninitialize();
1643
1644 }
1645
1646 static DWORD CALLBACK test_data_obj(void *arg)
1647 {
1648 IDataObject *data_obj = arg;
1649
1650 IDataObject_Release(data_obj);
1651 return 0;
1652 }
1653
1654 static void test_multithreaded_clipboard(void)
1655 {
1656 IDataObject *data_obj;
1657 HANDLE thread;
1658 HRESULT hr;
1659 DWORD ret;
1660
1661 OleInitialize(NULL);
1662
1663 hr = OleGetClipboard(&data_obj);
1664 ok(hr == S_OK, "OleGetClipboard returned %x\n", hr);
1665
1666 thread = CreateThread(NULL, 0, test_data_obj, data_obj, 0, NULL);
1667 ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError());
1668 ret = WaitForSingleObject(thread, 5000);
1669 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret);
1670
1671 hr = OleGetClipboard(&data_obj);
1672 ok(hr == S_OK, "OleGetClipboard returned %x\n", hr);
1673 IDataObject_Release(data_obj);
1674
1675 OleUninitialize();
1676 }
1677
1678 static void test_get_clipboard_locked(void)
1679 {
1680 HRESULT hr;
1681 IDataObject *pDObj;
1682
1683 OleInitialize(NULL);
1684
1685 pDObj = (IDataObject *)0xdeadbeef;
1686 /* lock clipboard */
1687 OpenClipboard(NULL);
1688 hr = OleGetClipboard(&pDObj);
1689 todo_wine ok(hr == CLIPBRD_E_CANT_OPEN, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr, CLIPBRD_E_CANT_OPEN);
1690 todo_wine ok(pDObj == NULL, "OleGetClipboard() got 0x%p instead of NULL\n",pDObj);
1691 if (pDObj) IDataObject_Release(pDObj);
1692 CloseClipboard();
1693
1694 OleUninitialize();
1695 }
1696
1697 START_TEST(clipboard)
1698 {
1699 test_get_clipboard_uninitialized();
1700 test_set_clipboard();
1701 test_set_clipboard_DRAWCLIPBOARD();
1702 test_consumer_refs();
1703 test_flushed_getdata();
1704 test_nonole_clipboard();
1705 test_getdatahere();
1706 test_multithreaded_clipboard();
1707 test_get_clipboard_locked();
1708 }