167fa99fbd4a1a9c80ccf059eb673d78fcbba5cb
[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 = (LPENUMFORMATETC)ret;
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 = (LPDATAOBJECT)obj;
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 = (LPDATAOBJECT)obj;
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 ||
622 broken(hr == S_OK && count == 5), /* win9x and winme don't enumerate duplicated cf's */
623 "%d: got %08x\n", count, hr);
624 IEnumFORMATETC_Release(src_enum);
625 }
626
627 hr = IEnumFORMATETC_Reset(enum_fmt);
628 ok(hr == S_OK, "got %08x\n", hr);
629
630 if(src) /* Exercise the enumerator a bit */
631 {
632 IEnumFORMATETC *clone;
633 FORMATETC third_fmt;
634
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 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
640 ok(hr == S_OK, "got %08x\n", hr);
641
642 hr = IEnumFORMATETC_Reset(enum_fmt);
643 ok(hr == S_OK, "got %08x\n", hr);
644 hr = IEnumFORMATETC_Skip(enum_fmt, 2);
645 ok(hr == S_OK, "got %08x\n", hr);
646
647 hr = IEnumFORMATETC_Clone(enum_fmt, &clone);
648 ok(hr == S_OK, "got %08x\n", hr);
649 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
650 ok(hr == S_OK, "got %08x\n", hr);
651 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
652 hr = IEnumFORMATETC_Next(clone, 1, &fmt, NULL);
653 ok(hr == S_OK, "got %08x\n", hr);
654 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
655 IEnumFORMATETC_Release(clone);
656 }
657
658 IEnumFORMATETC_Release(enum_fmt);
659 IDataObject_Release(data);
660 }
661
662 static void test_no_cf_dataobject(void)
663 {
664 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
665 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
666 HANDLE h;
667 OpenClipboard(NULL);
668
669 h = GetClipboardData(cf_dataobject);
670 ok(!h, "got %p\n", h);
671 h = GetClipboardData(cf_ole_priv_data);
672 ok(!h, "got %p\n", h);
673
674 CloseClipboard();
675 }
676
677 static void test_cf_dataobject(IDataObject *data)
678 {
679 UINT cf = 0;
680 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
681 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
682 BOOL found_dataobject = FALSE, found_priv_data = FALSE;
683
684 OpenClipboard(NULL);
685 do
686 {
687 cf = EnumClipboardFormats(cf);
688 if(cf == cf_dataobject)
689 {
690 HGLOBAL h = GetClipboardData(cf);
691 HWND *ptr = GlobalLock(h);
692 DWORD size = GlobalSize(h);
693 HWND clip_owner = GetClipboardOwner();
694
695 found_dataobject = TRUE;
696 ok(size >= sizeof(*ptr), "size %d\n", size);
697 if(data)
698 ok(*ptr == clip_owner, "hwnd %p clip_owner %p\n", *ptr, clip_owner);
699 else /* ole clipboard flushed */
700 ok(*ptr == NULL, "hwnd %p\n", *ptr);
701 GlobalUnlock(h);
702 }
703 else if(cf == cf_ole_priv_data)
704 {
705 found_priv_data = TRUE;
706 if(data)
707 {
708 HGLOBAL h = GetClipboardData(cf);
709 DWORD *ptr = GlobalLock(h);
710 DWORD size = GlobalSize(h);
711
712 if(size != ptr[1])
713 win_skip("Ole Private Data in win9x format\n");
714 else
715 {
716 HRESULT hr;
717 IEnumFORMATETC *enum_fmt;
718 DWORD count = 0;
719 FORMATETC fmt;
720 struct formatetcetc
721 {
722 FORMATETC fmt;
723 BOOL first_use_of_cf;
724 DWORD res[2];
725 } *fmt_ptr;
726 struct priv_data
727 {
728 DWORD res1;
729 DWORD size;
730 DWORD res2;
731 DWORD count;
732 DWORD res3[2];
733 struct formatetcetc fmts[1];
734 } *priv = (struct priv_data*)ptr;
735 CLIPFORMAT cfs_seen[10];
736
737 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
738 ok(hr == S_OK, "got %08x\n", hr);
739 fmt_ptr = priv->fmts;
740
741 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
742 {
743 int i;
744 BOOL seen_cf = FALSE;
745
746 ok(fmt_ptr->fmt.cfFormat == fmt.cfFormat,
747 "got %08x expected %08x\n", fmt_ptr->fmt.cfFormat, fmt.cfFormat);
748 ok(fmt_ptr->fmt.dwAspect == fmt.dwAspect, "got %08x expected %08x\n",
749 fmt_ptr->fmt.dwAspect, fmt.dwAspect);
750 ok(fmt_ptr->fmt.lindex == fmt.lindex, "got %08x expected %08x\n",
751 fmt_ptr->fmt.lindex, fmt.lindex);
752 ok(fmt_ptr->fmt.tymed == fmt.tymed, "got %08x expected %08x\n",
753 fmt_ptr->fmt.tymed, fmt.tymed);
754 for(i = 0; i < count; i++)
755 if(fmt_ptr->fmt.cfFormat == cfs_seen[i])
756 {
757 seen_cf = TRUE;
758 break;
759 }
760 cfs_seen[count] = fmt.cfFormat;
761 ok(fmt_ptr->first_use_of_cf != seen_cf, "got %08x expected %08x\n",
762 fmt_ptr->first_use_of_cf, !seen_cf);
763 ok(fmt_ptr->res[0] == 0, "got %08x\n", fmt_ptr->res[0]);
764 ok(fmt_ptr->res[1] == 0, "got %08x\n", fmt_ptr->res[1]);
765 if(fmt.ptd)
766 {
767 DVTARGETDEVICE *target;
768
769 ok(fmt_ptr->fmt.ptd != NULL, "target device offset zero\n");
770 target = (DVTARGETDEVICE*)((char*)priv + (DWORD_PTR)fmt_ptr->fmt.ptd);
771 ok(!memcmp(target, fmt.ptd, fmt.ptd->tdSize), "target devices differ\n");
772 CoTaskMemFree(fmt.ptd);
773 }
774 fmt_ptr++;
775 count++;
776 }
777 ok(priv->res1 == 0, "got %08x\n", priv->res1);
778 ok(priv->res2 == 1, "got %08x\n", priv->res2);
779 ok(priv->count == count, "got %08x expected %08x\n", priv->count, count);
780 ok(priv->res3[0] == 0, "got %08x\n", priv->res3[0]);
781
782 /* win64 sets the lsb */
783 if(sizeof(fmt_ptr->fmt.ptd) == 8)
784 todo_wine ok(priv->res3[1] == 1, "got %08x\n", priv->res3[1]);
785 else
786 ok(priv->res3[1] == 0, "got %08x\n", priv->res3[1]);
787
788 GlobalUnlock(h);
789 IEnumFORMATETC_Release(enum_fmt);
790 }
791 }
792 }
793 else if(cf == cf_stream)
794 {
795 HGLOBAL h;
796 void *ptr;
797 DWORD size;
798
799 DataObjectImpl_GetDataHere_calls = 0;
800 h = GetClipboardData(cf);
801 ok(DataObjectImpl_GetDataHere_calls == 1, "got %d\n", DataObjectImpl_GetDataHere_calls);
802 ptr = GlobalLock(h);
803 size = GlobalSize(h);
804 ok(size == strlen(cmpl_stm_data) ||
805 broken(size > strlen(cmpl_stm_data)), /* win9x, winme */
806 "expected %d got %d\n", lstrlenA(cmpl_stm_data), size);
807 ok(!memcmp(ptr, cmpl_stm_data, strlen(cmpl_stm_data)), "mismatch\n");
808 GlobalUnlock(h);
809 }
810 else if(cf == cf_global)
811 {
812 HGLOBAL h;
813 void *ptr;
814 DWORD size;
815
816 DataObjectImpl_GetDataHere_calls = 0;
817 h = GetClipboardData(cf);
818 ok(DataObjectImpl_GetDataHere_calls == 0, "got %d\n", DataObjectImpl_GetDataHere_calls);
819 ptr = GlobalLock(h);
820 size = GlobalSize(h);
821 ok(size == strlen(cmpl_text_data) + 1 ||
822 broken(size > strlen(cmpl_text_data) + 1), /* win9x, winme */
823 "expected %d got %d\n", lstrlenA(cmpl_text_data) + 1, size);
824 ok(!memcmp(ptr, cmpl_text_data, strlen(cmpl_text_data) + 1), "mismatch\n");
825 GlobalUnlock(h);
826 }
827 } while(cf);
828 CloseClipboard();
829 ok(found_dataobject, "didn't find cf_dataobject\n");
830 ok(found_priv_data, "didn't find cf_ole_priv_data\n");
831 }
832
833 static void test_set_clipboard(void)
834 {
835 HRESULT hr;
836 ULONG ref;
837 LPDATAOBJECT data1, data2, data_cmpl;
838 HGLOBAL hblob, h;
839
840 cf_stream = RegisterClipboardFormatA("stream format");
841 cf_storage = RegisterClipboardFormatA("storage format");
842 cf_global = RegisterClipboardFormatA("global format");
843 cf_another = RegisterClipboardFormatA("another format");
844 cf_onemore = RegisterClipboardFormatA("one more format");
845
846 hr = DataObjectImpl_CreateText("data1", &data1);
847 ok(hr == S_OK, "Failed to create data1 object: 0x%08x\n", hr);
848 if(FAILED(hr))
849 return;
850 hr = DataObjectImpl_CreateText("data2", &data2);
851 ok(hr == S_OK, "Failed to create data2 object: 0x%08x\n", hr);
852 if(FAILED(hr))
853 return;
854 hr = DataObjectImpl_CreateComplex(&data_cmpl);
855 ok(hr == S_OK, "Failed to create complex data object: 0x%08x\n", hr);
856 if(FAILED(hr))
857 return;
858
859 hr = OleSetClipboard(data1);
860 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
861
862 CoInitialize(NULL);
863 hr = OleSetClipboard(data1);
864 ok(hr == CO_E_NOTINITIALIZED ||
865 hr == CLIPBRD_E_CANT_SET, /* win9x */
866 "OleSetClipboard should have failed with "
867 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr);
868 CoUninitialize();
869
870 hr = OleInitialize(NULL);
871 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
872
873 hr = OleSetClipboard(data1);
874 ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr);
875
876 test_cf_dataobject(data1);
877
878 hr = OleIsCurrentClipboard(data1);
879 ok(hr == S_OK, "expected current clipboard to be data1, hr = 0x%08x\n", hr);
880 hr = OleIsCurrentClipboard(data2);
881 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
882 hr = OleIsCurrentClipboard(NULL);
883 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
884
885 test_get_clipboard();
886
887 hr = OleSetClipboard(data2);
888 ok(hr == S_OK, "failed to set clipboard to data2, hr = 0x%08x\n", hr);
889 hr = OleIsCurrentClipboard(data1);
890 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
891 hr = OleIsCurrentClipboard(data2);
892 ok(hr == S_OK, "expected current clipboard to be data2, hr = 0x%08x\n", hr);
893 hr = OleIsCurrentClipboard(NULL);
894 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
895
896 /* put a format directly onto the clipboard to show
897 OleFlushClipboard doesn't empty the clipboard */
898 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
899 OpenClipboard(NULL);
900 h = SetClipboardData(cf_onemore, hblob);
901 ok(h == hblob, "got %p\n", h);
902 h = GetClipboardData(cf_onemore);
903 ok(h == hblob ||
904 broken(h != NULL), /* win9x */
905 "got %p\n", h);
906 CloseClipboard();
907
908 hr = OleFlushClipboard();
909 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
910 hr = OleIsCurrentClipboard(data1);
911 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
912 hr = OleIsCurrentClipboard(data2);
913 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
914 hr = OleIsCurrentClipboard(NULL);
915 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
916
917 /* format should survive the flush */
918 OpenClipboard(NULL);
919 h = GetClipboardData(cf_onemore);
920 ok(h == hblob ||
921 broken(h != NULL), /* win9x */
922 "got %p\n", h);
923 CloseClipboard();
924
925 test_cf_dataobject(NULL);
926
927 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
928
929 OpenClipboard(NULL);
930 h = GetClipboardData(cf_onemore);
931 ok(h == NULL, "got %p\n", h);
932 CloseClipboard();
933
934 trace("setting complex\n");
935 hr = OleSetClipboard(data_cmpl);
936 ok(hr == S_OK, "failed to set clipboard to complex data, hr = 0x%08x\n", hr);
937 test_cf_dataobject(data_cmpl);
938 test_enum_fmtetc(data_cmpl);
939
940 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
941
942 test_no_cf_dataobject();
943 test_enum_fmtetc(NULL);
944
945 ref = IDataObject_Release(data1);
946 ok(ref == 0, "expected data1 ref=0, got %d\n", ref);
947 ref = IDataObject_Release(data2);
948 ok(ref == 0, "expected data2 ref=0, got %d\n", ref);
949 ref = IDataObject_Release(data_cmpl);
950 ok(ref == 0, "expected data_cmpl ref=0, got %d\n", ref);
951
952 OleUninitialize();
953 }
954
955 static inline ULONG count_refs(IDataObject *d)
956 {
957 IDataObject_AddRef(d);
958 return IDataObject_Release(d);
959 }
960
961 static void test_consumer_refs(void)
962 {
963 HRESULT hr;
964 IDataObject *src, *src2, *get1, *get2, *get3;
965 ULONG refs, old_refs;
966 FORMATETC fmt;
967 STGMEDIUM med;
968
969 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
970
971 OleInitialize(NULL);
972
973 /* First show that each clipboard state results in
974 a different data object */
975
976 hr = DataObjectImpl_CreateText("data1", &src);
977 ok(hr == S_OK, "got %08x\n", hr);
978 hr = DataObjectImpl_CreateText("data2", &src2);
979 ok(hr == S_OK, "got %08x\n", hr);
980
981 hr = OleSetClipboard(src);
982 ok(hr == S_OK, "got %08x\n", hr);
983
984 hr = OleGetClipboard(&get1);
985 ok(hr == S_OK, "got %08x\n", hr);
986
987 hr = OleGetClipboard(&get2);
988 ok(hr == S_OK, "got %08x\n", hr);
989
990 ok(get1 == get2 ||
991 broken(get1 != get2), /* win9x, winme & nt4 */
992 "data objects differ\n");
993 refs = IDataObject_Release(get2);
994 ok(refs == (get1 == get2 ? 1 : 0), "got %d\n", refs);
995
996 OleFlushClipboard();
997
998 DataObjectImpl_GetData_calls = 0;
999 hr = IDataObject_GetData(get1, &fmt, &med);
1000 ok(hr == S_OK, "got %08x\n", hr);
1001 ok(DataObjectImpl_GetData_calls == 0, "GetData called\n");
1002 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1003
1004 hr = OleGetClipboard(&get2);
1005 ok(hr == S_OK, "got %08x\n", hr);
1006
1007 ok(get1 != get2, "data objects match\n");
1008
1009 OleSetClipboard(NULL);
1010
1011 hr = OleGetClipboard(&get3);
1012 ok(hr == S_OK, "got %08x\n", hr);
1013
1014 ok(get1 != get3, "data objects match\n");
1015 ok(get2 != get3, "data objects match\n");
1016
1017 IDataObject_Release(get3);
1018 IDataObject_Release(get2);
1019 IDataObject_Release(get1);
1020
1021 /* Now call GetData before the flush and show that this
1022 takes a ref on our src data obj. */
1023
1024 hr = OleSetClipboard(src);
1025 ok(hr == S_OK, "got %08x\n", hr);
1026
1027 old_refs = count_refs(src);
1028
1029 hr = OleGetClipboard(&get1);
1030 ok(hr == S_OK, "got %08x\n", hr);
1031
1032 refs = count_refs(src);
1033 ok(refs == old_refs, "%d %d\n", refs, old_refs);
1034
1035 DataObjectImpl_GetData_calls = 0;
1036 hr = IDataObject_GetData(get1, &fmt, &med);
1037 ok(hr == S_OK, "got %08x\n", hr);
1038 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1039 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1040 refs = count_refs(src);
1041 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1042
1043 OleFlushClipboard();
1044
1045 DataObjectImpl_GetData_calls = 0;
1046 hr = IDataObject_GetData(get1, &fmt, &med);
1047 ok(hr == S_OK, "got %08x\n", hr);
1048 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1049 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1050
1051 refs = count_refs(src);
1052 ok(refs == 2, "%d\n", refs);
1053
1054 IDataObject_Release(get1);
1055
1056 refs = count_refs(src);
1057 ok(refs == 1, "%d\n", refs);
1058
1059 /* Now set a second src object before the call to GetData
1060 and show that GetData calls that second src. */
1061
1062 hr = OleSetClipboard(src);
1063 ok(hr == S_OK, "got %08x\n", hr);
1064
1065 old_refs = count_refs(src);
1066
1067 hr = OleGetClipboard(&get1);
1068 ok(hr == S_OK, "got %08x\n", hr);
1069
1070 refs = count_refs(src);
1071 ok(refs == old_refs, "%d %d\n", refs, old_refs);
1072
1073 hr = OleSetClipboard(src2);
1074 ok(hr == S_OK, "got %08x\n", hr);
1075
1076 old_refs = count_refs(src2);
1077
1078 DataObjectImpl_GetData_calls = 0;
1079 hr = IDataObject_GetData(get1, &fmt, &med);
1080 ok(hr == S_OK, "got %08x\n", hr);
1081 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1082 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1083
1084 refs = count_refs(src);
1085 ok(refs == 1, "%d\n", refs);
1086 refs = count_refs(src2);
1087 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1088
1089 OleSetClipboard(NULL);
1090
1091 refs = count_refs(src2);
1092 ok(refs == 2, "%d\n", refs);
1093
1094 IDataObject_Release(get1);
1095
1096 IDataObject_Release(src2);
1097 IDataObject_Release(src);
1098
1099 OleUninitialize();
1100 }
1101
1102 static void test_flushed_getdata(void)
1103 {
1104 HRESULT hr;
1105 IDataObject *src, *get;
1106 FORMATETC fmt;
1107 STGMEDIUM med;
1108 STATSTG stat;
1109 DEVMODEW dm;
1110
1111 OleInitialize(NULL);
1112
1113 hr = DataObjectImpl_CreateComplex(&src);
1114 ok(hr == S_OK, "got %08x\n", hr);
1115
1116 hr = OleSetClipboard(src);
1117 ok(hr == S_OK, "got %08x\n", hr);
1118
1119 hr = OleFlushClipboard();
1120 ok(hr == S_OK, "got %08x\n", hr);
1121
1122 hr = OleGetClipboard(&get);
1123 ok(hr == S_OK, "got %08x\n", hr);
1124
1125 /* global format -> global & stream */
1126
1127 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1128 hr = IDataObject_GetData(get, &fmt, &med);
1129 ok(hr == S_OK, "got %08x\n", hr);
1130 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1131 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1132
1133 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTREAM);
1134 hr = IDataObject_GetData(get, &fmt, &med);
1135 ok(hr == S_OK, "got %08x\n", hr);
1136 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1137 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1138
1139 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTORAGE);
1140 hr = IDataObject_GetData(get, &fmt, &med);
1141 ok(hr == E_FAIL, "got %08x\n", hr);
1142 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1143
1144 InitFormatEtc(fmt, CF_TEXT, 0xffff);
1145 hr = IDataObject_GetData(get, &fmt, &med);
1146 ok(hr == S_OK, "got %08x\n", hr);
1147 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1148 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1149
1150 /* stream format -> global & stream */
1151
1152 InitFormatEtc(fmt, cf_stream, TYMED_ISTREAM);
1153 hr = IDataObject_GetData(get, &fmt, &med);
1154 ok(hr == S_OK, "got %08x\n", hr);
1155 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1156 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1157
1158 InitFormatEtc(fmt, cf_stream, TYMED_ISTORAGE);
1159 hr = IDataObject_GetData(get, &fmt, &med);
1160 ok(hr == E_FAIL, "got %08x\n", hr);
1161 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1162
1163 InitFormatEtc(fmt, cf_stream, TYMED_HGLOBAL);
1164 hr = IDataObject_GetData(get, &fmt, &med);
1165 ok(hr == S_OK, "got %08x\n", hr);
1166 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1167 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1168
1169 InitFormatEtc(fmt, cf_stream, 0xffff);
1170 hr = IDataObject_GetData(get, &fmt, &med);
1171 ok(hr == S_OK, "got %08x\n", hr);
1172 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1173 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1174
1175 /* storage format -> global, stream & storage */
1176
1177 InitFormatEtc(fmt, cf_storage, TYMED_ISTORAGE);
1178 hr = IDataObject_GetData(get, &fmt, &med);
1179 ok(hr == S_OK, "got %08x\n", hr);
1180 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1181 if(SUCCEEDED(hr)) {
1182 hr = IStorage_Stat(med.u.pstg, &stat, STATFLAG_NONAME);
1183 ok(hr == S_OK, "got %08x\n", hr);
1184 ok(stat.grfMode == (STGM_SHARE_EXCLUSIVE | STGM_READWRITE), "got %08x\n", stat.grfMode);
1185 ReleaseStgMedium(&med);
1186 }
1187
1188 InitFormatEtc(fmt, cf_storage, TYMED_ISTREAM);
1189 hr = IDataObject_GetData(get, &fmt, &med);
1190 ok(hr == S_OK, "got %08x\n", hr);
1191 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1192 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1193
1194 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL);
1195 hr = IDataObject_GetData(get, &fmt, &med);
1196 ok(hr == S_OK, "got %08x\n", hr);
1197 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1198 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1199
1200 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL | TYMED_ISTREAM);
1201 hr = IDataObject_GetData(get, &fmt, &med);
1202 ok(hr == S_OK, "got %08x\n", hr);
1203 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1204 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1205
1206 InitFormatEtc(fmt, cf_storage, 0xffff);
1207 hr = IDataObject_GetData(get, &fmt, &med);
1208 ok(hr == S_OK, "got %08x\n", hr);
1209 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1210 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1211
1212 /* complex format with target device */
1213
1214 InitFormatEtc(fmt, cf_another, 0xffff);
1215 hr = IDataObject_GetData(get, &fmt, &med);
1216 ok(hr == S_OK, "got %08x\n", hr);
1217 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1218
1219 if (0) /* Causes crashes on both Wine and Windows */
1220 {
1221 InitFormatEtc(fmt, cf_another, 0xffff);
1222 memset(&dm, 0, sizeof(dm));
1223 dm.dmSize = sizeof(dm);
1224 dm.dmDriverExtra = 0;
1225 lstrcpyW(dm.dmDeviceName, device_name);
1226 fmt.ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
1227 fmt.ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
1228 fmt.ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
1229 fmt.ptd->tdDeviceNameOffset = 0;
1230 fmt.ptd->tdPortNameOffset = 0;
1231 fmt.ptd->tdExtDevmodeOffset = fmt.ptd->tdDriverNameOffset + sizeof(device_name);
1232 lstrcpyW((WCHAR*)fmt.ptd->tdData, device_name);
1233 memcpy(fmt.ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
1234
1235 hr = IDataObject_GetData(get, &fmt, &med);
1236 ok(hr == S_OK, "got %08x\n", hr);
1237 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1238 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1239
1240 HeapFree(GetProcessHeap(), 0, fmt.ptd);
1241 }
1242
1243
1244 IDataObject_Release(get);
1245 IDataObject_Release(src);
1246 OleUninitialize();
1247 }
1248
1249 static HGLOBAL create_text(void)
1250 {
1251 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5);
1252 char *p = GlobalLock(h);
1253 strcpy(p, "test");
1254 GlobalUnlock(h);
1255 return h;
1256 }
1257
1258 static HENHMETAFILE create_emf(void)
1259 {
1260 const RECT rect = {0, 0, 100, 100};
1261 HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1262 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
1263 return CloseEnhMetaFile(hdc);
1264 }
1265
1266 static void test_nonole_clipboard(void)
1267 {
1268 HRESULT hr;
1269 BOOL r;
1270 IDataObject *get;
1271 IEnumFORMATETC *enum_fmt;
1272 FORMATETC fmt;
1273 HGLOBAL h, hblob, htext;
1274 HENHMETAFILE emf;
1275 STGMEDIUM med;
1276 DWORD obj_type;
1277
1278 r = OpenClipboard(NULL);
1279 ok(r, "gle %d\n", GetLastError());
1280 r = EmptyClipboard();
1281 ok(r, "gle %d\n", GetLastError());
1282 r = CloseClipboard();
1283 ok(r, "gle %d\n", GetLastError());
1284
1285 OleInitialize(NULL);
1286
1287 /* empty clipboard */
1288 hr = OleGetClipboard(&get);
1289 ok(hr == S_OK, "got %08x\n", hr);
1290 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1291 ok(hr == S_OK, "got %08x\n", hr);
1292
1293 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1294 ok(hr == S_FALSE, "got %08x\n", hr);
1295 IEnumFORMATETC_Release(enum_fmt);
1296
1297 IDataObject_Release(get);
1298
1299 /* set a user defined clipboard type */
1300
1301 htext = create_text();
1302 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
1303 emf = create_emf();
1304
1305 r = OpenClipboard(NULL);
1306 ok(r, "gle %d\n", GetLastError());
1307 h = SetClipboardData(CF_TEXT, htext);
1308 ok(h == htext, "got %p\n", h);
1309 h = SetClipboardData(cf_onemore, hblob);
1310 ok(h == hblob, "got %p\n", h);
1311 h = SetClipboardData(CF_ENHMETAFILE, emf);
1312 ok(h == emf, "got %p\n", h);
1313 r = CloseClipboard();
1314 ok(r, "gle %d\n", GetLastError());
1315
1316 hr = OleGetClipboard(&get);
1317 ok(hr == S_OK, "got %08x\n", hr);
1318 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1319 ok(hr == S_OK, "got %08x\n", hr);
1320
1321 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1322 ok(hr == S_OK, "got %08x\n", hr);
1323 ok(fmt.cfFormat == CF_TEXT, "cf %04x\n", fmt.cfFormat);
1324 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1325 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1326 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1327 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1328
1329 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1330 ok(hr == S_OK, "got %08x\n", hr);
1331 ok(fmt.cfFormat == cf_onemore, "cf %04x\n", fmt.cfFormat);
1332 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1333 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1334 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1335 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1336
1337 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1338 ok(hr == S_OK, "got %08x\n", hr);
1339 ok(fmt.cfFormat == CF_ENHMETAFILE, "cf %04x\n", fmt.cfFormat);
1340 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1341 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1342 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1343 ok(fmt.tymed == TYMED_ENHMF, "tymed %x\n", fmt.tymed);
1344
1345 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1346 ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */
1347
1348 todo_wine ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
1349 if(fmt.cfFormat == CF_LOCALE)
1350 {
1351 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1352 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1353 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1354 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1355
1356 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1357 ok(hr == S_OK, "got %08x\n", hr);
1358 }
1359
1360 ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat);
1361 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1362 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1363 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1364 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1365
1366 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1367 ok(hr == S_OK, "got %08x\n", hr);
1368 ok(fmt.cfFormat == CF_UNICODETEXT ||
1369 broken(fmt.cfFormat == CF_METAFILEPICT), /* win9x and winme don't have CF_UNICODETEXT */
1370 "cf %04x\n", fmt.cfFormat);
1371 if(fmt.cfFormat == CF_UNICODETEXT)
1372 {
1373 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1374 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1375 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1376 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1377
1378 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1379 ok(hr == S_OK, "got %08x\n", hr);
1380 }
1381 ok(fmt.cfFormat == CF_METAFILEPICT, "cf %04x\n", fmt.cfFormat);
1382 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1383 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1384 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1385 ok(fmt.tymed == TYMED_MFPICT, "tymed %x\n", fmt.tymed);
1386
1387 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1388 ok(hr == S_FALSE, "got %08x\n", hr);
1389 IEnumFORMATETC_Release(enum_fmt);
1390
1391 InitFormatEtc(fmt, CF_ENHMETAFILE, TYMED_ENHMF);
1392 hr = IDataObject_GetData(get, &fmt, &med);
1393 ok(hr == S_OK, "got %08x\n", hr);
1394 obj_type = GetObjectType(U(med).hEnhMetaFile);
1395 ok(obj_type == OBJ_ENHMETAFILE, "got %d\n", obj_type);
1396 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1397
1398 IDataObject_Release(get);
1399
1400 r = OpenClipboard(NULL);
1401 ok(r, "gle %d\n", GetLastError());
1402 r = EmptyClipboard();
1403 ok(r, "gle %d\n", GetLastError());
1404 r = CloseClipboard();
1405 ok(r, "gle %d\n", GetLastError());
1406
1407 OleUninitialize();
1408 }
1409
1410 static void test_getdatahere(void)
1411 {
1412 HRESULT hr;
1413 IDataObject *src, *get;
1414 FORMATETC fmt;
1415 STGMEDIUM med;
1416
1417 OleInitialize(NULL);
1418
1419 hr = DataObjectImpl_CreateComplex(&src);
1420 ok(hr == S_OK, "got %08x\n", hr);
1421
1422 hr = OleSetClipboard(src);
1423 ok(hr == S_OK, "got %08x\n", hr);
1424
1425 hr = OleGetClipboard(&get);
1426 ok(hr == S_OK, "got %08x\n", hr);
1427
1428 /* global format -> global & stream */
1429
1430 DataObjectImpl_GetData_calls = 0;
1431 DataObjectImpl_GetDataHere_calls = 0;
1432
1433 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1434
1435 med.pUnkForRelease = NULL;
1436 med.tymed = TYMED_HGLOBAL;
1437 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1438 hr = IDataObject_GetDataHere(get, &fmt, &med);
1439 ok(hr == S_OK, "got %08x\n", hr);
1440 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1441 ReleaseStgMedium(&med);
1442 ok(DataObjectImpl_GetDataHere_calls == 1, "called %d\n", DataObjectImpl_GetDataHere_calls);
1443 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1444
1445 InitFormatEtc(fmt, CF_TEXT, 0);
1446
1447 med.pUnkForRelease = NULL;
1448 med.tymed = TYMED_HGLOBAL;
1449 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1450 hr = IDataObject_GetDataHere(get, &fmt, &med);
1451 ok(hr == S_OK, "got %08x\n", hr);
1452 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1453 ReleaseStgMedium(&med);
1454 ok(DataObjectImpl_GetDataHere_calls == 2, "called %d\n", DataObjectImpl_GetDataHere_calls);
1455 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1456
1457 med.pUnkForRelease = NULL;
1458 med.tymed = TYMED_HGLOBAL;
1459 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 1);
1460 hr = IDataObject_GetDataHere(get, &fmt, &med);
1461 ok(hr == E_FAIL, "got %08x\n", hr);
1462 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1463 ReleaseStgMedium(&med);
1464 ok(DataObjectImpl_GetDataHere_calls == 3, "called %d\n", DataObjectImpl_GetDataHere_calls);
1465 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1466
1467 med.pUnkForRelease = NULL;
1468 med.tymed = TYMED_ISTREAM;
1469 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1470 hr = IDataObject_GetDataHere(get, &fmt, &med);
1471 ok(hr == S_OK, "got %08x\n", hr);
1472 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1473 ReleaseStgMedium(&med);
1474 ok(DataObjectImpl_GetDataHere_calls == 4, "called %d\n", DataObjectImpl_GetDataHere_calls);
1475 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1476
1477 med.pUnkForRelease = NULL;
1478 med.tymed = TYMED_ISTORAGE;
1479 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1480 hr = IDataObject_GetDataHere(get, &fmt, &med);
1481 ok(hr == E_FAIL, "got %08x\n", hr);
1482 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1483 ReleaseStgMedium(&med);
1484 ok(DataObjectImpl_GetDataHere_calls == 5, "called %d\n", DataObjectImpl_GetDataHere_calls);
1485 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1486
1487 InitFormatEtc(fmt, cf_stream, 0);
1488
1489 med.pUnkForRelease = NULL;
1490 med.tymed = TYMED_HGLOBAL;
1491 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1492 hr = IDataObject_GetDataHere(get, &fmt, &med);
1493 ok(hr == S_OK, "got %08x\n", hr);
1494 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1495 ReleaseStgMedium(&med);
1496 ok(DataObjectImpl_GetDataHere_calls == 7, "called %d\n", DataObjectImpl_GetDataHere_calls);
1497 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1498
1499 med.pUnkForRelease = NULL;
1500 med.tymed = TYMED_ISTREAM;
1501 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1502 hr = IDataObject_GetDataHere(get, &fmt, &med);
1503 ok(hr == S_OK, "got %08x\n", hr);
1504 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1505 ReleaseStgMedium(&med);
1506 ok(DataObjectImpl_GetDataHere_calls == 8, "called %d\n", DataObjectImpl_GetDataHere_calls);
1507 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1508
1509 med.pUnkForRelease = NULL;
1510 med.tymed = TYMED_ISTORAGE;
1511 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1512 hr = IDataObject_GetDataHere(get, &fmt, &med);
1513 ok(hr == E_FAIL, "got %08x\n", hr);
1514 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1515 ReleaseStgMedium(&med);
1516 ok(DataObjectImpl_GetDataHere_calls == 9, "called %d\n", DataObjectImpl_GetDataHere_calls);
1517 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1518
1519 InitFormatEtc(fmt, cf_storage, 0);
1520
1521 med.pUnkForRelease = NULL;
1522 med.tymed = TYMED_HGLOBAL;
1523 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 3000);
1524 hr = IDataObject_GetDataHere(get, &fmt, &med);
1525 ok(hr == S_OK, "got %08x\n", hr);
1526 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1527 ReleaseStgMedium(&med);
1528 ok(DataObjectImpl_GetDataHere_calls == 11, "called %d\n", DataObjectImpl_GetDataHere_calls);
1529 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1530
1531 med.pUnkForRelease = NULL;
1532 med.tymed = TYMED_ISTREAM;
1533 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1534 hr = IDataObject_GetDataHere(get, &fmt, &med);
1535 ok(hr == S_OK, "got %08x\n", hr);
1536 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1537 ReleaseStgMedium(&med);
1538 ok(DataObjectImpl_GetDataHere_calls == 12, "called %d\n", DataObjectImpl_GetDataHere_calls);
1539 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1540
1541 med.pUnkForRelease = NULL;
1542 med.tymed = TYMED_ISTORAGE;
1543 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1544 hr = IDataObject_GetDataHere(get, &fmt, &med);
1545 ok(hr == S_OK, "got %08x\n", hr);
1546 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1547 ReleaseStgMedium(&med);
1548 ok(DataObjectImpl_GetDataHere_calls == 13, "called %d\n", DataObjectImpl_GetDataHere_calls);
1549 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1550
1551
1552 IDataObject_Release(get);
1553 IDataObject_Release(src);
1554
1555 OleUninitialize();
1556
1557 }
1558
1559 static DWORD CALLBACK test_data_obj(void *arg)
1560 {
1561 IDataObject *data_obj = arg;
1562
1563 IDataObject_Release(data_obj);
1564 return 0;
1565 }
1566
1567 static void test_multithreaded_clipboard(void)
1568 {
1569 IDataObject *data_obj;
1570 HANDLE thread;
1571 HRESULT hr;
1572 DWORD ret;
1573
1574 OleInitialize(NULL);
1575
1576 hr = OleGetClipboard(&data_obj);
1577 ok(hr == S_OK, "OleGetClipboard returned %x\n", hr);
1578
1579 thread = CreateThread(NULL, 0, test_data_obj, data_obj, 0, NULL);
1580 ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError());
1581 ret = WaitForSingleObject(thread, 5000);
1582 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret);
1583
1584 hr = OleGetClipboard(&data_obj);
1585 ok(hr == S_OK, "OleGetClipboard returned %x\n", hr);
1586 IDataObject_Release(data_obj);
1587
1588 OleUninitialize();
1589 }
1590
1591 static void test_get_clipboard_locked(void)
1592 {
1593 HRESULT hr;
1594 IDataObject *pDObj;
1595
1596 OleInitialize(NULL);
1597
1598 pDObj = (IDataObject *)0xdeadbeef;
1599 /* lock clipboard */
1600 OpenClipboard(NULL);
1601 hr = OleGetClipboard(&pDObj);
1602 todo_wine ok(hr == CLIPBRD_E_CANT_OPEN, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr, CLIPBRD_E_CANT_OPEN);
1603 todo_wine ok(pDObj == NULL, "OleGetClipboard() got 0x%p instead of NULL\n",pDObj);
1604 if (pDObj) IDataObject_Release(pDObj);
1605 CloseClipboard();
1606
1607 OleUninitialize();
1608 }
1609
1610 START_TEST(clipboard)
1611 {
1612 test_get_clipboard_uninitialized();
1613 test_set_clipboard();
1614 test_consumer_refs();
1615 test_flushed_getdata();
1616 test_nonole_clipboard();
1617 test_getdatahere();
1618 test_multithreaded_clipboard();
1619 test_get_clipboard_locked();
1620 }