ole32/tests: Rename variable to avoid a conflict on some systems.
[wine/hacks.git] / dlls / ole32 / tests / clipboard.c
bloba64fa2355e5dd7b2aeff9c9214df6599364cef7e
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 NONAMELESSUNION
24 #include <stdarg.h>
25 #include <stdio.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "objbase.h"
31 #include "wine/test.h"
33 #define InitFormatEtc(fe, cf, med) \
35 (fe).cfFormat=cf;\
36 (fe).dwAspect=DVASPECT_CONTENT;\
37 (fe).ptd=NULL;\
38 (fe).tymed=med;\
39 (fe).lindex=-1;\
42 static inline char *dump_fmtetc(FORMATETC *fmt)
44 static char buf[100];
46 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
47 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
48 return buf;
51 typedef struct DataObjectImpl {
52 const IDataObjectVtbl *lpVtbl;
53 LONG ref;
55 FORMATETC *fmtetc;
56 UINT fmtetc_cnt;
58 HANDLE text;
59 IStream *stm;
60 IStorage *stg;
61 } DataObjectImpl;
63 typedef struct EnumFormatImpl {
64 const IEnumFORMATETCVtbl *lpVtbl;
65 LONG ref;
67 FORMATETC *fmtetc;
68 UINT fmtetc_cnt;
70 UINT cur;
71 } EnumFormatImpl;
73 static BOOL expect_DataObjectImpl_QueryGetData = TRUE;
74 static ULONG DataObjectImpl_GetData_calls = 0;
75 static ULONG DataObjectImpl_GetDataHere_calls = 0;
76 static ULONG DataObjectImpl_EnumFormatEtc_calls = 0;
78 static UINT cf_stream, cf_storage, cf_global, cf_another, cf_onemore;
80 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
82 static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
84 EnumFormatImpl *This = (EnumFormatImpl*)iface;
86 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) {
87 IEnumFORMATETC_AddRef(iface);
88 *ppvObj = This;
89 return S_OK;
91 *ppvObj = NULL;
92 return E_NOINTERFACE;
95 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
97 EnumFormatImpl *This = (EnumFormatImpl*)iface;
98 LONG ref = InterlockedIncrement(&This->ref);
99 return ref;
102 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
104 EnumFormatImpl *This = (EnumFormatImpl*)iface;
105 ULONG ref = InterlockedDecrement(&This->ref);
107 if(!ref) {
108 HeapFree(GetProcessHeap(), 0, This->fmtetc);
109 HeapFree(GetProcessHeap(), 0, This);
112 return ref;
115 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
116 FORMATETC *rgelt, ULONG *pceltFetched)
118 EnumFormatImpl *This = (EnumFormatImpl*)iface;
119 ULONG count, i;
121 if(!rgelt)
122 return E_INVALIDARG;
124 count = min(celt, This->fmtetc_cnt - This->cur);
125 for(i = 0; i < count; i++, This->cur++, rgelt++)
127 *rgelt = This->fmtetc[This->cur];
128 if(rgelt->ptd)
130 DWORD size = This->fmtetc[This->cur].ptd->tdSize;
131 rgelt->ptd = CoTaskMemAlloc(size);
132 memcpy(rgelt->ptd, This->fmtetc[This->cur].ptd, size);
135 if(pceltFetched)
136 *pceltFetched = count;
137 return count == celt ? S_OK : S_FALSE;
140 static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt)
142 ok(0, "unexpected call\n");
143 return E_NOTIMPL;
146 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
148 EnumFormatImpl *This = (EnumFormatImpl*)iface;
150 This->cur = 0;
151 return S_OK;
154 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
156 ok(0, "unexpected call\n");
157 return E_NOTIMPL;
160 static const IEnumFORMATETCVtbl VT_EnumFormatImpl = {
161 EnumFormatImpl_QueryInterface,
162 EnumFormatImpl_AddRef,
163 EnumFormatImpl_Release,
164 EnumFormatImpl_Next,
165 EnumFormatImpl_Skip,
166 EnumFormatImpl_Reset,
167 EnumFormatImpl_Clone
170 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
172 EnumFormatImpl *ret;
174 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl));
175 ret->lpVtbl = &VT_EnumFormatImpl;
176 ret->ref = 1;
177 ret->cur = 0;
178 ret->fmtetc_cnt = fmtetc_cnt;
179 ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC));
180 memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
181 *lplpformatetc = (LPENUMFORMATETC)ret;
182 return S_OK;
185 static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj)
187 DataObjectImpl *This = (DataObjectImpl*)iface;
189 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) {
190 IDataObject_AddRef(iface);
191 *ppvObj = This;
192 return S_OK;
194 *ppvObj = NULL;
195 return E_NOINTERFACE;
198 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
200 DataObjectImpl *This = (DataObjectImpl*)iface;
201 ULONG ref = InterlockedIncrement(&This->ref);
202 return ref;
205 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
207 DataObjectImpl *This = (DataObjectImpl*)iface;
208 ULONG ref = InterlockedDecrement(&This->ref);
210 if(!ref)
212 int i;
213 if(This->text) GlobalFree(This->text);
214 for(i = 0; i < This->fmtetc_cnt; i++)
215 HeapFree(GetProcessHeap(), 0, This->fmtetc[i].ptd);
216 HeapFree(GetProcessHeap(), 0, This->fmtetc);
217 if(This->stm) IStream_Release(This->stm);
218 if(This->stg) IStorage_Release(This->stg);
219 HeapFree(GetProcessHeap(), 0, This);
222 return ref;
225 static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
227 DataObjectImpl *This = (DataObjectImpl*)iface;
228 UINT i;
229 BOOL foundFormat = FALSE;
231 trace("getdata: %s\n", dump_fmtetc(pformatetc));
233 DataObjectImpl_GetData_calls++;
235 if(pformatetc->lindex != -1)
236 return DV_E_FORMATETC;
238 for(i = 0; i < This->fmtetc_cnt; i++)
240 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat)
242 foundFormat = TRUE;
243 if(This->fmtetc[i].tymed & pformatetc->tymed)
245 pmedium->pUnkForRelease = (LPUNKNOWN)iface;
246 IUnknown_AddRef(pmedium->pUnkForRelease);
248 if(pformatetc->cfFormat == CF_TEXT || pformatetc->cfFormat == cf_global)
250 pmedium->tymed = TYMED_HGLOBAL;
251 U(*pmedium).hGlobal = This->text;
253 else if(pformatetc->cfFormat == cf_stream)
255 pmedium->tymed = TYMED_ISTREAM;
256 IStream_AddRef(This->stm);
257 U(*pmedium).pstm = This->stm;
259 else if(pformatetc->cfFormat == cf_storage || pformatetc->cfFormat == cf_another)
261 pmedium->tymed = TYMED_ISTORAGE;
262 IStorage_AddRef(This->stg);
263 U(*pmedium).pstg = This->stg;
265 return S_OK;
270 return foundFormat ? DV_E_TYMED : DV_E_FORMATETC;
273 static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
275 trace("getdatahere: %s\n", dump_fmtetc(pformatetc));
276 DataObjectImpl_GetDataHere_calls++;
278 return E_NOTIMPL;
281 static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc)
283 DataObjectImpl *This = (DataObjectImpl*)iface;
284 UINT i;
285 BOOL foundFormat = FALSE;
287 trace("querygetdata: %s\n", dump_fmtetc(pformatetc));
288 if (!expect_DataObjectImpl_QueryGetData)
289 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
291 if(pformatetc->lindex != -1)
292 return DV_E_LINDEX;
294 for(i=0; i<This->fmtetc_cnt; i++) {
295 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) {
296 foundFormat = TRUE;
297 if(This->fmtetc[i].tymed == pformatetc->tymed)
298 return S_OK;
301 return foundFormat?DV_E_FORMATETC:DV_E_TYMED;
304 static HRESULT WINAPI DataObjectImpl_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC *pformatectIn,
305 FORMATETC *pformatetcOut)
307 ok(0, "unexpected call\n");
308 return E_NOTIMPL;
311 static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc,
312 STGMEDIUM *pmedium, BOOL fRelease)
314 ok(0, "unexpected call\n");
315 return E_NOTIMPL;
318 static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwDirection,
319 IEnumFORMATETC **ppenumFormatEtc)
321 DataObjectImpl *This = (DataObjectImpl*)iface;
323 DataObjectImpl_EnumFormatEtc_calls++;
325 if(dwDirection != DATADIR_GET) {
326 ok(0, "unexpected direction %d\n", dwDirection);
327 return E_NOTIMPL;
329 return EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenumFormatEtc);
332 static HRESULT WINAPI DataObjectImpl_DAdvise(IDataObject* iface, FORMATETC *pformatetc, DWORD advf,
333 IAdviseSink *pAdvSink, DWORD *pdwConnection)
335 ok(0, "unexpected call\n");
336 return E_NOTIMPL;
339 static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection)
341 ok(0, "unexpected call\n");
342 return E_NOTIMPL;
345 static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise)
347 ok(0, "unexpected call\n");
348 return E_NOTIMPL;
351 static const IDataObjectVtbl VT_DataObjectImpl =
353 DataObjectImpl_QueryInterface,
354 DataObjectImpl_AddRef,
355 DataObjectImpl_Release,
356 DataObjectImpl_GetData,
357 DataObjectImpl_GetDataHere,
358 DataObjectImpl_QueryGetData,
359 DataObjectImpl_GetCanonicalFormatEtc,
360 DataObjectImpl_SetData,
361 DataObjectImpl_EnumFormatEtc,
362 DataObjectImpl_DAdvise,
363 DataObjectImpl_DUnadvise,
364 DataObjectImpl_EnumDAdvise
367 static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
369 DataObjectImpl *obj;
371 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
372 obj->lpVtbl = &VT_DataObjectImpl;
373 obj->ref = 1;
374 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1);
375 strcpy(GlobalLock(obj->text), text);
376 GlobalUnlock(obj->text);
377 obj->stm = NULL;
378 obj->stg = NULL;
380 obj->fmtetc_cnt = 1;
381 obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
382 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
384 *lplpdataobj = (LPDATAOBJECT)obj;
385 return S_OK;
388 const char *cmpl_stm_data = "complex stream";
389 const char *cmpl_text_data = "complex text";
390 const WCHAR device_name[] = {'m','y','d','e','v',0};
392 static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj)
394 DataObjectImpl *obj;
395 ILockBytes *lbs;
396 DEVMODEW dm;
398 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
399 obj->lpVtbl = &VT_DataObjectImpl;
400 obj->ref = 1;
401 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(cmpl_text_data) + 1);
402 strcpy(GlobalLock(obj->text), cmpl_text_data);
403 GlobalUnlock(obj->text);
404 CreateStreamOnHGlobal(NULL, TRUE, &obj->stm);
405 IStream_Write(obj->stm, cmpl_stm_data, strlen(cmpl_stm_data), NULL);
407 CreateILockBytesOnHGlobal(NULL, TRUE, &lbs);
408 StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &obj->stg);
409 ILockBytes_Release(lbs);
411 obj->fmtetc_cnt = 8;
412 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
413 obj->fmtetc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, obj->fmtetc_cnt*sizeof(FORMATETC));
414 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
415 InitFormatEtc(obj->fmtetc[1], cf_stream, TYMED_ISTREAM);
416 InitFormatEtc(obj->fmtetc[2], cf_storage, TYMED_ISTORAGE);
417 InitFormatEtc(obj->fmtetc[3], cf_another, TYMED_ISTORAGE|TYMED_ISTREAM|TYMED_HGLOBAL);
418 memset(&dm, 0, sizeof(dm));
419 dm.dmSize = sizeof(dm);
420 dm.dmDriverExtra = 0;
421 lstrcpyW(dm.dmDeviceName, device_name);
422 obj->fmtetc[3].ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
423 obj->fmtetc[3].ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
424 obj->fmtetc[3].ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
425 obj->fmtetc[3].ptd->tdDeviceNameOffset = 0;
426 obj->fmtetc[3].ptd->tdPortNameOffset = 0;
427 obj->fmtetc[3].ptd->tdExtDevmodeOffset = obj->fmtetc[3].ptd->tdDriverNameOffset + sizeof(device_name);
428 lstrcpyW((WCHAR*)obj->fmtetc[3].ptd->tdData, device_name);
429 memcpy(obj->fmtetc[3].ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
431 InitFormatEtc(obj->fmtetc[4], cf_global, TYMED_HGLOBAL);
432 InitFormatEtc(obj->fmtetc[5], cf_another, TYMED_HGLOBAL);
433 InitFormatEtc(obj->fmtetc[6], cf_another, 0xfffff);
434 InitFormatEtc(obj->fmtetc[7], cf_another, 0xfffff);
435 obj->fmtetc[7].dwAspect = DVASPECT_ICON;
437 *lplpdataobj = (LPDATAOBJECT)obj;
438 return S_OK;
441 static void test_get_clipboard(void)
443 HRESULT hr;
444 IDataObject *data_obj;
445 FORMATETC fmtetc;
446 STGMEDIUM stgmedium;
448 hr = OleGetClipboard(NULL);
449 ok(hr == E_INVALIDARG, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr);
451 hr = OleGetClipboard(&data_obj);
452 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
454 /* test IDataObject_QueryGetData */
456 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
457 expect_DataObjectImpl_QueryGetData = FALSE;
459 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
460 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
461 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
463 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
464 fmtetc.dwAspect = 0xdeadbeef;
465 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
466 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
468 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
469 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
470 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
471 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
473 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
474 fmtetc.lindex = 256;
475 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
476 ok(hr == DV_E_FORMATETC || broken(hr == S_OK),
477 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
478 if (hr == S_OK)
479 ReleaseStgMedium(&stgmedium);
481 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
482 fmtetc.cfFormat = CF_RIFF;
483 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
484 ok(hr == DV_E_CLIPFORMAT, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr);
486 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
487 fmtetc.tymed = TYMED_FILE;
488 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
489 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
491 expect_DataObjectImpl_QueryGetData = TRUE;
493 /* test IDataObject_GetData */
495 DataObjectImpl_GetData_calls = 0;
497 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
498 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
499 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
500 ReleaseStgMedium(&stgmedium);
502 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
503 fmtetc.dwAspect = 0xdeadbeef;
504 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
505 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
506 ReleaseStgMedium(&stgmedium);
508 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
509 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
510 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
511 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
512 ReleaseStgMedium(&stgmedium);
514 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
515 fmtetc.lindex = 256;
516 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
517 ok(hr == DV_E_FORMATETC || broken(hr == S_OK), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
518 if (hr == S_OK)
520 /* undo the unexpected success */
521 DataObjectImpl_GetData_calls--;
522 ReleaseStgMedium(&stgmedium);
525 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
526 fmtetc.cfFormat = CF_RIFF;
527 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
528 ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
530 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
531 fmtetc.tymed = TYMED_FILE;
532 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
533 ok(hr == DV_E_TYMED, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr);
535 ok(DataObjectImpl_GetData_calls == 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls);
537 IDataObject_Release(data_obj);
540 static void test_enum_fmtetc(IDataObject *src)
542 HRESULT hr;
543 IDataObject *data;
544 IEnumFORMATETC *enum_fmt, *src_enum;
545 FORMATETC fmt, src_fmt;
546 DWORD count = 0;
548 hr = OleGetClipboard(&data);
549 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
551 hr = IDataObject_EnumFormatEtc(data, DATADIR_SET, &enum_fmt);
552 ok(hr == E_NOTIMPL ||
553 broken(hr == E_INVALIDARG), /* win98 (not win98SE) */
554 "got %08x\n", hr);
556 DataObjectImpl_EnumFormatEtc_calls = 0;
557 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
558 ok(hr == S_OK, "got %08x\n", hr);
559 ok(DataObjectImpl_EnumFormatEtc_calls == 0, "EnumFormatEtc was called\n");
561 if(src) IDataObject_EnumFormatEtc(src, DATADIR_GET, &src_enum);
563 while((hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL)) == S_OK)
565 ok(src != NULL, "shouldn't be here\n");
566 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
567 ok(hr == S_OK, "%d: got %08x\n", count, hr);
568 trace("%d: cf %04x aspect %x tymed %x\n", count, fmt.cfFormat, fmt.dwAspect, fmt.tymed);
569 ok(fmt.cfFormat == src_fmt.cfFormat, "%d: %04x %04x\n", count, fmt.cfFormat, src_fmt.cfFormat);
570 ok(fmt.dwAspect == src_fmt.dwAspect, "%d: %08x %08x\n", count, fmt.dwAspect, src_fmt.dwAspect);
571 ok(fmt.lindex == src_fmt.lindex, "%d: %08x %08x\n", count, fmt.lindex, src_fmt.lindex);
572 ok(fmt.tymed == src_fmt.tymed, "%d: %08x %08x\n", count, fmt.tymed, src_fmt.tymed);
573 if(fmt.ptd)
575 ok(src_fmt.ptd != NULL, "%d: expected non-NULL\n", count);
576 CoTaskMemFree(fmt.ptd);
577 CoTaskMemFree(src_fmt.ptd);
579 count++;
582 ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
584 if(src)
586 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
587 ok(hr == S_FALSE ||
588 broken(hr == S_OK && count == 5), /* win9x and winme don't enumerate duplicated cf's */
589 "%d: got %08x\n", count, hr);
590 IEnumFORMATETC_Release(src_enum);
593 hr = IEnumFORMATETC_Reset(enum_fmt);
594 ok(hr == S_OK, "got %08x\n", hr);
596 if(src) /* Exercise the enumerator a bit */
598 IEnumFORMATETC *clone;
599 FORMATETC third_fmt;
601 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
602 ok(hr == S_OK, "got %08x\n", hr);
603 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
604 ok(hr == S_OK, "got %08x\n", hr);
605 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
606 ok(hr == S_OK, "got %08x\n", hr);
608 hr = IEnumFORMATETC_Reset(enum_fmt);
609 ok(hr == S_OK, "got %08x\n", hr);
610 hr = IEnumFORMATETC_Skip(enum_fmt, 2);
611 ok(hr == S_OK, "got %08x\n", hr);
613 hr = IEnumFORMATETC_Clone(enum_fmt, &clone);
614 ok(hr == S_OK, "got %08x\n", hr);
615 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
616 ok(hr == S_OK, "got %08x\n", hr);
617 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
618 hr = IEnumFORMATETC_Next(clone, 1, &fmt, NULL);
619 ok(hr == S_OK, "got %08x\n", hr);
620 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
621 IEnumFORMATETC_Release(clone);
624 IEnumFORMATETC_Release(enum_fmt);
625 IDataObject_Release(data);
628 static void test_no_cf_dataobject(void)
630 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
631 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
632 HANDLE h;
633 OpenClipboard(NULL);
635 h = GetClipboardData(cf_dataobject);
636 ok(!h, "got %p\n", h);
637 h = GetClipboardData(cf_ole_priv_data);
638 ok(!h, "got %p\n", h);
640 CloseClipboard();
643 static void test_cf_dataobject(IDataObject *data)
645 UINT cf = 0;
646 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
647 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
648 BOOL found_dataobject = FALSE, found_priv_data = FALSE;
650 OpenClipboard(NULL);
653 cf = EnumClipboardFormats(cf);
654 if(cf == cf_dataobject)
656 HGLOBAL h = GetClipboardData(cf);
657 HWND *ptr = GlobalLock(h);
658 DWORD size = GlobalSize(h);
659 HWND clip_owner = GetClipboardOwner();
661 found_dataobject = TRUE;
662 ok(size >= sizeof(*ptr), "size %d\n", size);
663 if(data)
664 ok(*ptr == clip_owner, "hwnd %p clip_owner %p\n", *ptr, clip_owner);
665 else /* ole clipboard flushed */
666 ok(*ptr == NULL, "hwnd %p\n", *ptr);
667 GlobalUnlock(h);
669 else if(cf == cf_ole_priv_data)
671 found_priv_data = TRUE;
672 if(data)
674 HGLOBAL h = GetClipboardData(cf);
675 DWORD *ptr = GlobalLock(h);
676 DWORD size = GlobalSize(h);
678 if(size != ptr[1])
679 win_skip("Ole Private Data in win9x format\n");
680 else
682 HRESULT hr;
683 IEnumFORMATETC *enum_fmt;
684 DWORD count = 0;
685 FORMATETC fmt;
686 struct formatetcetc
688 FORMATETC fmt;
689 BOOL first_use_of_cf;
690 DWORD res[2];
691 } *fmt_ptr;
692 struct priv_data
694 DWORD res1;
695 DWORD size;
696 DWORD res2;
697 DWORD count;
698 DWORD res3[2];
699 struct formatetcetc fmts[1];
700 } *priv = (struct priv_data*)ptr;
701 CLIPFORMAT cfs_seen[10];
703 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
704 ok(hr == S_OK, "got %08x\n", hr);
705 fmt_ptr = priv->fmts;
707 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
709 int i;
710 BOOL seen_cf = FALSE;
712 ok(fmt_ptr->fmt.cfFormat == fmt.cfFormat,
713 "got %08x expected %08x\n", fmt_ptr->fmt.cfFormat, fmt.cfFormat);
714 ok(fmt_ptr->fmt.dwAspect == fmt.dwAspect, "got %08x expected %08x\n",
715 fmt_ptr->fmt.dwAspect, fmt.dwAspect);
716 ok(fmt_ptr->fmt.lindex == fmt.lindex, "got %08x expected %08x\n",
717 fmt_ptr->fmt.lindex, fmt.lindex);
718 ok(fmt_ptr->fmt.tymed == fmt.tymed, "got %08x expected %08x\n",
719 fmt_ptr->fmt.tymed, fmt.tymed);
720 for(i = 0; i < count; i++)
721 if(fmt_ptr->fmt.cfFormat == cfs_seen[i])
723 seen_cf = TRUE;
724 break;
726 cfs_seen[count] = fmt.cfFormat;
727 ok(fmt_ptr->first_use_of_cf == seen_cf ? FALSE : TRUE, "got %08x expected %08x\n",
728 fmt_ptr->first_use_of_cf, !seen_cf);
729 ok(fmt_ptr->res[0] == 0, "got %08x\n", fmt_ptr->res[1]);
730 ok(fmt_ptr->res[1] == 0, "got %08x\n", fmt_ptr->res[2]);
731 if(fmt.ptd)
733 DVTARGETDEVICE *target;
735 ok(fmt_ptr->fmt.ptd != NULL, "target device offset zero\n");
736 target = (DVTARGETDEVICE*)((char*)priv + (DWORD)fmt_ptr->fmt.ptd);
737 ok(!memcmp(target, fmt.ptd, fmt.ptd->tdSize), "target devices differ\n");
738 CoTaskMemFree(fmt.ptd);
740 fmt_ptr++;
741 count++;
743 ok(priv->res1 == 0, "got %08x\n", priv->res1);
744 ok(priv->res2 == 1, "got %08x\n", priv->res2);
745 ok(priv->count == count, "got %08x expected %08x\n", priv->count, count);
746 ok(priv->res3[0] == 0, "got %08x\n", priv->res3[0]);
748 /* win64 sets the lsb */
749 if(sizeof(fmt_ptr->fmt.ptd) == 8)
750 todo_wine ok(priv->res3[1] == 1, "got %08x\n", priv->res3[1]);
751 else
752 ok(priv->res3[1] == 0, "got %08x\n", priv->res3[1]);
754 GlobalUnlock(h);
755 IEnumFORMATETC_Release(enum_fmt);
759 else if(cf == cf_stream)
761 HGLOBAL h;
762 void *ptr;
763 DWORD size;
765 DataObjectImpl_GetDataHere_calls = 0;
766 h = GetClipboardData(cf);
767 ok(DataObjectImpl_GetDataHere_calls == 1, "got %d\n", DataObjectImpl_GetDataHere_calls);
768 ptr = GlobalLock(h);
769 size = GlobalSize(h);
770 ok(size == strlen(cmpl_stm_data), "expected %d got %d\n", lstrlenA(cmpl_stm_data), size);
771 ok(!memcmp(ptr, cmpl_stm_data, size), "mismatch\n");
772 GlobalUnlock(h);
774 else if(cf == cf_global)
776 HGLOBAL h;
777 void *ptr;
778 DWORD size;
780 DataObjectImpl_GetDataHere_calls = 0;
781 h = GetClipboardData(cf);
782 ok(DataObjectImpl_GetDataHere_calls == 0, "got %d\n", DataObjectImpl_GetDataHere_calls);
783 ptr = GlobalLock(h);
784 size = GlobalSize(h);
785 ok(size == strlen(cmpl_text_data) + 1, "expected %d got %d\n", lstrlenA(cmpl_text_data) + 1, size);
786 ok(!memcmp(ptr, cmpl_text_data, size), "mismatch\n");
787 GlobalUnlock(h);
789 } while(cf);
790 CloseClipboard();
791 ok(found_dataobject, "didn't find cf_dataobject\n");
792 ok(found_priv_data, "didn't find cf_ole_priv_data\n");
795 static void test_set_clipboard(void)
797 HRESULT hr;
798 ULONG ref;
799 LPDATAOBJECT data1, data2, data_cmpl;
800 HGLOBAL hblob, h;
802 cf_stream = RegisterClipboardFormatA("stream format");
803 cf_storage = RegisterClipboardFormatA("storage format");
804 cf_global = RegisterClipboardFormatA("global format");
805 cf_another = RegisterClipboardFormatA("another format");
806 cf_onemore = RegisterClipboardFormatA("one more format");
808 hr = DataObjectImpl_CreateText("data1", &data1);
809 ok(SUCCEEDED(hr), "Failed to create data1 object: 0x%08x\n", hr);
810 if(FAILED(hr))
811 return;
812 hr = DataObjectImpl_CreateText("data2", &data2);
813 ok(SUCCEEDED(hr), "Failed to create data2 object: 0x%08x\n", hr);
814 if(FAILED(hr))
815 return;
816 hr = DataObjectImpl_CreateComplex(&data_cmpl);
817 ok(SUCCEEDED(hr), "Failed to create complex data object: 0x%08x\n", hr);
818 if(FAILED(hr))
819 return;
821 hr = OleSetClipboard(data1);
822 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
824 CoInitialize(NULL);
825 hr = OleSetClipboard(data1);
826 ok(hr == CO_E_NOTINITIALIZED ||
827 hr == CLIPBRD_E_CANT_SET, /* win9x */
828 "OleSetClipboard should have failed with "
829 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr);
830 CoUninitialize();
832 hr = OleInitialize(NULL);
833 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
835 hr = OleSetClipboard(data1);
836 ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr);
838 test_cf_dataobject(data1);
840 hr = OleIsCurrentClipboard(data1);
841 ok(hr == S_OK, "expected current clipboard to be data1, hr = 0x%08x\n", hr);
842 hr = OleIsCurrentClipboard(data2);
843 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
844 hr = OleIsCurrentClipboard(NULL);
845 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
847 test_get_clipboard();
849 hr = OleSetClipboard(data2);
850 ok(hr == S_OK, "failed to set clipboard to data2, hr = 0x%08x\n", hr);
851 hr = OleIsCurrentClipboard(data1);
852 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
853 hr = OleIsCurrentClipboard(data2);
854 ok(hr == S_OK, "expected current clipboard to be data2, hr = 0x%08x\n", hr);
855 hr = OleIsCurrentClipboard(NULL);
856 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
858 /* put a format directly onto the clipboard to show
859 OleFlushClipboard doesn't empty the clipboard */
860 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
861 OpenClipboard(NULL);
862 h = SetClipboardData(cf_onemore, hblob);
863 ok(h == hblob, "got %p\n", h);
864 h = GetClipboardData(cf_onemore);
865 ok(h == hblob ||
866 broken(h != NULL), /* win9x */
867 "got %p\n", h);
868 CloseClipboard();
870 hr = OleFlushClipboard();
871 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
872 hr = OleIsCurrentClipboard(data1);
873 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
874 hr = OleIsCurrentClipboard(data2);
875 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
876 hr = OleIsCurrentClipboard(NULL);
877 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
879 /* format should survive the flush */
880 OpenClipboard(NULL);
881 h = GetClipboardData(cf_onemore);
882 ok(h == hblob ||
883 broken(h != NULL), /* win9x */
884 "got %p\n", h);
885 CloseClipboard();
887 test_cf_dataobject(NULL);
889 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
891 OpenClipboard(NULL);
892 h = GetClipboardData(cf_onemore);
893 ok(h == NULL, "got %p\n", h);
894 CloseClipboard();
896 trace("setting complex\n");
897 hr = OleSetClipboard(data_cmpl);
898 ok(hr == S_OK, "failed to set clipboard to complex data, hr = 0x%08x\n", hr);
899 test_cf_dataobject(data_cmpl);
900 test_enum_fmtetc(data_cmpl);
902 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
904 test_no_cf_dataobject();
905 test_enum_fmtetc(NULL);
907 ref = IDataObject_Release(data1);
908 ok(ref == 0, "expected data1 ref=0, got %d\n", ref);
909 ref = IDataObject_Release(data2);
910 ok(ref == 0, "expected data2 ref=0, got %d\n", ref);
911 ref = IDataObject_Release(data_cmpl);
912 ok(ref == 0, "expected data_cmpl ref=0, got %d\n", ref);
914 OleUninitialize();
917 static inline ULONG count_refs(IDataObject *d)
919 IDataObject_AddRef(d);
920 return IDataObject_Release(d);
923 static void test_consumer_refs(void)
925 HRESULT hr;
926 IDataObject *src, *src2, *get1, *get2, *get3;
927 ULONG refs, old_refs;
928 FORMATETC fmt;
929 STGMEDIUM med;
931 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
933 OleInitialize(NULL);
935 /* First show that each clipboard state results in
936 a different data object */
938 hr = DataObjectImpl_CreateText("data1", &src);
939 ok(hr == S_OK, "got %08x\n", hr);
940 hr = DataObjectImpl_CreateText("data2", &src2);
941 ok(hr == S_OK, "got %08x\n", hr);
943 hr = OleSetClipboard(src);
944 ok(hr == S_OK, "got %08x\n", hr);
946 hr = OleGetClipboard(&get1);
947 ok(hr == S_OK, "got %08x\n", hr);
949 hr = OleGetClipboard(&get2);
950 ok(hr == S_OK, "got %08x\n", hr);
952 ok(get1 == get2 ||
953 broken(get1 != get2), /* win9x, winme & nt4 */
954 "data objects differ\n");
955 refs = IDataObject_Release(get2);
956 ok(refs == (get1 == get2 ? 1 : 0), "got %d\n", refs);
958 OleFlushClipboard();
960 DataObjectImpl_GetData_calls = 0;
961 hr = IDataObject_GetData(get1, &fmt, &med);
962 ok(hr == S_OK, "got %08x\n", hr);
963 ok(DataObjectImpl_GetData_calls == 0, "GetData called\n");
964 ReleaseStgMedium(&med);
966 hr = OleGetClipboard(&get2);
967 ok(hr == S_OK, "got %08x\n", hr);
969 ok(get1 != get2, "data objects match\n");
971 OleSetClipboard(NULL);
973 hr = OleGetClipboard(&get3);
974 ok(hr == S_OK, "got %08x\n", hr);
976 ok(get1 != get3, "data objects match\n");
977 ok(get2 != get3, "data objects match\n");
979 IDataObject_Release(get3);
980 IDataObject_Release(get2);
981 IDataObject_Release(get1);
983 /* Now call GetData before the flush and show that this
984 takes a ref on our src data obj. */
986 hr = OleSetClipboard(src);
987 ok(hr == S_OK, "got %08x\n", hr);
989 old_refs = count_refs(src);
991 hr = OleGetClipboard(&get1);
992 ok(hr == S_OK, "got %08x\n", hr);
994 refs = count_refs(src);
995 ok(refs == old_refs, "%d %d\n", refs, old_refs);
997 DataObjectImpl_GetData_calls = 0;
998 hr = IDataObject_GetData(get1, &fmt, &med);
999 ok(hr == S_OK, "got %08x\n", hr);
1000 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1001 ReleaseStgMedium(&med);
1002 refs = count_refs(src);
1003 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1005 OleFlushClipboard();
1007 DataObjectImpl_GetData_calls = 0;
1008 hr = IDataObject_GetData(get1, &fmt, &med);
1009 ok(hr == S_OK, "got %08x\n", hr);
1010 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1011 ReleaseStgMedium(&med);
1013 refs = count_refs(src);
1014 ok(refs == 2, "%d\n", refs);
1016 IDataObject_Release(get1);
1018 refs = count_refs(src);
1019 ok(refs == 1, "%d\n", refs);
1021 /* Now set a second src object before the call to GetData
1022 and show that GetData calls that second src. */
1024 hr = OleSetClipboard(src);
1025 ok(hr == S_OK, "got %08x\n", hr);
1027 old_refs = count_refs(src);
1029 hr = OleGetClipboard(&get1);
1030 ok(hr == S_OK, "got %08x\n", hr);
1032 refs = count_refs(src);
1033 ok(refs == old_refs, "%d %d\n", refs, old_refs);
1035 hr = OleSetClipboard(src2);
1036 ok(hr == S_OK, "got %08x\n", hr);
1038 old_refs = count_refs(src2);
1040 DataObjectImpl_GetData_calls = 0;
1041 hr = IDataObject_GetData(get1, &fmt, &med);
1042 ok(hr == S_OK, "got %08x\n", hr);
1043 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1044 ReleaseStgMedium(&med);
1046 refs = count_refs(src);
1047 ok(refs == 1, "%d\n", refs);
1048 refs = count_refs(src2);
1049 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1051 OleSetClipboard(NULL);
1053 refs = count_refs(src2);
1054 ok(refs == 2, "%d\n", refs);
1056 IDataObject_Release(get1);
1058 IDataObject_Release(src2);
1059 IDataObject_Release(src);
1061 OleUninitialize();
1064 static void test_flushed_getdata(void)
1066 HRESULT hr;
1067 IDataObject *src, *get;
1068 FORMATETC fmt;
1069 STGMEDIUM med;
1070 STATSTG stat;
1071 DEVMODEW dm;
1073 OleInitialize(NULL);
1075 hr = DataObjectImpl_CreateComplex(&src);
1076 ok(hr == S_OK, "got %08x\n", hr);
1078 hr = OleSetClipboard(src);
1079 ok(hr == S_OK, "got %08x\n", hr);
1081 hr = OleFlushClipboard();
1082 ok(hr == S_OK, "got %08x\n", hr);
1084 hr = OleGetClipboard(&get);
1085 ok(hr == S_OK, "got %08x\n", hr);
1087 /* global format -> global & stream */
1089 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1090 hr = IDataObject_GetData(get, &fmt, &med);
1091 ok(hr == S_OK, "got %08x\n", hr);
1092 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1093 ReleaseStgMedium(&med);
1095 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTREAM);
1096 hr = IDataObject_GetData(get, &fmt, &med);
1097 ok(hr == S_OK, "got %08x\n", hr);
1098 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1099 ReleaseStgMedium(&med);
1101 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTORAGE);
1102 hr = IDataObject_GetData(get, &fmt, &med);
1103 ok(hr == E_FAIL, "got %08x\n", hr);
1105 InitFormatEtc(fmt, CF_TEXT, 0xffff);
1106 hr = IDataObject_GetData(get, &fmt, &med);
1107 ok(hr == S_OK, "got %08x\n", hr);
1108 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1109 ReleaseStgMedium(&med);
1111 /* stream format -> global & stream */
1113 InitFormatEtc(fmt, cf_stream, TYMED_ISTREAM);
1114 hr = IDataObject_GetData(get, &fmt, &med);
1115 ok(hr == S_OK, "got %08x\n", hr);
1116 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1117 ReleaseStgMedium(&med);
1119 InitFormatEtc(fmt, cf_stream, TYMED_ISTORAGE);
1120 hr = IDataObject_GetData(get, &fmt, &med);
1121 ok(hr == E_FAIL, "got %08x\n", hr);
1123 InitFormatEtc(fmt, cf_stream, TYMED_HGLOBAL);
1124 hr = IDataObject_GetData(get, &fmt, &med);
1125 ok(hr == S_OK, "got %08x\n", hr);
1126 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1127 ReleaseStgMedium(&med);
1129 InitFormatEtc(fmt, cf_stream, 0xffff);
1130 hr = IDataObject_GetData(get, &fmt, &med);
1131 ok(hr == S_OK, "got %08x\n", hr);
1132 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1133 ReleaseStgMedium(&med);
1135 /* storage format -> global, stream & storage */
1137 InitFormatEtc(fmt, cf_storage, TYMED_ISTORAGE);
1138 hr = IDataObject_GetData(get, &fmt, &med);
1139 ok(hr == S_OK, "got %08x\n", hr);
1140 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1141 hr = IStorage_Stat(med.u.pstg, &stat, STATFLAG_NONAME);
1142 ok(hr == S_OK, "got %08x\n", hr);
1143 ok(stat.grfMode == (STGM_SHARE_EXCLUSIVE | STGM_READWRITE), "got %08x\n", stat.grfMode);
1144 ReleaseStgMedium(&med);
1146 InitFormatEtc(fmt, cf_storage, TYMED_ISTREAM);
1147 hr = IDataObject_GetData(get, &fmt, &med);
1148 ok(hr == S_OK, "got %08x\n", hr);
1149 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1150 ReleaseStgMedium(&med);
1152 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL);
1153 hr = IDataObject_GetData(get, &fmt, &med);
1154 ok(hr == S_OK, "got %08x\n", hr);
1155 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1156 ReleaseStgMedium(&med);
1158 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL | TYMED_ISTREAM);
1159 hr = IDataObject_GetData(get, &fmt, &med);
1160 ok(hr == S_OK, "got %08x\n", hr);
1161 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1162 ReleaseStgMedium(&med);
1164 InitFormatEtc(fmt, cf_storage, 0xffff);
1165 hr = IDataObject_GetData(get, &fmt, &med);
1166 ok(hr == S_OK, "got %08x\n", hr);
1167 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1168 ReleaseStgMedium(&med);
1170 /* complex format with target device */
1172 InitFormatEtc(fmt, cf_another, 0xffff);
1173 hr = IDataObject_GetData(get, &fmt, &med);
1174 ok(hr == DV_E_FORMATETC ||
1175 broken(hr == S_OK), /* win9x, winme & nt4 */
1176 "got %08x\n", hr);
1177 if(hr == S_OK) ReleaseStgMedium(&med);
1179 InitFormatEtc(fmt, cf_another, 0xffff);
1180 memset(&dm, 0, sizeof(dm));
1181 dm.dmSize = sizeof(dm);
1182 dm.dmDriverExtra = 0;
1183 lstrcpyW(dm.dmDeviceName, device_name);
1184 fmt.ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
1185 fmt.ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
1186 fmt.ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
1187 fmt.ptd->tdDeviceNameOffset = 0;
1188 fmt.ptd->tdPortNameOffset = 0;
1189 fmt.ptd->tdExtDevmodeOffset = fmt.ptd->tdDriverNameOffset + sizeof(device_name);
1190 lstrcpyW((WCHAR*)fmt.ptd->tdData, device_name);
1191 memcpy(fmt.ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
1193 hr = IDataObject_GetData(get, &fmt, &med);
1194 ok(hr == S_OK, "got %08x\n", hr);
1195 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1196 ReleaseStgMedium(&med);
1198 HeapFree(GetProcessHeap(), 0, fmt.ptd);
1201 IDataObject_Release(get);
1202 IDataObject_Release(src);
1203 OleUninitialize();
1206 static HGLOBAL create_text(void)
1208 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5);
1209 char *p = GlobalLock(h);
1210 strcpy(p, "test");
1211 GlobalUnlock(h);
1212 return h;
1215 static HENHMETAFILE create_emf(void)
1217 const RECT rect = {0, 0, 100, 100};
1218 HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1219 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
1220 return CloseEnhMetaFile(hdc);
1223 static void test_nonole_clipboard(void)
1225 HRESULT hr;
1226 BOOL r;
1227 IDataObject *get;
1228 IEnumFORMATETC *enum_fmt;
1229 FORMATETC fmt;
1230 HGLOBAL h, hblob, htext;
1231 HENHMETAFILE emf;
1233 r = OpenClipboard(NULL);
1234 ok(r, "gle %d\n", GetLastError());
1235 r = EmptyClipboard();
1236 ok(r, "gle %d\n", GetLastError());
1237 r = CloseClipboard();
1238 ok(r, "gle %d\n", GetLastError());
1240 OleInitialize(NULL);
1242 /* empty clipboard */
1243 hr = OleGetClipboard(&get);
1244 ok(hr == S_OK, "got %08x\n", hr);
1245 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1246 ok(hr == S_OK, "got %08x\n", hr);
1248 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1249 ok(hr == S_FALSE, "got %08x\n", hr);
1250 IEnumFORMATETC_Release(enum_fmt);
1252 IDataObject_Release(get);
1254 /* set a user defined clipboard type */
1256 htext = create_text();
1257 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
1258 emf = create_emf();
1260 r = OpenClipboard(NULL);
1261 ok(r, "gle %d\n", GetLastError());
1262 h = SetClipboardData(CF_TEXT, htext);
1263 ok(h == htext, "got %p\n", h);
1264 h = SetClipboardData(cf_onemore, hblob);
1265 ok(h == hblob, "got %p\n", h);
1266 h = SetClipboardData(CF_ENHMETAFILE, emf);
1267 ok(h == emf, "got %p\n", h);
1268 r = CloseClipboard();
1269 ok(r, "gle %d\n", GetLastError());
1271 hr = OleGetClipboard(&get);
1272 ok(hr == S_OK, "got %08x\n", hr);
1273 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1274 ok(hr == S_OK, "got %08x\n", hr);
1276 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1277 ok(hr == S_OK, "got %08x\n", hr);
1278 ok(fmt.cfFormat == CF_TEXT, "cf %04x\n", fmt.cfFormat);
1279 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1280 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1281 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1282 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1284 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1285 ok(hr == S_OK, "got %08x\n", hr);
1286 ok(fmt.cfFormat == cf_onemore, "cf %04x\n", fmt.cfFormat);
1287 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1288 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1289 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1290 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1292 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1293 ok(hr == S_OK, "got %08x\n", hr);
1294 ok(fmt.cfFormat == CF_ENHMETAFILE, "cf %04x\n", fmt.cfFormat);
1295 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1296 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1297 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1298 ok(fmt.tymed == TYMED_ENHMF, "tymed %x\n", fmt.tymed);
1300 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1301 ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */
1303 todo_wine ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
1304 if(fmt.cfFormat == CF_LOCALE)
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);
1315 ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat);
1316 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1317 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1318 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1319 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1321 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1322 ok(hr == S_OK, "got %08x\n", hr);
1323 ok(fmt.cfFormat == CF_UNICODETEXT ||
1324 broken(fmt.cfFormat == CF_METAFILEPICT), /* win9x and winme don't have CF_UNICODETEXT */
1325 "cf %04x\n", fmt.cfFormat);
1326 if(fmt.cfFormat == CF_UNICODETEXT)
1328 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1329 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1330 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1331 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1333 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1334 ok(hr == S_OK, "got %08x\n", hr);
1336 ok(fmt.cfFormat == CF_METAFILEPICT, "cf %04x\n", fmt.cfFormat);
1337 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1338 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1339 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1340 ok(fmt.tymed == TYMED_MFPICT, "tymed %x\n", fmt.tymed);
1342 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1343 ok(hr == S_FALSE, "got %08x\n", hr);
1344 IEnumFORMATETC_Release(enum_fmt);
1346 IDataObject_Release(get);
1348 r = OpenClipboard(NULL);
1349 ok(r, "gle %d\n", GetLastError());
1350 r = EmptyClipboard();
1351 ok(r, "gle %d\n", GetLastError());
1352 r = CloseClipboard();
1353 ok(r, "gle %d\n", GetLastError());
1355 OleUninitialize();
1358 START_TEST(clipboard)
1360 test_set_clipboard();
1361 test_consumer_refs();
1362 test_flushed_getdata();
1363 test_nonole_clipboard();