64fafaf1f29d38cd5004e0a708096dcf68ae667e
[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
22 #include "precomp.h"
23
24 #define InitFormatEtc(fe, cf, med) \
25 {\
26 (fe).cfFormat=cf;\
27 (fe).dwAspect=DVASPECT_CONTENT;\
28 (fe).ptd=NULL;\
29 (fe).tymed=med;\
30 (fe).lindex=-1;\
31 };
32
33 static inline char *dump_fmtetc(FORMATETC *fmt)
34 {
35 static char buf[100];
36
37 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
38 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
39 return buf;
40 }
41
42 typedef struct DataObjectImpl {
43 IDataObject IDataObject_iface;
44 LONG ref;
45
46 FORMATETC *fmtetc;
47 UINT fmtetc_cnt;
48
49 HANDLE text;
50 IStream *stm;
51 IStorage *stg;
52 } DataObjectImpl;
53
54 typedef struct EnumFormatImpl {
55 IEnumFORMATETC IEnumFORMATETC_iface;
56 LONG ref;
57
58 FORMATETC *fmtetc;
59 UINT fmtetc_cnt;
60
61 UINT cur;
62 } EnumFormatImpl;
63
64 static BOOL expect_DataObjectImpl_QueryGetData = TRUE;
65 static ULONG DataObjectImpl_GetData_calls = 0;
66 static ULONG DataObjectImpl_GetDataHere_calls = 0;
67 static ULONG DataObjectImpl_EnumFormatEtc_calls = 0;
68
69 static UINT cf_stream, cf_storage, cf_global, cf_another, cf_onemore;
70
71 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
72
73 static inline DataObjectImpl *impl_from_IDataObject(IDataObject *iface)
74 {
75 return CONTAINING_RECORD(iface, DataObjectImpl, IDataObject_iface);
76 }
77
78 static inline EnumFormatImpl *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
79 {
80 return CONTAINING_RECORD(iface, EnumFormatImpl, IEnumFORMATETC_iface);
81 }
82
83 static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
84 {
85 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
86
87 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) {
88 IEnumFORMATETC_AddRef(iface);
89 *ppvObj = &This->IEnumFORMATETC_iface;
90 return S_OK;
91 }
92 *ppvObj = NULL;
93 return E_NOINTERFACE;
94 }
95
96 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
97 {
98 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
99 LONG ref = InterlockedIncrement(&This->ref);
100 return ref;
101 }
102
103 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
104 {
105 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
106 ULONG ref = InterlockedDecrement(&This->ref);
107
108 if(!ref) {
109 HeapFree(GetProcessHeap(), 0, This->fmtetc);
110 HeapFree(GetProcessHeap(), 0, This);
111 }
112
113 return ref;
114 }
115
116 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
117 FORMATETC *rgelt, ULONG *pceltFetched)
118 {
119 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
120 ULONG count, i;
121
122 if (winetest_debug > 1)
123 trace("next: count %d cur %d\n", celt, This->cur);
124
125 if(!rgelt)
126 return E_INVALIDARG;
127
128 count = min(celt, This->fmtetc_cnt - This->cur);
129 for(i = 0; i < count; i++, This->cur++, rgelt++)
130 {
131 *rgelt = This->fmtetc[This->cur];
132 if(rgelt->ptd)
133 {
134 DWORD size = This->fmtetc[This->cur].ptd->tdSize;
135 rgelt->ptd = CoTaskMemAlloc(size);
136 memcpy(rgelt->ptd, This->fmtetc[This->cur].ptd, size);
137 }
138 }
139 if(pceltFetched)
140 *pceltFetched = count;
141 return count == celt ? S_OK : S_FALSE;
142 }
143
144 static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt)
145 {
146 ok(0, "unexpected call\n");
147 return E_NOTIMPL;
148 }
149
150 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
151 {
152 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
153
154 This->cur = 0;
155 return S_OK;
156 }
157
158 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
159 {
160 ok(0, "unexpected call\n");
161 return E_NOTIMPL;
162 }
163
164 static const IEnumFORMATETCVtbl VT_EnumFormatImpl = {
165 EnumFormatImpl_QueryInterface,
166 EnumFormatImpl_AddRef,
167 EnumFormatImpl_Release,
168 EnumFormatImpl_Next,
169 EnumFormatImpl_Skip,
170 EnumFormatImpl_Reset,
171 EnumFormatImpl_Clone
172 };
173
174 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
175 {
176 EnumFormatImpl *ret;
177
178 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl));
179 ret->IEnumFORMATETC_iface.lpVtbl = &VT_EnumFormatImpl;
180 ret->ref = 1;
181 ret->cur = 0;
182 ret->fmtetc_cnt = fmtetc_cnt;
183 ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC));
184 memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
185 *lplpformatetc = &ret->IEnumFORMATETC_iface;
186 return S_OK;
187 }
188
189 static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj)
190 {
191 DataObjectImpl *This = impl_from_IDataObject(iface);
192
193 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) {
194 IDataObject_AddRef(iface);
195 *ppvObj = &This->IDataObject_iface;
196 return S_OK;
197 }
198 *ppvObj = NULL;
199 return E_NOINTERFACE;
200 }
201
202 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
203 {
204 DataObjectImpl *This = impl_from_IDataObject(iface);
205 ULONG ref = InterlockedIncrement(&This->ref);
206 return ref;
207 }
208
209 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
210 {
211 DataObjectImpl *This = impl_from_IDataObject(iface);
212 ULONG ref = InterlockedDecrement(&This->ref);
213
214 if(!ref)
215 {
216 int i;
217 if(This->text) GlobalFree(This->text);
218 for(i = 0; i < This->fmtetc_cnt; i++)
219 HeapFree(GetProcessHeap(), 0, This->fmtetc[i].ptd);
220 HeapFree(GetProcessHeap(), 0, This->fmtetc);
221 if(This->stm) IStream_Release(This->stm);
222 if(This->stg) IStorage_Release(This->stg);
223 HeapFree(GetProcessHeap(), 0, This);
224 }
225
226 return ref;
227 }
228
229 static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
230 {
231 DataObjectImpl *This = impl_from_IDataObject(iface);
232 UINT i;
233 BOOL foundFormat = FALSE;
234
235 trace("getdata: %s\n", dump_fmtetc(pformatetc));
236
237 DataObjectImpl_GetData_calls++;
238
239 ok(pmedium->tymed == 0, "pmedium->tymed = %u\n", pmedium->tymed);
240 ok(U(*pmedium).hGlobal == NULL, "pmedium->hGlobal = %p\n", U(*pmedium).hGlobal);
241 ok(pmedium->pUnkForRelease == NULL, "pmedium->pUnkForRelease = %p\n", pmedium->pUnkForRelease);
242
243 if(pformatetc->lindex != -1)
244 return DV_E_FORMATETC;
245
246 for(i = 0; i < This->fmtetc_cnt; i++)
247 {
248 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat)
249 {
250 foundFormat = TRUE;
251 if(This->fmtetc[i].tymed & pformatetc->tymed)
252 {
253 pmedium->pUnkForRelease = (LPUNKNOWN)iface;
254 IUnknown_AddRef(pmedium->pUnkForRelease);
255
256 if(pformatetc->cfFormat == CF_TEXT || pformatetc->cfFormat == cf_global)
257 {
258 pmedium->tymed = TYMED_HGLOBAL;
259 U(*pmedium).hGlobal = This->text;
260 }
261 else if(pformatetc->cfFormat == cf_stream)
262 {
263 pmedium->tymed = TYMED_ISTREAM;
264 IStream_AddRef(This->stm);
265 U(*pmedium).pstm = This->stm;
266 }
267 else if(pformatetc->cfFormat == cf_storage || pformatetc->cfFormat == cf_another)
268 {
269 pmedium->tymed = TYMED_ISTORAGE;
270 IStorage_AddRef(This->stg);
271 U(*pmedium).pstg = This->stg;
272 }
273 return S_OK;
274 }
275 }
276 }
277
278 return foundFormat ? DV_E_TYMED : DV_E_FORMATETC;
279 }
280
281 static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
282 {
283 trace("getdatahere: %s\n", dump_fmtetc(pformatetc));
284 DataObjectImpl_GetDataHere_calls++;
285
286 return E_NOTIMPL;
287 }
288
289 static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc)
290 {
291 DataObjectImpl *This = impl_from_IDataObject(iface);
292 UINT i;
293 BOOL foundFormat = FALSE;
294
295 trace("querygetdata: %s\n", dump_fmtetc(pformatetc));
296 if (!expect_DataObjectImpl_QueryGetData)
297 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
298
299 if(pformatetc->lindex != -1)
300 return DV_E_LINDEX;
301
302 for(i=0; i<This->fmtetc_cnt; i++) {
303 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) {
304 foundFormat = TRUE;
305 if(This->fmtetc[i].tymed == pformatetc->tymed)
306 return S_OK;
307 }
308 }
309 return foundFormat?DV_E_FORMATETC:DV_E_TYMED;
310 }
311
312 static HRESULT WINAPI DataObjectImpl_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC *pformatectIn,
313 FORMATETC *pformatetcOut)
314 {
315 ok(0, "unexpected call\n");
316 return E_NOTIMPL;
317 }
318
319 static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc,
320 STGMEDIUM *pmedium, BOOL fRelease)
321 {
322 ok(0, "unexpected call\n");
323 return E_NOTIMPL;
324 }
325
326 static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwDirection,
327 IEnumFORMATETC **ppenumFormatEtc)
328 {
329 DataObjectImpl *This = impl_from_IDataObject(iface);
330
331 DataObjectImpl_EnumFormatEtc_calls++;
332
333 if(dwDirection != DATADIR_GET) {
334 ok(0, "unexpected direction %d\n", dwDirection);
335 return E_NOTIMPL;
336 }
337 return EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenumFormatEtc);
338 }
339
340 static HRESULT WINAPI DataObjectImpl_DAdvise(IDataObject* iface, FORMATETC *pformatetc, DWORD advf,
341 IAdviseSink *pAdvSink, DWORD *pdwConnection)
342 {
343 ok(0, "unexpected call\n");
344 return E_NOTIMPL;
345 }
346
347 static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection)
348 {
349 ok(0, "unexpected call\n");
350 return E_NOTIMPL;
351 }
352
353 static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise)
354 {
355 ok(0, "unexpected call\n");
356 return E_NOTIMPL;
357 }
358
359 static const IDataObjectVtbl VT_DataObjectImpl =
360 {
361 DataObjectImpl_QueryInterface,
362 DataObjectImpl_AddRef,
363 DataObjectImpl_Release,
364 DataObjectImpl_GetData,
365 DataObjectImpl_GetDataHere,
366 DataObjectImpl_QueryGetData,
367 DataObjectImpl_GetCanonicalFormatEtc,
368 DataObjectImpl_SetData,
369 DataObjectImpl_EnumFormatEtc,
370 DataObjectImpl_DAdvise,
371 DataObjectImpl_DUnadvise,
372 DataObjectImpl_EnumDAdvise
373 };
374
375 static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
376 {
377 DataObjectImpl *obj;
378
379 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
380 obj->IDataObject_iface.lpVtbl = &VT_DataObjectImpl;
381 obj->ref = 1;
382 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1);
383 strcpy(GlobalLock(obj->text), text);
384 GlobalUnlock(obj->text);
385 obj->stm = NULL;
386 obj->stg = NULL;
387
388 obj->fmtetc_cnt = 1;
389 obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
390 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
391
392 *lplpdataobj = &obj->IDataObject_iface;
393 return S_OK;
394 }
395
396 static const char *cmpl_stm_data = "complex stream";
397 static const char *cmpl_text_data = "complex text";
398 static const WCHAR device_name[] = {'m','y','d','e','v',0};
399
400 static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj)
401 {
402 DataObjectImpl *obj;
403 ILockBytes *lbs;
404 DEVMODEW dm;
405
406 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
407 obj->IDataObject_iface.lpVtbl = &VT_DataObjectImpl;
408 obj->ref = 1;
409 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(cmpl_text_data) + 1);
410 strcpy(GlobalLock(obj->text), cmpl_text_data);
411 GlobalUnlock(obj->text);
412 CreateStreamOnHGlobal(NULL, TRUE, &obj->stm);
413 IStream_Write(obj->stm, cmpl_stm_data, strlen(cmpl_stm_data), NULL);
414
415 CreateILockBytesOnHGlobal(NULL, TRUE, &lbs);
416 StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &obj->stg);
417 ILockBytes_Release(lbs);
418
419 obj->fmtetc_cnt = 8;
420 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
421 obj->fmtetc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, obj->fmtetc_cnt*sizeof(FORMATETC));
422 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
423 InitFormatEtc(obj->fmtetc[1], cf_stream, TYMED_ISTREAM);
424 InitFormatEtc(obj->fmtetc[2], cf_storage, TYMED_ISTORAGE);
425 InitFormatEtc(obj->fmtetc[3], cf_another, TYMED_ISTORAGE|TYMED_ISTREAM|TYMED_HGLOBAL);
426 if (0) /* Causes crashes on both Wine and Windows */
427 {
428 memset(&dm, 0, sizeof(dm));
429 dm.dmSize = sizeof(dm);
430 dm.dmDriverExtra = 0;
431 lstrcpyW(dm.dmDeviceName, device_name);
432 obj->fmtetc[3].ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
433 obj->fmtetc[3].ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
434 obj->fmtetc[3].ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
435 obj->fmtetc[3].ptd->tdDeviceNameOffset = 0;
436 obj->fmtetc[3].ptd->tdPortNameOffset = 0;
437 obj->fmtetc[3].ptd->tdExtDevmodeOffset = obj->fmtetc[3].ptd->tdDriverNameOffset + sizeof(device_name);
438 lstrcpyW((WCHAR*)obj->fmtetc[3].ptd->tdData, device_name);
439 memcpy(obj->fmtetc[3].ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
440 }
441
442 InitFormatEtc(obj->fmtetc[4], cf_global, TYMED_HGLOBAL);
443 InitFormatEtc(obj->fmtetc[5], cf_another, TYMED_HGLOBAL);
444 InitFormatEtc(obj->fmtetc[6], cf_another, 0xfffff);
445 InitFormatEtc(obj->fmtetc[7], cf_another, 0xfffff);
446 obj->fmtetc[7].dwAspect = DVASPECT_ICON;
447
448 *lplpdataobj = &obj->IDataObject_iface;
449 return S_OK;
450 }
451
452 static void test_get_clipboard_uninitialized(void)
453 {
454 HRESULT hr;
455 IDataObject *pDObj;
456
457 pDObj = (IDataObject *)0xdeadbeef;
458 hr = OleGetClipboard(&pDObj);
459 todo_wine ok(hr == S_OK, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr, S_OK);
460 if (pDObj && pDObj != (IDataObject *)0xdeadbeef) IDataObject_Release(pDObj);
461 }
462
463 static void test_get_clipboard(void)
464 {
465 HRESULT hr;
466 IDataObject *data_obj;
467 FORMATETC fmtetc;
468 STGMEDIUM stgmedium;
469
470 hr = OleGetClipboard(NULL);
471 ok(hr == E_INVALIDARG, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr);
472
473 hr = OleGetClipboard(&data_obj);
474 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
475
476 /* test IDataObject_QueryGetData */
477
478 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
479 expect_DataObjectImpl_QueryGetData = FALSE;
480
481 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
482 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
483 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
484
485 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
486 fmtetc.dwAspect = 0xdeadbeef;
487 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
488 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
489
490 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
491 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
492 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
493 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
494
495 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
496 fmtetc.lindex = 256;
497 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
498 ok(hr == DV_E_FORMATETC || broken(hr == S_OK),
499 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
500
501 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
502 fmtetc.cfFormat = CF_RIFF;
503 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
504 ok(hr == DV_E_CLIPFORMAT, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr);
505
506 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
507 fmtetc.tymed = TYMED_FILE;
508 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
509 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
510
511 expect_DataObjectImpl_QueryGetData = TRUE;
512
513 /* test IDataObject_GetData */
514
515 DataObjectImpl_GetData_calls = 0;
516
517 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
518 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
519 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
520 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
521
522 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
523 fmtetc.dwAspect = 0xdeadbeef;
524 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
525 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
526 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
527
528 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
529 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
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.lindex = 256;
536 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
537 ok(hr == DV_E_FORMATETC || broken(hr == S_OK), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
538 if (hr == S_OK)
539 {
540 /* undo the unexpected success */
541 DataObjectImpl_GetData_calls--;
542 ReleaseStgMedium(&stgmedium);
543 }
544
545 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
546 fmtetc.cfFormat = CF_RIFF;
547 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
548 ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
549 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
550
551 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
552 fmtetc.tymed = TYMED_FILE;
553 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
554 ok(hr == DV_E_TYMED, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr);
555 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
556
557 ok(DataObjectImpl_GetData_calls == 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls);
558
559 IDataObject_Release(data_obj);
560 }
561
562 static void test_enum_fmtetc(IDataObject *src)
563 {
564 HRESULT hr;
565 IDataObject *data;
566 IEnumFORMATETC *enum_fmt, *src_enum;
567 FORMATETC fmt, src_fmt;
568 DWORD count = 0;
569
570 hr = OleGetClipboard(&data);
571 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
572
573 hr = IDataObject_EnumFormatEtc(data, DATADIR_SET, &enum_fmt);
574 ok(hr == E_NOTIMPL ||
575 broken(hr == E_INVALIDARG), /* win98 (not win98SE) */
576 "got %08x\n", hr);
577
578 DataObjectImpl_EnumFormatEtc_calls = 0;
579 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
580 ok(hr == S_OK, "got %08x\n", hr);
581 ok(DataObjectImpl_EnumFormatEtc_calls == 0, "EnumFormatEtc was called\n");
582
583 if(src) IDataObject_EnumFormatEtc(src, DATADIR_GET, &src_enum);
584
585 while((hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL)) == S_OK)
586 {
587 ok(src != NULL, "shouldn't be here\n");
588 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
589 ok(hr == S_OK, "%d: got %08x\n", count, hr);
590 trace("%d: %s\n", count, dump_fmtetc(&fmt));
591 ok(fmt.cfFormat == src_fmt.cfFormat, "%d: %04x %04x\n", count, fmt.cfFormat, src_fmt.cfFormat);
592 ok(fmt.dwAspect == src_fmt.dwAspect, "%d: %08x %08x\n", count, fmt.dwAspect, src_fmt.dwAspect);
593 ok(fmt.lindex == src_fmt.lindex, "%d: %08x %08x\n", count, fmt.lindex, src_fmt.lindex);
594 ok(fmt.tymed == src_fmt.tymed, "%d: %08x %08x\n", count, fmt.tymed, src_fmt.tymed);
595 if(fmt.ptd)
596 {
597 ok(src_fmt.ptd != NULL, "%d: expected non-NULL\n", count);
598 CoTaskMemFree(fmt.ptd);
599 CoTaskMemFree(src_fmt.ptd);
600 }
601 count++;
602 }
603
604 ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
605
606 if(src)
607 {
608 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
609 ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
610 IEnumFORMATETC_Release(src_enum);
611 }
612
613 hr = IEnumFORMATETC_Reset(enum_fmt);
614 ok(hr == S_OK, "got %08x\n", hr);
615
616 if(src) /* Exercise the enumerator a bit */
617 {
618 IEnumFORMATETC *clone;
619 FORMATETC third_fmt;
620
621 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
622 ok(hr == S_OK, "got %08x\n", hr);
623 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
624 ok(hr == S_OK, "got %08x\n", hr);
625 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
626 ok(hr == S_OK, "got %08x\n", hr);
627
628 hr = IEnumFORMATETC_Reset(enum_fmt);
629 ok(hr == S_OK, "got %08x\n", hr);
630 hr = IEnumFORMATETC_Skip(enum_fmt, 2);
631 ok(hr == S_OK, "got %08x\n", hr);
632
633 hr = IEnumFORMATETC_Clone(enum_fmt, &clone);
634 ok(hr == S_OK, "got %08x\n", hr);
635 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
636 ok(hr == S_OK, "got %08x\n", hr);
637 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
638 hr = IEnumFORMATETC_Next(clone, 1, &fmt, NULL);
639 ok(hr == S_OK, "got %08x\n", hr);
640 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
641 IEnumFORMATETC_Release(clone);
642 }
643
644 IEnumFORMATETC_Release(enum_fmt);
645 IDataObject_Release(data);
646 }
647
648 static void test_no_cf_dataobject(void)
649 {
650 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
651 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
652 HANDLE h;
653 OpenClipboard(NULL);
654
655 h = GetClipboardData(cf_dataobject);
656 ok(!h, "got %p\n", h);
657 h = GetClipboardData(cf_ole_priv_data);
658 ok(!h, "got %p\n", h);
659
660 CloseClipboard();
661 }
662
663 static void test_cf_dataobject(IDataObject *data)
664 {
665 UINT cf = 0;
666 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
667 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
668 BOOL found_dataobject = FALSE, found_priv_data = FALSE;
669
670 OpenClipboard(NULL);
671 do
672 {
673 cf = EnumClipboardFormats(cf);
674 if(cf == cf_dataobject)
675 {
676 HGLOBAL h = GetClipboardData(cf);
677 HWND *ptr = GlobalLock(h);
678 DWORD size = GlobalSize(h);
679 HWND clip_owner = GetClipboardOwner();
680
681 found_dataobject = TRUE;
682 ok(size >= sizeof(*ptr), "size %d\n", size);
683 if(data)
684 ok(*ptr == clip_owner, "hwnd %p clip_owner %p\n", *ptr, clip_owner);
685 else /* ole clipboard flushed */
686 ok(*ptr == NULL, "hwnd %p\n", *ptr);
687 GlobalUnlock(h);
688 }
689 else if(cf == cf_ole_priv_data)
690 {
691 found_priv_data = TRUE;
692 if(data)
693 {
694 HGLOBAL h = GetClipboardData(cf);
695 DWORD *ptr = GlobalLock(h);
696 DWORD size = GlobalSize(h);
697
698 if(size != ptr[1])
699 win_skip("Ole Private Data in win9x format\n");
700 else
701 {
702 HRESULT hr;
703 IEnumFORMATETC *enum_fmt;
704 DWORD count = 0;
705 FORMATETC fmt;
706 struct formatetcetc
707 {
708 FORMATETC fmt;
709 BOOL first_use_of_cf;
710 DWORD res[2];
711 } *fmt_ptr;
712 struct priv_data
713 {
714 DWORD res1;
715 DWORD size;
716 DWORD res2;
717 DWORD count;
718 DWORD res3[2];
719 struct formatetcetc fmts[1];
720 } *priv = (struct priv_data*)ptr;
721 CLIPFORMAT cfs_seen[10];
722
723 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
724 ok(hr == S_OK, "got %08x\n", hr);
725 fmt_ptr = priv->fmts;
726
727 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
728 {
729 int i;
730 BOOL seen_cf = FALSE;
731
732 ok(fmt_ptr->fmt.cfFormat == fmt.cfFormat,
733 "got %08x expected %08x\n", fmt_ptr->fmt.cfFormat, fmt.cfFormat);
734 ok(fmt_ptr->fmt.dwAspect == fmt.dwAspect, "got %08x expected %08x\n",
735 fmt_ptr->fmt.dwAspect, fmt.dwAspect);
736 ok(fmt_ptr->fmt.lindex == fmt.lindex, "got %08x expected %08x\n",
737 fmt_ptr->fmt.lindex, fmt.lindex);
738 ok(fmt_ptr->fmt.tymed == fmt.tymed, "got %08x expected %08x\n",
739 fmt_ptr->fmt.tymed, fmt.tymed);
740 for(i = 0; i < count; i++)
741 if(fmt_ptr->fmt.cfFormat == cfs_seen[i])
742 {
743 seen_cf = TRUE;
744 break;
745 }
746 cfs_seen[count] = fmt.cfFormat;
747 ok(fmt_ptr->first_use_of_cf != seen_cf, "got %08x expected %08x\n",
748 fmt_ptr->first_use_of_cf, !seen_cf);
749 ok(fmt_ptr->res[0] == 0, "got %08x\n", fmt_ptr->res[0]);
750 ok(fmt_ptr->res[1] == 0, "got %08x\n", fmt_ptr->res[1]);
751 if(fmt.ptd)
752 {
753 DVTARGETDEVICE *target;
754
755 ok(fmt_ptr->fmt.ptd != NULL, "target device offset zero\n");
756 target = (DVTARGETDEVICE*)((char*)priv + (DWORD_PTR)fmt_ptr->fmt.ptd);
757 ok(!memcmp(target, fmt.ptd, fmt.ptd->tdSize), "target devices differ\n");
758 CoTaskMemFree(fmt.ptd);
759 }
760 fmt_ptr++;
761 count++;
762 }
763 ok(priv->res1 == 0, "got %08x\n", priv->res1);
764 ok(priv->res2 == 1, "got %08x\n", priv->res2);
765 ok(priv->count == count, "got %08x expected %08x\n", priv->count, count);
766 ok(priv->res3[0] == 0, "got %08x\n", priv->res3[0]);
767
768 /* win64 sets the lsb */
769 if(sizeof(fmt_ptr->fmt.ptd) == 8)
770 todo_wine ok(priv->res3[1] == 1, "got %08x\n", priv->res3[1]);
771 else
772 ok(priv->res3[1] == 0, "got %08x\n", priv->res3[1]);
773
774 GlobalUnlock(h);
775 IEnumFORMATETC_Release(enum_fmt);
776 }
777 }
778 }
779 else if(cf == cf_stream)
780 {
781 HGLOBAL h;
782 void *ptr;
783 DWORD size;
784
785 DataObjectImpl_GetDataHere_calls = 0;
786 h = GetClipboardData(cf);
787 ok(DataObjectImpl_GetDataHere_calls == 1, "got %d\n", DataObjectImpl_GetDataHere_calls);
788 ptr = GlobalLock(h);
789 size = GlobalSize(h);
790 ok(size == strlen(cmpl_stm_data),
791 "expected %d got %d\n", lstrlenA(cmpl_stm_data), size);
792 ok(!memcmp(ptr, cmpl_stm_data, strlen(cmpl_stm_data)), "mismatch\n");
793 GlobalUnlock(h);
794 }
795 else if(cf == cf_global)
796 {
797 HGLOBAL h;
798 void *ptr;
799 DWORD size;
800
801 DataObjectImpl_GetDataHere_calls = 0;
802 h = GetClipboardData(cf);
803 ok(DataObjectImpl_GetDataHere_calls == 0, "got %d\n", DataObjectImpl_GetDataHere_calls);
804 ptr = GlobalLock(h);
805 size = GlobalSize(h);
806 ok(size == strlen(cmpl_text_data) + 1,
807 "expected %d got %d\n", lstrlenA(cmpl_text_data) + 1, size);
808 ok(!memcmp(ptr, cmpl_text_data, strlen(cmpl_text_data) + 1), "mismatch\n");
809 GlobalUnlock(h);
810 }
811 } while(cf);
812 CloseClipboard();
813 ok(found_dataobject, "didn't find cf_dataobject\n");
814 ok(found_priv_data, "didn't find cf_ole_priv_data\n");
815 }
816
817 static void test_set_clipboard(void)
818 {
819 HRESULT hr;
820 ULONG ref;
821 LPDATAOBJECT data1, data2, data_cmpl;
822 HGLOBAL hblob, h;
823 void *ptr;
824
825 cf_stream = RegisterClipboardFormatA("stream format");
826 cf_storage = RegisterClipboardFormatA("storage format");
827 cf_global = RegisterClipboardFormatA("global format");
828 cf_another = RegisterClipboardFormatA("another format");
829 cf_onemore = RegisterClipboardFormatA("one more format");
830
831 hr = DataObjectImpl_CreateText("data1", &data1);
832 ok(hr == S_OK, "Failed to create data1 object: 0x%08x\n", hr);
833 if(FAILED(hr))
834 return;
835 hr = DataObjectImpl_CreateText("data2", &data2);
836 ok(hr == S_OK, "Failed to create data2 object: 0x%08x\n", hr);
837 if(FAILED(hr))
838 return;
839 hr = DataObjectImpl_CreateComplex(&data_cmpl);
840 ok(hr == S_OK, "Failed to create complex data object: 0x%08x\n", hr);
841 if(FAILED(hr))
842 return;
843
844 hr = OleSetClipboard(data1);
845 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
846
847 CoInitialize(NULL);
848 hr = OleSetClipboard(data1);
849 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard failed with 0x%08x\n", hr);
850 CoUninitialize();
851
852 hr = OleInitialize(NULL);
853 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
854
855 hr = OleSetClipboard(data1);
856 ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr);
857
858 test_cf_dataobject(data1);
859
860 hr = OleIsCurrentClipboard(data1);
861 ok(hr == S_OK, "expected current clipboard to be data1, hr = 0x%08x\n", hr);
862 hr = OleIsCurrentClipboard(data2);
863 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
864 hr = OleIsCurrentClipboard(NULL);
865 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
866
867 test_get_clipboard();
868
869 hr = OleSetClipboard(data2);
870 ok(hr == S_OK, "failed to set clipboard to data2, hr = 0x%08x\n", hr);
871 hr = OleIsCurrentClipboard(data1);
872 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
873 hr = OleIsCurrentClipboard(data2);
874 ok(hr == S_OK, "expected current clipboard to be data2, hr = 0x%08x\n", hr);
875 hr = OleIsCurrentClipboard(NULL);
876 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
877
878 /* put a format directly onto the clipboard to show
879 OleFlushClipboard doesn't empty the clipboard */
880 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
881 ptr = GlobalLock( hblob );
882 ok( ptr && ptr != hblob, "got fixed block %p / %p\n", ptr, hblob );
883 GlobalUnlock( hblob );
884 ok( OpenClipboard(NULL), "OpenClipboard failed\n" );
885 h = SetClipboardData(cf_onemore, hblob);
886 ok(h == hblob, "got %p\n", h);
887 h = GetClipboardData(cf_onemore);
888 ok(h == hblob, "got %p / %p\n", h, hblob);
889 ptr = GlobalLock( h );
890 ok( ptr && ptr != h, "got fixed block %p / %p\n", ptr, h );
891 GlobalUnlock( hblob );
892 ok( CloseClipboard(), "CloseClipboard failed\n" );
893
894 hr = OleFlushClipboard();
895 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
896 hr = OleIsCurrentClipboard(data1);
897 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
898 hr = OleIsCurrentClipboard(data2);
899 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
900 hr = OleIsCurrentClipboard(NULL);
901 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
902
903 /* format should survive the flush */
904 ok( OpenClipboard(NULL), "OpenClipboard failed\n" );
905 h = GetClipboardData(cf_onemore);
906 ok(h == hblob, "got %p\n", h);
907 ptr = GlobalLock( h );
908 ok( ptr && ptr != h, "got fixed block %p / %p\n", ptr, h );
909 GlobalUnlock( hblob );
910 ok( CloseClipboard(), "CloseClipboard failed\n" );
911
912 test_cf_dataobject(NULL);
913
914 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
915
916 OpenClipboard(NULL);
917 h = GetClipboardData(cf_onemore);
918 ok(h == NULL, "got %p\n", h);
919 CloseClipboard();
920
921 trace("setting complex\n");
922 hr = OleSetClipboard(data_cmpl);
923 ok(hr == S_OK, "failed to set clipboard to complex data, hr = 0x%08x\n", hr);
924 test_cf_dataobject(data_cmpl);
925 test_enum_fmtetc(data_cmpl);
926
927 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
928
929 test_no_cf_dataobject();
930 test_enum_fmtetc(NULL);
931
932 ref = IDataObject_Release(data1);
933 ok(ref == 0, "expected data1 ref=0, got %d\n", ref);
934 ref = IDataObject_Release(data2);
935 ok(ref == 0, "expected data2 ref=0, got %d\n", ref);
936 ref = IDataObject_Release(data_cmpl);
937 ok(ref == 0, "expected data_cmpl ref=0, got %d\n", ref);
938
939 OleUninitialize();
940 }
941
942 static LPDATAOBJECT clip_data;
943 static HWND next_wnd;
944 static UINT wm_drawclipboard;
945
946 static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
947 {
948 LRESULT ret;
949
950 switch (msg)
951 {
952 case WM_DRAWCLIPBOARD:
953 wm_drawclipboard++;
954 if (clip_data)
955 {
956 /* if this is the WM_DRAWCLIPBOARD of a previous change, the data isn't current yet */
957 /* this demonstrates an issue in Qt where it will free the data while it's being set */
958 HRESULT hr = OleIsCurrentClipboard( clip_data );
959 ok( hr == (wm_drawclipboard > 1) ? S_OK : S_FALSE,
960 "OleIsCurrentClipboard returned %x\n", hr );
961 }
962 break;
963 case WM_CHANGECBCHAIN:
964 if (next_wnd == (HWND)wp) next_wnd = (HWND)lp;
965 else if (next_wnd) SendMessageA( next_wnd, msg, wp, lp );
966 break;
967 case WM_USER:
968 ret = wm_drawclipboard;
969 wm_drawclipboard = 0;
970 return ret;
971 }
972
973 return DefWindowProcA(hwnd, msg, wp, lp);
974 }
975
976 static DWORD CALLBACK set_clipboard_thread(void *arg)
977 {
978 OpenClipboard( GetDesktopWindow() );
979 EmptyClipboard();
980 SetClipboardData( CF_WAVE, 0 );
981 CloseClipboard();
982 return 0;
983 }
984
985 /* test that WM_DRAWCLIPBOARD can be delivered for a previous change during OleSetClipboard */
986 static void test_set_clipboard_DRAWCLIPBOARD(void)
987 {
988 LPDATAOBJECT data;
989 HRESULT hr;
990 WNDCLASSA cls;
991 HWND viewer;
992 int ret;
993 HANDLE thread;
994
995 hr = DataObjectImpl_CreateText("data", &data);
996 ok(hr == S_OK, "Failed to create data object: 0x%08x\n", hr);
997
998 memset(&cls, 0, sizeof(cls));
999 cls.lpfnWndProc = clipboard_wnd_proc;
1000 cls.hInstance = GetModuleHandleA(NULL);
1001 cls.lpszClassName = "clipboard_test";
1002 RegisterClassA(&cls);
1003
1004 viewer = CreateWindowA("clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0);
1005 ok(viewer != NULL, "CreateWindow failed: %d\n", GetLastError());
1006 next_wnd = SetClipboardViewer( viewer );
1007
1008 ret = SendMessageA( viewer, WM_USER, 0, 0 );
1009 ok( ret == 1, "%u WM_DRAWCLIPBOARD received\n", ret );
1010
1011 hr = OleInitialize(NULL);
1012 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
1013
1014 ret = SendMessageA( viewer, WM_USER, 0, 0 );
1015 ok( !ret, "%u WM_DRAWCLIPBOARD received\n", ret );
1016
1017 thread = CreateThread(NULL, 0, set_clipboard_thread, NULL, 0, NULL);
1018 ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError());
1019 ret = WaitForSingleObject(thread, 5000);
1020 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret);
1021
1022 clip_data = data;
1023 hr = OleSetClipboard(data);
1024 ok(hr == S_OK, "failed to set clipboard to data, hr = 0x%08x\n", hr);
1025
1026 ret = SendMessageA( viewer, WM_USER, 0, 0 );
1027 ok( ret == 2, "%u WM_DRAWCLIPBOARD received\n", ret );
1028
1029 clip_data = NULL;
1030 hr = OleFlushClipboard();
1031 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
1032 ret = IDataObject_Release(data);
1033 ok(ret == 0, "got %d\n", ret);
1034
1035 OleUninitialize();
1036 ChangeClipboardChain( viewer, next_wnd );
1037 DestroyWindow( viewer );
1038 }
1039
1040 static inline ULONG count_refs(IDataObject *d)
1041 {
1042 IDataObject_AddRef(d);
1043 return IDataObject_Release(d);
1044 }
1045
1046 static void test_consumer_refs(void)
1047 {
1048 HRESULT hr;
1049 IDataObject *src, *src2, *get1, *get2, *get3;
1050 ULONG refs, old_refs;
1051 FORMATETC fmt;
1052 STGMEDIUM med;
1053
1054 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1055
1056 OleInitialize(NULL);
1057
1058 /* First show that each clipboard state results in
1059 a different data object */
1060
1061 hr = DataObjectImpl_CreateText("data1", &src);
1062 ok(hr == S_OK, "got %08x\n", hr);
1063 hr = DataObjectImpl_CreateText("data2", &src2);
1064 ok(hr == S_OK, "got %08x\n", hr);
1065
1066 hr = OleSetClipboard(src);
1067 ok(hr == S_OK, "got %08x\n", hr);
1068
1069 hr = OleGetClipboard(&get1);
1070 ok(hr == S_OK, "got %08x\n", hr);
1071
1072 hr = OleGetClipboard(&get2);
1073 ok(hr == S_OK, "got %08x\n", hr);
1074
1075 ok(get1 == get2, "data objects differ\n");
1076 refs = IDataObject_Release(get2);
1077 ok(refs == (get1 == get2 ? 1 : 0), "got %d\n", refs);
1078
1079 OleFlushClipboard();
1080
1081 DataObjectImpl_GetData_calls = 0;
1082 hr = IDataObject_GetData(get1, &fmt, &med);
1083 ok(hr == S_OK, "got %08x\n", hr);
1084 ok(DataObjectImpl_GetData_calls == 0, "GetData called\n");
1085 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1086
1087 hr = OleGetClipboard(&get2);
1088 ok(hr == S_OK, "got %08x\n", hr);
1089
1090 ok(get1 != get2, "data objects match\n");
1091
1092 OleSetClipboard(NULL);
1093
1094 hr = OleGetClipboard(&get3);
1095 ok(hr == S_OK, "got %08x\n", hr);
1096
1097 ok(get1 != get3, "data objects match\n");
1098 ok(get2 != get3, "data objects match\n");
1099
1100 IDataObject_Release(get3);
1101 IDataObject_Release(get2);
1102 IDataObject_Release(get1);
1103
1104 /* Now call GetData before the flush and show that this
1105 takes a ref on our src data obj. */
1106
1107 hr = OleSetClipboard(src);
1108 ok(hr == S_OK, "got %08x\n", hr);
1109
1110 old_refs = count_refs(src);
1111
1112 hr = OleGetClipboard(&get1);
1113 ok(hr == S_OK, "got %08x\n", hr);
1114
1115 refs = count_refs(src);
1116 ok(refs == old_refs, "%d %d\n", refs, old_refs);
1117
1118 DataObjectImpl_GetData_calls = 0;
1119 hr = IDataObject_GetData(get1, &fmt, &med);
1120 ok(hr == S_OK, "got %08x\n", hr);
1121 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1122 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1123 refs = count_refs(src);
1124 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1125
1126 OleFlushClipboard();
1127
1128 DataObjectImpl_GetData_calls = 0;
1129 hr = IDataObject_GetData(get1, &fmt, &med);
1130 ok(hr == S_OK, "got %08x\n", hr);
1131 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1132 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1133
1134 refs = count_refs(src);
1135 ok(refs == 2, "%d\n", refs);
1136
1137 IDataObject_Release(get1);
1138
1139 refs = count_refs(src);
1140 ok(refs == 1, "%d\n", refs);
1141
1142 /* Now set a second src object before the call to GetData
1143 and show that GetData calls that second src. */
1144
1145 hr = OleSetClipboard(src);
1146 ok(hr == S_OK, "got %08x\n", hr);
1147
1148 old_refs = count_refs(src);
1149
1150 hr = OleGetClipboard(&get1);
1151 ok(hr == S_OK, "got %08x\n", hr);
1152
1153 refs = count_refs(src);
1154 ok(refs == old_refs, "%d %d\n", refs, old_refs);
1155
1156 hr = OleSetClipboard(src2);
1157 ok(hr == S_OK, "got %08x\n", hr);
1158
1159 old_refs = count_refs(src2);
1160
1161 DataObjectImpl_GetData_calls = 0;
1162 hr = IDataObject_GetData(get1, &fmt, &med);
1163 ok(hr == S_OK, "got %08x\n", hr);
1164 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1165 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1166
1167 refs = count_refs(src);
1168 ok(refs == 1, "%d\n", refs);
1169 refs = count_refs(src2);
1170 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1171
1172 OleSetClipboard(NULL);
1173
1174 refs = count_refs(src2);
1175 ok(refs == 2, "%d\n", refs);
1176
1177 IDataObject_Release(get1);
1178
1179 IDataObject_Release(src2);
1180
1181 /* Show that OleUninitialize() doesn't release the
1182 dataobject's ref, and thus the object is leaked. */
1183 old_refs = count_refs(src);
1184 ok(old_refs == 1, "%d\n", old_refs);
1185
1186 OleSetClipboard(src);
1187 refs = count_refs(src);
1188 ok(refs > old_refs, "%d %d\n", refs, old_refs);
1189
1190 OleUninitialize();
1191 refs = count_refs(src);
1192 ok(refs == 2, "%d\n", refs);
1193
1194 IDataObject_Release(src);
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.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 }