dmscript: Merge the IClassFactory implementations.
[wine/testsucceed.git] / dlls / ole32 / tests / clipboard.c
blob1029a682726fa5b05f708085f336b46f1acb6690
1 /*
2 * Clipboard unit tests
4 * Copyright 2006 Kevin Koltzau
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.
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.
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
21 #define COBJMACROS
22 #define CONST_VTABLE
23 #define NONAMELESSUNION
25 #include <stdarg.h>
26 #include <stdio.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
32 #include "wine/test.h"
34 #define InitFormatEtc(fe, cf, med) \
36 (fe).cfFormat=cf;\
37 (fe).dwAspect=DVASPECT_CONTENT;\
38 (fe).ptd=NULL;\
39 (fe).tymed=med;\
40 (fe).lindex=-1;\
43 static inline char *dump_fmtetc(FORMATETC *fmt)
45 static char buf[100];
47 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
48 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
49 return buf;
52 typedef struct DataObjectImpl {
53 IDataObject IDataObject_iface;
54 LONG ref;
56 FORMATETC *fmtetc;
57 UINT fmtetc_cnt;
59 HANDLE text;
60 IStream *stm;
61 IStorage *stg;
62 } DataObjectImpl;
64 typedef struct EnumFormatImpl {
65 IEnumFORMATETC IEnumFORMATETC_iface;
66 LONG ref;
68 FORMATETC *fmtetc;
69 UINT fmtetc_cnt;
71 UINT cur;
72 } EnumFormatImpl;
74 static BOOL expect_DataObjectImpl_QueryGetData = TRUE;
75 static ULONG DataObjectImpl_GetData_calls = 0;
76 static ULONG DataObjectImpl_GetDataHere_calls = 0;
77 static ULONG DataObjectImpl_EnumFormatEtc_calls = 0;
79 static UINT cf_stream, cf_storage, cf_global, cf_another, cf_onemore;
81 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
83 static inline DataObjectImpl *impl_from_IDataObject(IDataObject *iface)
85 return CONTAINING_RECORD(iface, DataObjectImpl, IDataObject_iface);
88 static inline EnumFormatImpl *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
90 return CONTAINING_RECORD(iface, EnumFormatImpl, IEnumFORMATETC_iface);
93 static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
95 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
97 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) {
98 IEnumFORMATETC_AddRef(iface);
99 *ppvObj = This;
100 return S_OK;
102 *ppvObj = NULL;
103 return E_NOINTERFACE;
106 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
108 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
109 LONG ref = InterlockedIncrement(&This->ref);
110 return ref;
113 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
115 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
116 ULONG ref = InterlockedDecrement(&This->ref);
118 if(!ref) {
119 HeapFree(GetProcessHeap(), 0, This->fmtetc);
120 HeapFree(GetProcessHeap(), 0, This);
123 return ref;
126 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
127 FORMATETC *rgelt, ULONG *pceltFetched)
129 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
130 ULONG count, i;
132 trace("next: count %d cur %d\n", celt, This->cur);
134 if(!rgelt)
135 return E_INVALIDARG;
137 count = min(celt, This->fmtetc_cnt - This->cur);
138 for(i = 0; i < count; i++, This->cur++, rgelt++)
140 *rgelt = This->fmtetc[This->cur];
141 if(rgelt->ptd)
143 DWORD size = This->fmtetc[This->cur].ptd->tdSize;
144 rgelt->ptd = CoTaskMemAlloc(size);
145 memcpy(rgelt->ptd, This->fmtetc[This->cur].ptd, size);
148 if(pceltFetched)
149 *pceltFetched = count;
150 return count == celt ? S_OK : S_FALSE;
153 static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt)
155 ok(0, "unexpected call\n");
156 return E_NOTIMPL;
159 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
161 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
163 This->cur = 0;
164 return S_OK;
167 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
169 ok(0, "unexpected call\n");
170 return E_NOTIMPL;
173 static const IEnumFORMATETCVtbl VT_EnumFormatImpl = {
174 EnumFormatImpl_QueryInterface,
175 EnumFormatImpl_AddRef,
176 EnumFormatImpl_Release,
177 EnumFormatImpl_Next,
178 EnumFormatImpl_Skip,
179 EnumFormatImpl_Reset,
180 EnumFormatImpl_Clone
183 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
185 EnumFormatImpl *ret;
187 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl));
188 ret->IEnumFORMATETC_iface.lpVtbl = &VT_EnumFormatImpl;
189 ret->ref = 1;
190 ret->cur = 0;
191 ret->fmtetc_cnt = fmtetc_cnt;
192 ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC));
193 memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
194 *lplpformatetc = (LPENUMFORMATETC)ret;
195 return S_OK;
198 static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj)
200 DataObjectImpl *This = impl_from_IDataObject(iface);
202 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) {
203 IDataObject_AddRef(iface);
204 *ppvObj = This;
205 return S_OK;
207 *ppvObj = NULL;
208 return E_NOINTERFACE;
211 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
213 DataObjectImpl *This = impl_from_IDataObject(iface);
214 ULONG ref = InterlockedIncrement(&This->ref);
215 return ref;
218 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
220 DataObjectImpl *This = impl_from_IDataObject(iface);
221 ULONG ref = InterlockedDecrement(&This->ref);
223 if(!ref)
225 int i;
226 if(This->text) GlobalFree(This->text);
227 for(i = 0; i < This->fmtetc_cnt; i++)
228 HeapFree(GetProcessHeap(), 0, This->fmtetc[i].ptd);
229 HeapFree(GetProcessHeap(), 0, This->fmtetc);
230 if(This->stm) IStream_Release(This->stm);
231 if(This->stg) IStorage_Release(This->stg);
232 HeapFree(GetProcessHeap(), 0, This);
235 return ref;
238 static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
240 DataObjectImpl *This = impl_from_IDataObject(iface);
241 UINT i;
242 BOOL foundFormat = FALSE;
244 trace("getdata: %s\n", dump_fmtetc(pformatetc));
246 DataObjectImpl_GetData_calls++;
248 if(pformatetc->lindex != -1)
249 return DV_E_FORMATETC;
251 for(i = 0; i < This->fmtetc_cnt; i++)
253 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat)
255 foundFormat = TRUE;
256 if(This->fmtetc[i].tymed & pformatetc->tymed)
258 pmedium->pUnkForRelease = (LPUNKNOWN)iface;
259 IUnknown_AddRef(pmedium->pUnkForRelease);
261 if(pformatetc->cfFormat == CF_TEXT || pformatetc->cfFormat == cf_global)
263 pmedium->tymed = TYMED_HGLOBAL;
264 U(*pmedium).hGlobal = This->text;
266 else if(pformatetc->cfFormat == cf_stream)
268 pmedium->tymed = TYMED_ISTREAM;
269 IStream_AddRef(This->stm);
270 U(*pmedium).pstm = This->stm;
272 else if(pformatetc->cfFormat == cf_storage || pformatetc->cfFormat == cf_another)
274 pmedium->tymed = TYMED_ISTORAGE;
275 IStorage_AddRef(This->stg);
276 U(*pmedium).pstg = This->stg;
278 return S_OK;
283 return foundFormat ? DV_E_TYMED : DV_E_FORMATETC;
286 static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
288 trace("getdatahere: %s\n", dump_fmtetc(pformatetc));
289 DataObjectImpl_GetDataHere_calls++;
291 return E_NOTIMPL;
294 static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc)
296 DataObjectImpl *This = impl_from_IDataObject(iface);
297 UINT i;
298 BOOL foundFormat = FALSE;
300 trace("querygetdata: %s\n", dump_fmtetc(pformatetc));
301 if (!expect_DataObjectImpl_QueryGetData)
302 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
304 if(pformatetc->lindex != -1)
305 return DV_E_LINDEX;
307 for(i=0; i<This->fmtetc_cnt; i++) {
308 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) {
309 foundFormat = TRUE;
310 if(This->fmtetc[i].tymed == pformatetc->tymed)
311 return S_OK;
314 return foundFormat?DV_E_FORMATETC:DV_E_TYMED;
317 static HRESULT WINAPI DataObjectImpl_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC *pformatectIn,
318 FORMATETC *pformatetcOut)
320 ok(0, "unexpected call\n");
321 return E_NOTIMPL;
324 static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc,
325 STGMEDIUM *pmedium, BOOL fRelease)
327 ok(0, "unexpected call\n");
328 return E_NOTIMPL;
331 static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwDirection,
332 IEnumFORMATETC **ppenumFormatEtc)
334 DataObjectImpl *This = impl_from_IDataObject(iface);
336 DataObjectImpl_EnumFormatEtc_calls++;
338 if(dwDirection != DATADIR_GET) {
339 ok(0, "unexpected direction %d\n", dwDirection);
340 return E_NOTIMPL;
342 return EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenumFormatEtc);
345 static HRESULT WINAPI DataObjectImpl_DAdvise(IDataObject* iface, FORMATETC *pformatetc, DWORD advf,
346 IAdviseSink *pAdvSink, DWORD *pdwConnection)
348 ok(0, "unexpected call\n");
349 return E_NOTIMPL;
352 static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection)
354 ok(0, "unexpected call\n");
355 return E_NOTIMPL;
358 static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise)
360 ok(0, "unexpected call\n");
361 return E_NOTIMPL;
364 static const IDataObjectVtbl VT_DataObjectImpl =
366 DataObjectImpl_QueryInterface,
367 DataObjectImpl_AddRef,
368 DataObjectImpl_Release,
369 DataObjectImpl_GetData,
370 DataObjectImpl_GetDataHere,
371 DataObjectImpl_QueryGetData,
372 DataObjectImpl_GetCanonicalFormatEtc,
373 DataObjectImpl_SetData,
374 DataObjectImpl_EnumFormatEtc,
375 DataObjectImpl_DAdvise,
376 DataObjectImpl_DUnadvise,
377 DataObjectImpl_EnumDAdvise
380 static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
382 DataObjectImpl *obj;
384 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
385 obj->IDataObject_iface.lpVtbl = &VT_DataObjectImpl;
386 obj->ref = 1;
387 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1);
388 strcpy(GlobalLock(obj->text), text);
389 GlobalUnlock(obj->text);
390 obj->stm = NULL;
391 obj->stg = NULL;
393 obj->fmtetc_cnt = 1;
394 obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
395 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
397 *lplpdataobj = (LPDATAOBJECT)obj;
398 return S_OK;
401 static const char *cmpl_stm_data = "complex stream";
402 static const char *cmpl_text_data = "complex text";
403 static const WCHAR device_name[] = {'m','y','d','e','v',0};
405 static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj)
407 DataObjectImpl *obj;
408 ILockBytes *lbs;
409 DEVMODEW dm;
411 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
412 obj->IDataObject_iface.lpVtbl = &VT_DataObjectImpl;
413 obj->ref = 1;
414 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(cmpl_text_data) + 1);
415 strcpy(GlobalLock(obj->text), cmpl_text_data);
416 GlobalUnlock(obj->text);
417 CreateStreamOnHGlobal(NULL, TRUE, &obj->stm);
418 IStream_Write(obj->stm, cmpl_stm_data, strlen(cmpl_stm_data), NULL);
420 CreateILockBytesOnHGlobal(NULL, TRUE, &lbs);
421 StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &obj->stg);
422 ILockBytes_Release(lbs);
424 obj->fmtetc_cnt = 8;
425 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
426 obj->fmtetc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, obj->fmtetc_cnt*sizeof(FORMATETC));
427 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
428 InitFormatEtc(obj->fmtetc[1], cf_stream, TYMED_ISTREAM);
429 InitFormatEtc(obj->fmtetc[2], cf_storage, TYMED_ISTORAGE);
430 InitFormatEtc(obj->fmtetc[3], cf_another, TYMED_ISTORAGE|TYMED_ISTREAM|TYMED_HGLOBAL);
431 if (0) /* Causes crashes on both Wine and Windows */
433 memset(&dm, 0, sizeof(dm));
434 dm.dmSize = sizeof(dm);
435 dm.dmDriverExtra = 0;
436 lstrcpyW(dm.dmDeviceName, device_name);
437 obj->fmtetc[3].ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
438 obj->fmtetc[3].ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
439 obj->fmtetc[3].ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
440 obj->fmtetc[3].ptd->tdDeviceNameOffset = 0;
441 obj->fmtetc[3].ptd->tdPortNameOffset = 0;
442 obj->fmtetc[3].ptd->tdExtDevmodeOffset = obj->fmtetc[3].ptd->tdDriverNameOffset + sizeof(device_name);
443 lstrcpyW((WCHAR*)obj->fmtetc[3].ptd->tdData, device_name);
444 memcpy(obj->fmtetc[3].ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
447 InitFormatEtc(obj->fmtetc[4], cf_global, TYMED_HGLOBAL);
448 InitFormatEtc(obj->fmtetc[5], cf_another, TYMED_HGLOBAL);
449 InitFormatEtc(obj->fmtetc[6], cf_another, 0xfffff);
450 InitFormatEtc(obj->fmtetc[7], cf_another, 0xfffff);
451 obj->fmtetc[7].dwAspect = DVASPECT_ICON;
453 *lplpdataobj = (LPDATAOBJECT)obj;
454 return S_OK;
457 static void test_get_clipboard(void)
459 HRESULT hr;
460 IDataObject *data_obj;
461 FORMATETC fmtetc;
462 STGMEDIUM stgmedium;
464 hr = OleGetClipboard(NULL);
465 ok(hr == E_INVALIDARG, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr);
467 hr = OleGetClipboard(&data_obj);
468 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
470 /* test IDataObject_QueryGetData */
472 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
473 expect_DataObjectImpl_QueryGetData = FALSE;
475 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
476 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
477 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
479 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
480 fmtetc.dwAspect = 0xdeadbeef;
481 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
482 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
484 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
485 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
486 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
487 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
489 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
490 fmtetc.lindex = 256;
491 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
492 ok(hr == DV_E_FORMATETC || broken(hr == S_OK),
493 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
495 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
496 fmtetc.cfFormat = CF_RIFF;
497 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
498 ok(hr == DV_E_CLIPFORMAT, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr);
500 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
501 fmtetc.tymed = TYMED_FILE;
502 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
503 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
505 expect_DataObjectImpl_QueryGetData = TRUE;
507 /* test IDataObject_GetData */
509 DataObjectImpl_GetData_calls = 0;
511 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
512 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
513 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
514 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
516 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
517 fmtetc.dwAspect = 0xdeadbeef;
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);
522 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
523 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
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);
528 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
529 fmtetc.lindex = 256;
530 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
531 ok(hr == DV_E_FORMATETC || broken(hr == S_OK), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
532 if (hr == S_OK)
534 /* undo the unexpected success */
535 DataObjectImpl_GetData_calls--;
536 ReleaseStgMedium(&stgmedium);
539 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
540 fmtetc.cfFormat = CF_RIFF;
541 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
542 ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
543 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
545 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
546 fmtetc.tymed = TYMED_FILE;
547 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
548 ok(hr == DV_E_TYMED, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr);
549 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
551 ok(DataObjectImpl_GetData_calls == 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls);
553 IDataObject_Release(data_obj);
556 static void test_enum_fmtetc(IDataObject *src)
558 HRESULT hr;
559 IDataObject *data;
560 IEnumFORMATETC *enum_fmt, *src_enum;
561 FORMATETC fmt, src_fmt;
562 DWORD count = 0;
564 hr = OleGetClipboard(&data);
565 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
567 hr = IDataObject_EnumFormatEtc(data, DATADIR_SET, &enum_fmt);
568 ok(hr == E_NOTIMPL ||
569 broken(hr == E_INVALIDARG), /* win98 (not win98SE) */
570 "got %08x\n", hr);
572 DataObjectImpl_EnumFormatEtc_calls = 0;
573 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
574 ok(hr == S_OK, "got %08x\n", hr);
575 ok(DataObjectImpl_EnumFormatEtc_calls == 0, "EnumFormatEtc was called\n");
577 if(src) IDataObject_EnumFormatEtc(src, DATADIR_GET, &src_enum);
579 while((hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL)) == S_OK)
581 ok(src != NULL, "shouldn't be here\n");
582 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
583 ok(hr == S_OK, "%d: got %08x\n", count, hr);
584 trace("%d: %s\n", count, dump_fmtetc(&fmt));
585 ok(fmt.cfFormat == src_fmt.cfFormat, "%d: %04x %04x\n", count, fmt.cfFormat, src_fmt.cfFormat);
586 ok(fmt.dwAspect == src_fmt.dwAspect, "%d: %08x %08x\n", count, fmt.dwAspect, src_fmt.dwAspect);
587 ok(fmt.lindex == src_fmt.lindex, "%d: %08x %08x\n", count, fmt.lindex, src_fmt.lindex);
588 ok(fmt.tymed == src_fmt.tymed, "%d: %08x %08x\n", count, fmt.tymed, src_fmt.tymed);
589 if(fmt.ptd)
591 ok(src_fmt.ptd != NULL, "%d: expected non-NULL\n", count);
592 CoTaskMemFree(fmt.ptd);
593 CoTaskMemFree(src_fmt.ptd);
595 count++;
598 ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
600 if(src)
602 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
603 ok(hr == S_FALSE ||
604 broken(hr == S_OK && count == 5), /* win9x and winme don't enumerate duplicated cf's */
605 "%d: got %08x\n", count, hr);
606 IEnumFORMATETC_Release(src_enum);
609 hr = IEnumFORMATETC_Reset(enum_fmt);
610 ok(hr == S_OK, "got %08x\n", hr);
612 if(src) /* Exercise the enumerator a bit */
614 IEnumFORMATETC *clone;
615 FORMATETC third_fmt;
617 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
618 ok(hr == S_OK, "got %08x\n", hr);
619 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
620 ok(hr == S_OK, "got %08x\n", hr);
621 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
622 ok(hr == S_OK, "got %08x\n", hr);
624 hr = IEnumFORMATETC_Reset(enum_fmt);
625 ok(hr == S_OK, "got %08x\n", hr);
626 hr = IEnumFORMATETC_Skip(enum_fmt, 2);
627 ok(hr == S_OK, "got %08x\n", hr);
629 hr = IEnumFORMATETC_Clone(enum_fmt, &clone);
630 ok(hr == S_OK, "got %08x\n", hr);
631 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
632 ok(hr == S_OK, "got %08x\n", hr);
633 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
634 hr = IEnumFORMATETC_Next(clone, 1, &fmt, NULL);
635 ok(hr == S_OK, "got %08x\n", hr);
636 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
637 IEnumFORMATETC_Release(clone);
640 IEnumFORMATETC_Release(enum_fmt);
641 IDataObject_Release(data);
644 static void test_no_cf_dataobject(void)
646 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
647 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
648 HANDLE h;
649 OpenClipboard(NULL);
651 h = GetClipboardData(cf_dataobject);
652 ok(!h, "got %p\n", h);
653 h = GetClipboardData(cf_ole_priv_data);
654 ok(!h, "got %p\n", h);
656 CloseClipboard();
659 static void test_cf_dataobject(IDataObject *data)
661 UINT cf = 0;
662 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
663 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
664 BOOL found_dataobject = FALSE, found_priv_data = FALSE;
666 OpenClipboard(NULL);
669 cf = EnumClipboardFormats(cf);
670 if(cf == cf_dataobject)
672 HGLOBAL h = GetClipboardData(cf);
673 HWND *ptr = GlobalLock(h);
674 DWORD size = GlobalSize(h);
675 HWND clip_owner = GetClipboardOwner();
677 found_dataobject = TRUE;
678 ok(size >= sizeof(*ptr), "size %d\n", size);
679 if(data)
680 ok(*ptr == clip_owner, "hwnd %p clip_owner %p\n", *ptr, clip_owner);
681 else /* ole clipboard flushed */
682 ok(*ptr == NULL, "hwnd %p\n", *ptr);
683 GlobalUnlock(h);
685 else if(cf == cf_ole_priv_data)
687 found_priv_data = TRUE;
688 if(data)
690 HGLOBAL h = GetClipboardData(cf);
691 DWORD *ptr = GlobalLock(h);
692 DWORD size = GlobalSize(h);
694 if(size != ptr[1])
695 win_skip("Ole Private Data in win9x format\n");
696 else
698 HRESULT hr;
699 IEnumFORMATETC *enum_fmt;
700 DWORD count = 0;
701 FORMATETC fmt;
702 struct formatetcetc
704 FORMATETC fmt;
705 BOOL first_use_of_cf;
706 DWORD res[2];
707 } *fmt_ptr;
708 struct priv_data
710 DWORD res1;
711 DWORD size;
712 DWORD res2;
713 DWORD count;
714 DWORD res3[2];
715 struct formatetcetc fmts[1];
716 } *priv = (struct priv_data*)ptr;
717 CLIPFORMAT cfs_seen[10];
719 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
720 ok(hr == S_OK, "got %08x\n", hr);
721 fmt_ptr = priv->fmts;
723 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
725 int i;
726 BOOL seen_cf = FALSE;
728 ok(fmt_ptr->fmt.cfFormat == fmt.cfFormat,
729 "got %08x expected %08x\n", fmt_ptr->fmt.cfFormat, fmt.cfFormat);
730 ok(fmt_ptr->fmt.dwAspect == fmt.dwAspect, "got %08x expected %08x\n",
731 fmt_ptr->fmt.dwAspect, fmt.dwAspect);
732 ok(fmt_ptr->fmt.lindex == fmt.lindex, "got %08x expected %08x\n",
733 fmt_ptr->fmt.lindex, fmt.lindex);
734 ok(fmt_ptr->fmt.tymed == fmt.tymed, "got %08x expected %08x\n",
735 fmt_ptr->fmt.tymed, fmt.tymed);
736 for(i = 0; i < count; i++)
737 if(fmt_ptr->fmt.cfFormat == cfs_seen[i])
739 seen_cf = TRUE;
740 break;
742 cfs_seen[count] = fmt.cfFormat;
743 ok(fmt_ptr->first_use_of_cf == seen_cf ? FALSE : TRUE, "got %08x expected %08x\n",
744 fmt_ptr->first_use_of_cf, !seen_cf);
745 ok(fmt_ptr->res[0] == 0, "got %08x\n", fmt_ptr->res[1]);
746 ok(fmt_ptr->res[1] == 0, "got %08x\n", fmt_ptr->res[2]);
747 if(fmt.ptd)
749 DVTARGETDEVICE *target;
751 ok(fmt_ptr->fmt.ptd != NULL, "target device offset zero\n");
752 target = (DVTARGETDEVICE*)((char*)priv + (DWORD_PTR)fmt_ptr->fmt.ptd);
753 ok(!memcmp(target, fmt.ptd, fmt.ptd->tdSize), "target devices differ\n");
754 CoTaskMemFree(fmt.ptd);
756 fmt_ptr++;
757 count++;
759 ok(priv->res1 == 0, "got %08x\n", priv->res1);
760 ok(priv->res2 == 1, "got %08x\n", priv->res2);
761 ok(priv->count == count, "got %08x expected %08x\n", priv->count, count);
762 ok(priv->res3[0] == 0, "got %08x\n", priv->res3[0]);
764 /* win64 sets the lsb */
765 if(sizeof(fmt_ptr->fmt.ptd) == 8)
766 todo_wine ok(priv->res3[1] == 1, "got %08x\n", priv->res3[1]);
767 else
768 ok(priv->res3[1] == 0, "got %08x\n", priv->res3[1]);
770 GlobalUnlock(h);
771 IEnumFORMATETC_Release(enum_fmt);
775 else if(cf == cf_stream)
777 HGLOBAL h;
778 void *ptr;
779 DWORD size;
781 DataObjectImpl_GetDataHere_calls = 0;
782 h = GetClipboardData(cf);
783 ok(DataObjectImpl_GetDataHere_calls == 1, "got %d\n", DataObjectImpl_GetDataHere_calls);
784 ptr = GlobalLock(h);
785 size = GlobalSize(h);
786 ok(size == strlen(cmpl_stm_data) ||
787 broken(size > strlen(cmpl_stm_data)), /* win9x, winme */
788 "expected %d got %d\n", lstrlenA(cmpl_stm_data), size);
789 ok(!memcmp(ptr, cmpl_stm_data, strlen(cmpl_stm_data)), "mismatch\n");
790 GlobalUnlock(h);
792 else if(cf == cf_global)
794 HGLOBAL h;
795 void *ptr;
796 DWORD size;
798 DataObjectImpl_GetDataHere_calls = 0;
799 h = GetClipboardData(cf);
800 ok(DataObjectImpl_GetDataHere_calls == 0, "got %d\n", DataObjectImpl_GetDataHere_calls);
801 ptr = GlobalLock(h);
802 size = GlobalSize(h);
803 ok(size == strlen(cmpl_text_data) + 1 ||
804 broken(size > strlen(cmpl_text_data) + 1), /* win9x, winme */
805 "expected %d got %d\n", lstrlenA(cmpl_text_data) + 1, size);
806 ok(!memcmp(ptr, cmpl_text_data, strlen(cmpl_text_data) + 1), "mismatch\n");
807 GlobalUnlock(h);
809 } while(cf);
810 CloseClipboard();
811 ok(found_dataobject, "didn't find cf_dataobject\n");
812 ok(found_priv_data, "didn't find cf_ole_priv_data\n");
815 static void test_set_clipboard(void)
817 HRESULT hr;
818 ULONG ref;
819 LPDATAOBJECT data1, data2, data_cmpl;
820 HGLOBAL hblob, h;
822 cf_stream = RegisterClipboardFormatA("stream format");
823 cf_storage = RegisterClipboardFormatA("storage format");
824 cf_global = RegisterClipboardFormatA("global format");
825 cf_another = RegisterClipboardFormatA("another format");
826 cf_onemore = RegisterClipboardFormatA("one more format");
828 hr = DataObjectImpl_CreateText("data1", &data1);
829 ok(hr == S_OK, "Failed to create data1 object: 0x%08x\n", hr);
830 if(FAILED(hr))
831 return;
832 hr = DataObjectImpl_CreateText("data2", &data2);
833 ok(hr == S_OK, "Failed to create data2 object: 0x%08x\n", hr);
834 if(FAILED(hr))
835 return;
836 hr = DataObjectImpl_CreateComplex(&data_cmpl);
837 ok(hr == S_OK, "Failed to create complex data object: 0x%08x\n", hr);
838 if(FAILED(hr))
839 return;
841 hr = OleSetClipboard(data1);
842 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
844 CoInitialize(NULL);
845 hr = OleSetClipboard(data1);
846 ok(hr == CO_E_NOTINITIALIZED ||
847 hr == CLIPBRD_E_CANT_SET, /* win9x */
848 "OleSetClipboard should have failed with "
849 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr);
850 CoUninitialize();
852 hr = OleInitialize(NULL);
853 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
855 hr = OleSetClipboard(data1);
856 ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr);
858 test_cf_dataobject(data1);
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);
867 test_get_clipboard();
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);
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 OpenClipboard(NULL);
882 h = SetClipboardData(cf_onemore, hblob);
883 ok(h == hblob, "got %p\n", h);
884 h = GetClipboardData(cf_onemore);
885 ok(h == hblob ||
886 broken(h != NULL), /* win9x */
887 "got %p\n", h);
888 CloseClipboard();
890 hr = OleFlushClipboard();
891 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
892 hr = OleIsCurrentClipboard(data1);
893 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
894 hr = OleIsCurrentClipboard(data2);
895 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
896 hr = OleIsCurrentClipboard(NULL);
897 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
899 /* format should survive the flush */
900 OpenClipboard(NULL);
901 h = GetClipboardData(cf_onemore);
902 ok(h == hblob ||
903 broken(h != NULL), /* win9x */
904 "got %p\n", h);
905 CloseClipboard();
907 test_cf_dataobject(NULL);
909 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
911 OpenClipboard(NULL);
912 h = GetClipboardData(cf_onemore);
913 ok(h == NULL, "got %p\n", h);
914 CloseClipboard();
916 trace("setting complex\n");
917 hr = OleSetClipboard(data_cmpl);
918 ok(hr == S_OK, "failed to set clipboard to complex data, hr = 0x%08x\n", hr);
919 test_cf_dataobject(data_cmpl);
920 test_enum_fmtetc(data_cmpl);
922 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
924 test_no_cf_dataobject();
925 test_enum_fmtetc(NULL);
927 ref = IDataObject_Release(data1);
928 ok(ref == 0, "expected data1 ref=0, got %d\n", ref);
929 ref = IDataObject_Release(data2);
930 ok(ref == 0, "expected data2 ref=0, got %d\n", ref);
931 ref = IDataObject_Release(data_cmpl);
932 ok(ref == 0, "expected data_cmpl ref=0, got %d\n", ref);
934 OleUninitialize();
937 static inline ULONG count_refs(IDataObject *d)
939 IDataObject_AddRef(d);
940 return IDataObject_Release(d);
943 static void test_consumer_refs(void)
945 HRESULT hr;
946 IDataObject *src, *src2, *get1, *get2, *get3;
947 ULONG refs, old_refs;
948 FORMATETC fmt;
949 STGMEDIUM med;
951 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
953 OleInitialize(NULL);
955 /* First show that each clipboard state results in
956 a different data object */
958 hr = DataObjectImpl_CreateText("data1", &src);
959 ok(hr == S_OK, "got %08x\n", hr);
960 hr = DataObjectImpl_CreateText("data2", &src2);
961 ok(hr == S_OK, "got %08x\n", hr);
963 hr = OleSetClipboard(src);
964 ok(hr == S_OK, "got %08x\n", hr);
966 hr = OleGetClipboard(&get1);
967 ok(hr == S_OK, "got %08x\n", hr);
969 hr = OleGetClipboard(&get2);
970 ok(hr == S_OK, "got %08x\n", hr);
972 ok(get1 == get2 ||
973 broken(get1 != get2), /* win9x, winme & nt4 */
974 "data objects differ\n");
975 refs = IDataObject_Release(get2);
976 ok(refs == (get1 == get2 ? 1 : 0), "got %d\n", refs);
978 OleFlushClipboard();
980 DataObjectImpl_GetData_calls = 0;
981 hr = IDataObject_GetData(get1, &fmt, &med);
982 ok(hr == S_OK, "got %08x\n", hr);
983 ok(DataObjectImpl_GetData_calls == 0, "GetData called\n");
984 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
986 hr = OleGetClipboard(&get2);
987 ok(hr == S_OK, "got %08x\n", hr);
989 ok(get1 != get2, "data objects match\n");
991 OleSetClipboard(NULL);
993 hr = OleGetClipboard(&get3);
994 ok(hr == S_OK, "got %08x\n", hr);
996 ok(get1 != get3, "data objects match\n");
997 ok(get2 != get3, "data objects match\n");
999 IDataObject_Release(get3);
1000 IDataObject_Release(get2);
1001 IDataObject_Release(get1);
1003 /* Now call GetData before the flush and show that this
1004 takes a ref on our src data obj. */
1006 hr = OleSetClipboard(src);
1007 ok(hr == S_OK, "got %08x\n", hr);
1009 old_refs = count_refs(src);
1011 hr = OleGetClipboard(&get1);
1012 ok(hr == S_OK, "got %08x\n", hr);
1014 refs = count_refs(src);
1015 ok(refs == old_refs, "%d %d\n", refs, old_refs);
1017 DataObjectImpl_GetData_calls = 0;
1018 hr = IDataObject_GetData(get1, &fmt, &med);
1019 ok(hr == S_OK, "got %08x\n", hr);
1020 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1021 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1022 refs = count_refs(src);
1023 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1025 OleFlushClipboard();
1027 DataObjectImpl_GetData_calls = 0;
1028 hr = IDataObject_GetData(get1, &fmt, &med);
1029 ok(hr == S_OK, "got %08x\n", hr);
1030 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1031 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1033 refs = count_refs(src);
1034 ok(refs == 2, "%d\n", refs);
1036 IDataObject_Release(get1);
1038 refs = count_refs(src);
1039 ok(refs == 1, "%d\n", refs);
1041 /* Now set a second src object before the call to GetData
1042 and show that GetData calls that second src. */
1044 hr = OleSetClipboard(src);
1045 ok(hr == S_OK, "got %08x\n", hr);
1047 old_refs = count_refs(src);
1049 hr = OleGetClipboard(&get1);
1050 ok(hr == S_OK, "got %08x\n", hr);
1052 refs = count_refs(src);
1053 ok(refs == old_refs, "%d %d\n", refs, old_refs);
1055 hr = OleSetClipboard(src2);
1056 ok(hr == S_OK, "got %08x\n", hr);
1058 old_refs = count_refs(src2);
1060 DataObjectImpl_GetData_calls = 0;
1061 hr = IDataObject_GetData(get1, &fmt, &med);
1062 ok(hr == S_OK, "got %08x\n", hr);
1063 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1064 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1066 refs = count_refs(src);
1067 ok(refs == 1, "%d\n", refs);
1068 refs = count_refs(src2);
1069 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1071 OleSetClipboard(NULL);
1073 refs = count_refs(src2);
1074 ok(refs == 2, "%d\n", refs);
1076 IDataObject_Release(get1);
1078 IDataObject_Release(src2);
1079 IDataObject_Release(src);
1081 OleUninitialize();
1084 static void test_flushed_getdata(void)
1086 HRESULT hr;
1087 IDataObject *src, *get;
1088 FORMATETC fmt;
1089 STGMEDIUM med;
1090 STATSTG stat;
1091 DEVMODEW dm;
1093 OleInitialize(NULL);
1095 hr = DataObjectImpl_CreateComplex(&src);
1096 ok(hr == S_OK, "got %08x\n", hr);
1098 hr = OleSetClipboard(src);
1099 ok(hr == S_OK, "got %08x\n", hr);
1101 hr = OleFlushClipboard();
1102 ok(hr == S_OK, "got %08x\n", hr);
1104 hr = OleGetClipboard(&get);
1105 ok(hr == S_OK, "got %08x\n", hr);
1107 /* global format -> global & stream */
1109 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1110 hr = IDataObject_GetData(get, &fmt, &med);
1111 ok(hr == S_OK, "got %08x\n", hr);
1112 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1113 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1115 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTREAM);
1116 hr = IDataObject_GetData(get, &fmt, &med);
1117 ok(hr == S_OK, "got %08x\n", hr);
1118 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1119 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1121 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTORAGE);
1122 hr = IDataObject_GetData(get, &fmt, &med);
1123 ok(hr == E_FAIL, "got %08x\n", hr);
1124 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1126 InitFormatEtc(fmt, CF_TEXT, 0xffff);
1127 hr = IDataObject_GetData(get, &fmt, &med);
1128 ok(hr == S_OK, "got %08x\n", hr);
1129 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1130 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1132 /* stream format -> global & stream */
1134 InitFormatEtc(fmt, cf_stream, TYMED_ISTREAM);
1135 hr = IDataObject_GetData(get, &fmt, &med);
1136 ok(hr == S_OK, "got %08x\n", hr);
1137 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1138 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1140 InitFormatEtc(fmt, cf_stream, TYMED_ISTORAGE);
1141 hr = IDataObject_GetData(get, &fmt, &med);
1142 ok(hr == E_FAIL, "got %08x\n", hr);
1143 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1145 InitFormatEtc(fmt, cf_stream, TYMED_HGLOBAL);
1146 hr = IDataObject_GetData(get, &fmt, &med);
1147 ok(hr == S_OK, "got %08x\n", hr);
1148 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1149 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1151 InitFormatEtc(fmt, cf_stream, 0xffff);
1152 hr = IDataObject_GetData(get, &fmt, &med);
1153 ok(hr == S_OK, "got %08x\n", hr);
1154 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1155 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1157 /* storage format -> global, stream & storage */
1159 InitFormatEtc(fmt, cf_storage, TYMED_ISTORAGE);
1160 hr = IDataObject_GetData(get, &fmt, &med);
1161 ok(hr == S_OK, "got %08x\n", hr);
1162 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1163 if(SUCCEEDED(hr)) {
1164 hr = IStorage_Stat(med.u.pstg, &stat, STATFLAG_NONAME);
1165 ok(hr == S_OK, "got %08x\n", hr);
1166 ok(stat.grfMode == (STGM_SHARE_EXCLUSIVE | STGM_READWRITE), "got %08x\n", stat.grfMode);
1167 ReleaseStgMedium(&med);
1170 InitFormatEtc(fmt, cf_storage, TYMED_ISTREAM);
1171 hr = IDataObject_GetData(get, &fmt, &med);
1172 ok(hr == S_OK, "got %08x\n", hr);
1173 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1174 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1176 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL);
1177 hr = IDataObject_GetData(get, &fmt, &med);
1178 ok(hr == S_OK, "got %08x\n", hr);
1179 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1180 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1182 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL | TYMED_ISTREAM);
1183 hr = IDataObject_GetData(get, &fmt, &med);
1184 ok(hr == S_OK, "got %08x\n", hr);
1185 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1186 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1188 InitFormatEtc(fmt, cf_storage, 0xffff);
1189 hr = IDataObject_GetData(get, &fmt, &med);
1190 ok(hr == S_OK, "got %08x\n", hr);
1191 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1192 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1194 /* complex format with target device */
1196 InitFormatEtc(fmt, cf_another, 0xffff);
1197 hr = IDataObject_GetData(get, &fmt, &med);
1198 ok(hr == S_OK, "got %08x\n", hr);
1199 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1201 if (0) /* Causes crashes on both Wine and Windows */
1203 InitFormatEtc(fmt, cf_another, 0xffff);
1204 memset(&dm, 0, sizeof(dm));
1205 dm.dmSize = sizeof(dm);
1206 dm.dmDriverExtra = 0;
1207 lstrcpyW(dm.dmDeviceName, device_name);
1208 fmt.ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
1209 fmt.ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
1210 fmt.ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
1211 fmt.ptd->tdDeviceNameOffset = 0;
1212 fmt.ptd->tdPortNameOffset = 0;
1213 fmt.ptd->tdExtDevmodeOffset = fmt.ptd->tdDriverNameOffset + sizeof(device_name);
1214 lstrcpyW((WCHAR*)fmt.ptd->tdData, device_name);
1215 memcpy(fmt.ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
1217 hr = IDataObject_GetData(get, &fmt, &med);
1218 ok(hr == S_OK, "got %08x\n", hr);
1219 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1220 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1222 HeapFree(GetProcessHeap(), 0, fmt.ptd);
1226 IDataObject_Release(get);
1227 IDataObject_Release(src);
1228 OleUninitialize();
1231 static HGLOBAL create_text(void)
1233 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5);
1234 char *p = GlobalLock(h);
1235 strcpy(p, "test");
1236 GlobalUnlock(h);
1237 return h;
1240 static HENHMETAFILE create_emf(void)
1242 const RECT rect = {0, 0, 100, 100};
1243 HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1244 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
1245 return CloseEnhMetaFile(hdc);
1248 static void test_nonole_clipboard(void)
1250 HRESULT hr;
1251 BOOL r;
1252 IDataObject *get;
1253 IEnumFORMATETC *enum_fmt;
1254 FORMATETC fmt;
1255 HGLOBAL h, hblob, htext;
1256 HENHMETAFILE emf;
1257 STGMEDIUM med;
1258 DWORD obj_type;
1260 r = OpenClipboard(NULL);
1261 ok(r, "gle %d\n", GetLastError());
1262 r = EmptyClipboard();
1263 ok(r, "gle %d\n", GetLastError());
1264 r = CloseClipboard();
1265 ok(r, "gle %d\n", GetLastError());
1267 OleInitialize(NULL);
1269 /* empty clipboard */
1270 hr = OleGetClipboard(&get);
1271 ok(hr == S_OK, "got %08x\n", hr);
1272 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1273 ok(hr == S_OK, "got %08x\n", hr);
1275 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1276 ok(hr == S_FALSE, "got %08x\n", hr);
1277 IEnumFORMATETC_Release(enum_fmt);
1279 IDataObject_Release(get);
1281 /* set a user defined clipboard type */
1283 htext = create_text();
1284 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
1285 emf = create_emf();
1287 r = OpenClipboard(NULL);
1288 ok(r, "gle %d\n", GetLastError());
1289 h = SetClipboardData(CF_TEXT, htext);
1290 ok(h == htext, "got %p\n", h);
1291 h = SetClipboardData(cf_onemore, hblob);
1292 ok(h == hblob, "got %p\n", h);
1293 h = SetClipboardData(CF_ENHMETAFILE, emf);
1294 ok(h == emf, "got %p\n", h);
1295 r = CloseClipboard();
1296 ok(r, "gle %d\n", GetLastError());
1298 hr = OleGetClipboard(&get);
1299 ok(hr == S_OK, "got %08x\n", hr);
1300 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1301 ok(hr == S_OK, "got %08x\n", hr);
1303 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1304 ok(hr == S_OK, "got %08x\n", hr);
1305 ok(fmt.cfFormat == CF_TEXT, "cf %04x\n", fmt.cfFormat);
1306 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1307 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1308 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1309 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1311 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1312 ok(hr == S_OK, "got %08x\n", hr);
1313 ok(fmt.cfFormat == cf_onemore, "cf %04x\n", fmt.cfFormat);
1314 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1315 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1316 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1317 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1319 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1320 ok(hr == S_OK, "got %08x\n", hr);
1321 ok(fmt.cfFormat == CF_ENHMETAFILE, "cf %04x\n", fmt.cfFormat);
1322 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1323 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1324 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1325 ok(fmt.tymed == TYMED_ENHMF, "tymed %x\n", fmt.tymed);
1327 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1328 ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */
1330 todo_wine ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
1331 if(fmt.cfFormat == CF_LOCALE)
1333 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1334 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1335 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1336 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1338 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1339 ok(hr == S_OK, "got %08x\n", hr);
1342 ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat);
1343 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1344 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1345 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1346 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1348 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1349 ok(hr == S_OK, "got %08x\n", hr);
1350 ok(fmt.cfFormat == CF_UNICODETEXT ||
1351 broken(fmt.cfFormat == CF_METAFILEPICT), /* win9x and winme don't have CF_UNICODETEXT */
1352 "cf %04x\n", fmt.cfFormat);
1353 if(fmt.cfFormat == CF_UNICODETEXT)
1355 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1356 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1357 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1358 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1360 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1361 ok(hr == S_OK, "got %08x\n", hr);
1363 ok(fmt.cfFormat == CF_METAFILEPICT, "cf %04x\n", fmt.cfFormat);
1364 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1365 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1366 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1367 ok(fmt.tymed == TYMED_MFPICT, "tymed %x\n", fmt.tymed);
1369 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1370 ok(hr == S_FALSE, "got %08x\n", hr);
1371 IEnumFORMATETC_Release(enum_fmt);
1373 InitFormatEtc(fmt, CF_ENHMETAFILE, TYMED_ENHMF);
1374 hr = IDataObject_GetData(get, &fmt, &med);
1375 ok(hr == S_OK, "got %08x\n", hr);
1376 obj_type = GetObjectType(U(med).hEnhMetaFile);
1377 ok(obj_type == OBJ_ENHMETAFILE, "got %d\n", obj_type);
1378 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1380 IDataObject_Release(get);
1382 r = OpenClipboard(NULL);
1383 ok(r, "gle %d\n", GetLastError());
1384 r = EmptyClipboard();
1385 ok(r, "gle %d\n", GetLastError());
1386 r = CloseClipboard();
1387 ok(r, "gle %d\n", GetLastError());
1389 OleUninitialize();
1392 static void test_getdatahere(void)
1394 HRESULT hr;
1395 IDataObject *src, *get;
1396 FORMATETC fmt;
1397 STGMEDIUM med;
1399 OleInitialize(NULL);
1401 hr = DataObjectImpl_CreateComplex(&src);
1402 ok(hr == S_OK, "got %08x\n", hr);
1404 hr = OleSetClipboard(src);
1405 ok(hr == S_OK, "got %08x\n", hr);
1407 hr = OleGetClipboard(&get);
1408 ok(hr == S_OK, "got %08x\n", hr);
1410 /* global format -> global & stream */
1412 DataObjectImpl_GetData_calls = 0;
1413 DataObjectImpl_GetDataHere_calls = 0;
1415 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1417 med.pUnkForRelease = NULL;
1418 med.tymed = TYMED_HGLOBAL;
1419 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1420 hr = IDataObject_GetDataHere(get, &fmt, &med);
1421 ok(hr == S_OK, "got %08x\n", hr);
1422 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1423 ReleaseStgMedium(&med);
1424 ok(DataObjectImpl_GetDataHere_calls == 1, "called %d\n", DataObjectImpl_GetDataHere_calls);
1425 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1427 InitFormatEtc(fmt, CF_TEXT, 0);
1429 med.pUnkForRelease = NULL;
1430 med.tymed = TYMED_HGLOBAL;
1431 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1432 hr = IDataObject_GetDataHere(get, &fmt, &med);
1433 ok(hr == S_OK, "got %08x\n", hr);
1434 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1435 ReleaseStgMedium(&med);
1436 ok(DataObjectImpl_GetDataHere_calls == 2, "called %d\n", DataObjectImpl_GetDataHere_calls);
1437 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1439 med.pUnkForRelease = NULL;
1440 med.tymed = TYMED_HGLOBAL;
1441 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 1);
1442 hr = IDataObject_GetDataHere(get, &fmt, &med);
1443 ok(hr == E_FAIL, "got %08x\n", hr);
1444 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1445 ReleaseStgMedium(&med);
1446 ok(DataObjectImpl_GetDataHere_calls == 3, "called %d\n", DataObjectImpl_GetDataHere_calls);
1447 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1449 med.pUnkForRelease = NULL;
1450 med.tymed = TYMED_ISTREAM;
1451 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1452 hr = IDataObject_GetDataHere(get, &fmt, &med);
1453 ok(hr == S_OK, "got %08x\n", hr);
1454 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1455 ReleaseStgMedium(&med);
1456 ok(DataObjectImpl_GetDataHere_calls == 4, "called %d\n", DataObjectImpl_GetDataHere_calls);
1457 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1459 med.pUnkForRelease = NULL;
1460 med.tymed = TYMED_ISTORAGE;
1461 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1462 hr = IDataObject_GetDataHere(get, &fmt, &med);
1463 ok(hr == E_FAIL, "got %08x\n", hr);
1464 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1465 ReleaseStgMedium(&med);
1466 ok(DataObjectImpl_GetDataHere_calls == 5, "called %d\n", DataObjectImpl_GetDataHere_calls);
1467 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1469 InitFormatEtc(fmt, cf_stream, 0);
1471 med.pUnkForRelease = NULL;
1472 med.tymed = TYMED_HGLOBAL;
1473 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1474 hr = IDataObject_GetDataHere(get, &fmt, &med);
1475 ok(hr == S_OK, "got %08x\n", hr);
1476 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1477 ReleaseStgMedium(&med);
1478 ok(DataObjectImpl_GetDataHere_calls == 7, "called %d\n", DataObjectImpl_GetDataHere_calls);
1479 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1481 med.pUnkForRelease = NULL;
1482 med.tymed = TYMED_ISTREAM;
1483 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1484 hr = IDataObject_GetDataHere(get, &fmt, &med);
1485 ok(hr == S_OK, "got %08x\n", hr);
1486 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1487 ReleaseStgMedium(&med);
1488 ok(DataObjectImpl_GetDataHere_calls == 8, "called %d\n", DataObjectImpl_GetDataHere_calls);
1489 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1491 med.pUnkForRelease = NULL;
1492 med.tymed = TYMED_ISTORAGE;
1493 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1494 hr = IDataObject_GetDataHere(get, &fmt, &med);
1495 ok(hr == E_FAIL, "got %08x\n", hr);
1496 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1497 ReleaseStgMedium(&med);
1498 ok(DataObjectImpl_GetDataHere_calls == 9, "called %d\n", DataObjectImpl_GetDataHere_calls);
1499 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1501 InitFormatEtc(fmt, cf_storage, 0);
1503 med.pUnkForRelease = NULL;
1504 med.tymed = TYMED_HGLOBAL;
1505 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 3000);
1506 hr = IDataObject_GetDataHere(get, &fmt, &med);
1507 ok(hr == S_OK, "got %08x\n", hr);
1508 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1509 ReleaseStgMedium(&med);
1510 ok(DataObjectImpl_GetDataHere_calls == 11, "called %d\n", DataObjectImpl_GetDataHere_calls);
1511 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1513 med.pUnkForRelease = NULL;
1514 med.tymed = TYMED_ISTREAM;
1515 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1516 hr = IDataObject_GetDataHere(get, &fmt, &med);
1517 ok(hr == S_OK, "got %08x\n", hr);
1518 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1519 ReleaseStgMedium(&med);
1520 ok(DataObjectImpl_GetDataHere_calls == 12, "called %d\n", DataObjectImpl_GetDataHere_calls);
1521 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1523 med.pUnkForRelease = NULL;
1524 med.tymed = TYMED_ISTORAGE;
1525 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1526 hr = IDataObject_GetDataHere(get, &fmt, &med);
1527 ok(hr == S_OK, "got %08x\n", hr);
1528 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1529 ReleaseStgMedium(&med);
1530 ok(DataObjectImpl_GetDataHere_calls == 13, "called %d\n", DataObjectImpl_GetDataHere_calls);
1531 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1534 IDataObject_Release(get);
1535 IDataObject_Release(src);
1537 OleUninitialize();
1541 START_TEST(clipboard)
1543 test_set_clipboard();
1544 test_consumer_refs();
1545 test_flushed_getdata();
1546 test_nonole_clipboard();
1547 test_getdatahere();