push a9ee6bdc492dbf6a3d2de76ff889abeabd04e8d0
[wine/hacks.git] / dlls / ole32 / tests / clipboard.c
blobfc55d385a40e85efb76dac64929f9631d3d7cdff
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
23 #include <stdarg.h>
24 #include <stdio.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "objbase.h"
30 #include "wine/test.h"
32 #define InitFormatEtc(fe, cf, med) \
34 (fe).cfFormat=cf;\
35 (fe).dwAspect=DVASPECT_CONTENT;\
36 (fe).ptd=NULL;\
37 (fe).tymed=med;\
38 (fe).lindex=-1;\
41 static inline char *dump_fmtetc(FORMATETC *fmt)
43 static char buf[100];
45 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
46 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
47 return buf;
50 typedef struct DataObjectImpl {
51 const IDataObjectVtbl *lpVtbl;
52 LONG ref;
54 FORMATETC *fmtetc;
55 UINT fmtetc_cnt;
57 HANDLE text;
58 IStream *stm;
59 IStorage *stg;
60 } DataObjectImpl;
62 typedef struct EnumFormatImpl {
63 const IEnumFORMATETCVtbl *lpVtbl;
64 LONG ref;
66 FORMATETC *fmtetc;
67 UINT fmtetc_cnt;
69 UINT cur;
70 } EnumFormatImpl;
72 static BOOL expect_DataObjectImpl_QueryGetData = TRUE;
73 static ULONG DataObjectImpl_GetData_calls = 0;
74 static ULONG DataObjectImpl_GetDataHere_calls = 0;
75 static ULONG DataObjectImpl_EnumFormatEtc_calls = 0;
77 static UINT cf_stream, cf_storage, cf_global, cf_another, cf_onemore;
79 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
81 static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
83 EnumFormatImpl *This = (EnumFormatImpl*)iface;
85 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) {
86 IEnumFORMATETC_AddRef(iface);
87 *ppvObj = This;
88 return S_OK;
90 *ppvObj = NULL;
91 return E_NOINTERFACE;
94 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
96 EnumFormatImpl *This = (EnumFormatImpl*)iface;
97 LONG ref = InterlockedIncrement(&This->ref);
98 return ref;
101 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
103 EnumFormatImpl *This = (EnumFormatImpl*)iface;
104 ULONG ref = InterlockedDecrement(&This->ref);
106 if(!ref) {
107 HeapFree(GetProcessHeap(), 0, This->fmtetc);
108 HeapFree(GetProcessHeap(), 0, This);
111 return ref;
114 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
115 FORMATETC *rgelt, ULONG *pceltFetched)
117 EnumFormatImpl *This = (EnumFormatImpl*)iface;
118 ULONG count, i;
120 if(!rgelt)
121 return E_INVALIDARG;
123 count = min(celt, This->fmtetc_cnt - This->cur);
124 for(i = 0; i < count; i++, This->cur++, rgelt++)
126 *rgelt = This->fmtetc[This->cur];
127 if(rgelt->ptd)
129 DWORD size = This->fmtetc[This->cur].ptd->tdSize;
130 rgelt->ptd = CoTaskMemAlloc(size);
131 memcpy(rgelt->ptd, This->fmtetc[This->cur].ptd, size);
134 if(pceltFetched)
135 *pceltFetched = count;
136 return count == celt ? S_OK : S_FALSE;
139 static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt)
141 ok(0, "unexpected call\n");
142 return E_NOTIMPL;
145 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
147 EnumFormatImpl *This = (EnumFormatImpl*)iface;
149 This->cur = 0;
150 return S_OK;
153 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
155 ok(0, "unexpected call\n");
156 return E_NOTIMPL;
159 static const IEnumFORMATETCVtbl VT_EnumFormatImpl = {
160 EnumFormatImpl_QueryInterface,
161 EnumFormatImpl_AddRef,
162 EnumFormatImpl_Release,
163 EnumFormatImpl_Next,
164 EnumFormatImpl_Skip,
165 EnumFormatImpl_Reset,
166 EnumFormatImpl_Clone
169 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
171 EnumFormatImpl *ret;
173 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl));
174 ret->lpVtbl = &VT_EnumFormatImpl;
175 ret->ref = 1;
176 ret->cur = 0;
177 ret->fmtetc_cnt = fmtetc_cnt;
178 ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC));
179 memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
180 *lplpformatetc = (LPENUMFORMATETC)ret;
181 return S_OK;
184 static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj)
186 DataObjectImpl *This = (DataObjectImpl*)iface;
188 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) {
189 IDataObject_AddRef(iface);
190 *ppvObj = This;
191 return S_OK;
193 *ppvObj = NULL;
194 return E_NOINTERFACE;
197 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
199 DataObjectImpl *This = (DataObjectImpl*)iface;
200 ULONG ref = InterlockedIncrement(&This->ref);
201 return ref;
204 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
206 DataObjectImpl *This = (DataObjectImpl*)iface;
207 ULONG ref = InterlockedDecrement(&This->ref);
209 if(!ref)
211 int i;
212 if(This->text) GlobalFree(This->text);
213 for(i = 0; i < This->fmtetc_cnt; i++)
214 HeapFree(GetProcessHeap(), 0, This->fmtetc[i].ptd);
215 HeapFree(GetProcessHeap(), 0, This->fmtetc);
216 if(This->stm) IStream_Release(This->stm);
217 if(This->stg) IStorage_Release(This->stg);
218 HeapFree(GetProcessHeap(), 0, This);
221 return ref;
224 static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
226 DataObjectImpl *This = (DataObjectImpl*)iface;
227 UINT i;
228 BOOL foundFormat = FALSE;
230 trace("getdata: %s\n", dump_fmtetc(pformatetc));
232 DataObjectImpl_GetData_calls++;
234 if(pformatetc->lindex != -1)
235 return DV_E_FORMATETC;
237 for(i = 0; i < This->fmtetc_cnt; i++)
239 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat)
241 foundFormat = TRUE;
242 if(This->fmtetc[i].tymed & pformatetc->tymed)
244 pmedium->pUnkForRelease = (LPUNKNOWN)iface;
245 IUnknown_AddRef(pmedium->pUnkForRelease);
247 if(pformatetc->cfFormat == CF_TEXT || pformatetc->cfFormat == cf_global)
249 pmedium->tymed = TYMED_HGLOBAL;
250 U(*pmedium).hGlobal = This->text;
252 else if(pformatetc->cfFormat == cf_stream)
254 pmedium->tymed = TYMED_ISTREAM;
255 IStream_AddRef(This->stm);
256 U(*pmedium).pstm = This->stm;
258 else if(pformatetc->cfFormat == cf_storage)
260 pmedium->tymed = TYMED_ISTORAGE;
261 IStorage_AddRef(This->stg);
262 U(*pmedium).pstg = This->stg;
264 return S_OK;
269 return foundFormat ? DV_E_TYMED : DV_E_FORMATETC;
272 static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
274 trace("getdatahere: %s\n", dump_fmtetc(pformatetc));
275 DataObjectImpl_GetDataHere_calls++;
277 return E_NOTIMPL;
280 static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc)
282 DataObjectImpl *This = (DataObjectImpl*)iface;
283 UINT i;
284 BOOL foundFormat = FALSE;
286 trace("querygetdata: %s\n", dump_fmtetc(pformatetc));
287 if (!expect_DataObjectImpl_QueryGetData)
288 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
290 if(pformatetc->lindex != -1)
291 return DV_E_LINDEX;
293 for(i=0; i<This->fmtetc_cnt; i++) {
294 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) {
295 foundFormat = TRUE;
296 if(This->fmtetc[i].tymed == pformatetc->tymed)
297 return S_OK;
300 return foundFormat?DV_E_FORMATETC:DV_E_TYMED;
303 static HRESULT WINAPI DataObjectImpl_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC *pformatectIn,
304 FORMATETC *pformatetcOut)
306 ok(0, "unexpected call\n");
307 return E_NOTIMPL;
310 static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc,
311 STGMEDIUM *pmedium, BOOL fRelease)
313 ok(0, "unexpected call\n");
314 return E_NOTIMPL;
317 static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwDirection,
318 IEnumFORMATETC **ppenumFormatEtc)
320 DataObjectImpl *This = (DataObjectImpl*)iface;
322 DataObjectImpl_EnumFormatEtc_calls++;
324 if(dwDirection != DATADIR_GET) {
325 ok(0, "unexpected direction %d\n", dwDirection);
326 return E_NOTIMPL;
328 return EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenumFormatEtc);
331 static HRESULT WINAPI DataObjectImpl_DAdvise(IDataObject* iface, FORMATETC *pformatetc, DWORD advf,
332 IAdviseSink *pAdvSink, DWORD *pdwConnection)
334 ok(0, "unexpected call\n");
335 return E_NOTIMPL;
338 static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection)
340 ok(0, "unexpected call\n");
341 return E_NOTIMPL;
344 static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise)
346 ok(0, "unexpected call\n");
347 return E_NOTIMPL;
350 static const IDataObjectVtbl VT_DataObjectImpl =
352 DataObjectImpl_QueryInterface,
353 DataObjectImpl_AddRef,
354 DataObjectImpl_Release,
355 DataObjectImpl_GetData,
356 DataObjectImpl_GetDataHere,
357 DataObjectImpl_QueryGetData,
358 DataObjectImpl_GetCanonicalFormatEtc,
359 DataObjectImpl_SetData,
360 DataObjectImpl_EnumFormatEtc,
361 DataObjectImpl_DAdvise,
362 DataObjectImpl_DUnadvise,
363 DataObjectImpl_EnumDAdvise
366 static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
368 DataObjectImpl *obj;
370 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
371 obj->lpVtbl = &VT_DataObjectImpl;
372 obj->ref = 1;
373 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1);
374 strcpy(GlobalLock(obj->text), text);
375 GlobalUnlock(obj->text);
376 obj->stm = NULL;
377 obj->stg = NULL;
379 obj->fmtetc_cnt = 1;
380 obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
381 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
383 *lplpdataobj = (LPDATAOBJECT)obj;
384 return S_OK;
387 const char *cmpl_stm_data = "complex stream";
388 const char *cmpl_text_data = "complex text";
390 static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj)
392 DataObjectImpl *obj;
393 ILockBytes *lbs;
394 static const WCHAR devname[] = {'m','y','d','e','v',0};
395 DEVMODEW dm;
397 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
398 obj->lpVtbl = &VT_DataObjectImpl;
399 obj->ref = 1;
400 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(cmpl_text_data) + 1);
401 strcpy(GlobalLock(obj->text), cmpl_text_data);
402 GlobalUnlock(obj->text);
403 CreateStreamOnHGlobal(NULL, TRUE, &obj->stm);
404 IStream_Write(obj->stm, cmpl_stm_data, strlen(cmpl_stm_data), NULL);
406 CreateILockBytesOnHGlobal(NULL, TRUE, &lbs);
407 StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &obj->stg);
408 ILockBytes_Release(lbs);
410 obj->fmtetc_cnt = 8;
411 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
412 obj->fmtetc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, obj->fmtetc_cnt*sizeof(FORMATETC));
413 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
414 InitFormatEtc(obj->fmtetc[1], cf_stream, TYMED_ISTREAM);
415 InitFormatEtc(obj->fmtetc[2], cf_storage, TYMED_ISTORAGE);
416 InitFormatEtc(obj->fmtetc[3], cf_another, TYMED_ISTORAGE|TYMED_ISTREAM|TYMED_HGLOBAL);
417 memset(&dm, 0, sizeof(dm));
418 dm.dmSize = sizeof(dm);
419 dm.dmDriverExtra = 0;
420 lstrcpyW(dm.dmDeviceName, devname);
421 obj->fmtetc[3].ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(devname) + dm.dmSize + dm.dmDriverExtra);
422 obj->fmtetc[3].ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(devname) + dm.dmSize + dm.dmDriverExtra;
423 obj->fmtetc[3].ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
424 obj->fmtetc[3].ptd->tdDeviceNameOffset = 0;
425 obj->fmtetc[3].ptd->tdPortNameOffset = 0;
426 obj->fmtetc[3].ptd->tdExtDevmodeOffset = obj->fmtetc[3].ptd->tdDriverNameOffset + sizeof(devname);
427 lstrcpyW((WCHAR*)obj->fmtetc[3].ptd->tdData, devname);
428 memcpy(obj->fmtetc[3].ptd->tdData + sizeof(devname), &dm, dm.dmSize + dm.dmDriverExtra);
430 InitFormatEtc(obj->fmtetc[4], cf_global, TYMED_HGLOBAL);
431 InitFormatEtc(obj->fmtetc[5], cf_another, TYMED_HGLOBAL);
432 InitFormatEtc(obj->fmtetc[6], cf_another, 0xfffff);
433 InitFormatEtc(obj->fmtetc[7], cf_another, 0xfffff);
434 obj->fmtetc[7].dwAspect = DVASPECT_ICON;
436 *lplpdataobj = (LPDATAOBJECT)obj;
437 return S_OK;
440 static void test_get_clipboard(void)
442 HRESULT hr;
443 IDataObject *data_obj;
444 FORMATETC fmtetc;
445 STGMEDIUM stgmedium;
447 hr = OleGetClipboard(NULL);
448 ok(hr == E_INVALIDARG, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr);
450 hr = OleGetClipboard(&data_obj);
451 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
453 /* test IDataObject_QueryGetData */
455 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
456 expect_DataObjectImpl_QueryGetData = FALSE;
458 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
459 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
460 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
462 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
463 fmtetc.dwAspect = 0xdeadbeef;
464 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
465 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
467 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
468 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
469 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
470 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
472 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
473 fmtetc.lindex = 256;
474 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
475 ok(hr == DV_E_FORMATETC || broken(hr == S_OK),
476 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
477 if (hr == S_OK)
478 ReleaseStgMedium(&stgmedium);
480 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
481 fmtetc.cfFormat = CF_RIFF;
482 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
483 ok(hr == DV_E_CLIPFORMAT, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr);
485 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
486 fmtetc.tymed = TYMED_FILE;
487 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
488 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
490 expect_DataObjectImpl_QueryGetData = TRUE;
492 /* test IDataObject_GetData */
494 DataObjectImpl_GetData_calls = 0;
496 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
497 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
498 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
499 ReleaseStgMedium(&stgmedium);
501 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
502 fmtetc.dwAspect = 0xdeadbeef;
503 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
504 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
505 ReleaseStgMedium(&stgmedium);
507 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
508 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
509 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
510 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
511 ReleaseStgMedium(&stgmedium);
513 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
514 fmtetc.lindex = 256;
515 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
516 ok(hr == DV_E_FORMATETC || broken(hr == S_OK), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
517 if (hr == S_OK)
519 /* undo the unexpected success */
520 DataObjectImpl_GetData_calls--;
521 ReleaseStgMedium(&stgmedium);
524 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
525 fmtetc.cfFormat = CF_RIFF;
526 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
527 ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
529 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
530 fmtetc.tymed = TYMED_FILE;
531 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
532 ok(hr == DV_E_TYMED, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr);
534 ok(DataObjectImpl_GetData_calls == 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls);
536 IDataObject_Release(data_obj);
539 static void test_enum_fmtetc(IDataObject *src)
541 HRESULT hr;
542 IDataObject *data;
543 IEnumFORMATETC *enum_fmt, *src_enum;
544 FORMATETC fmt, src_fmt;
545 DWORD count = 0;
547 hr = OleGetClipboard(&data);
548 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
550 hr = IDataObject_EnumFormatEtc(data, DATADIR_SET, &enum_fmt);
551 ok(hr == E_NOTIMPL ||
552 broken(hr == E_INVALIDARG), /* win98 (not win98SE) */
553 "got %08x\n", hr);
555 DataObjectImpl_EnumFormatEtc_calls = 0;
556 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
557 ok(hr == S_OK, "got %08x\n", hr);
558 ok(DataObjectImpl_EnumFormatEtc_calls == 0, "EnumFormatEtc was called\n");
560 if(src) IDataObject_EnumFormatEtc(src, DATADIR_GET, &src_enum);
562 while((hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL)) == S_OK)
564 ok(src != NULL, "shouldn't be here\n");
565 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
566 ok(hr == S_OK, "%d: got %08x\n", count, hr);
567 trace("%d: cf %04x aspect %x tymed %x\n", count, fmt.cfFormat, fmt.dwAspect, fmt.tymed);
568 ok(fmt.cfFormat == src_fmt.cfFormat, "%d: %04x %04x\n", count, fmt.cfFormat, src_fmt.cfFormat);
569 ok(fmt.dwAspect == src_fmt.dwAspect, "%d: %08x %08x\n", count, fmt.dwAspect, src_fmt.dwAspect);
570 ok(fmt.lindex == src_fmt.lindex, "%d: %08x %08x\n", count, fmt.lindex, src_fmt.lindex);
571 ok(fmt.tymed == src_fmt.tymed, "%d: %08x %08x\n", count, fmt.tymed, src_fmt.tymed);
572 if(fmt.ptd)
574 ok(src_fmt.ptd != NULL, "%d: expected non-NULL\n", count);
575 CoTaskMemFree(fmt.ptd);
576 CoTaskMemFree(src_fmt.ptd);
578 count++;
581 ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
583 if(src)
585 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
586 ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
587 IEnumFORMATETC_Release(src_enum);
590 hr = IEnumFORMATETC_Reset(enum_fmt);
591 ok(hr == S_OK, "got %08x\n", hr);
593 IEnumFORMATETC_Release(enum_fmt);
594 IDataObject_Release(data);
597 static void test_cf_dataobject(IDataObject *data)
599 UINT cf = 0;
600 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
601 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
602 BOOL found_dataobject = FALSE, found_priv_data = FALSE;
604 OpenClipboard(NULL);
607 cf = EnumClipboardFormats(cf);
608 if(cf == cf_dataobject)
610 HGLOBAL h = GetClipboardData(cf);
611 HWND *ptr = GlobalLock(h);
612 DWORD size = GlobalSize(h);
613 HWND clip_owner = GetClipboardOwner();
615 found_dataobject = TRUE;
616 ok(size >= sizeof(*ptr), "size %d\n", size);
617 if(data)
618 ok(*ptr == clip_owner, "hwnd %p clip_owner %p\n", *ptr, clip_owner);
619 else /* ole clipboard flushed */
620 ok(*ptr == NULL, "hwnd %p\n", *ptr);
621 GlobalUnlock(h);
623 else if(cf == cf_ole_priv_data)
625 found_priv_data = TRUE;
626 if(data)
628 HGLOBAL h = GetClipboardData(cf);
629 DWORD *ptr = GlobalLock(h);
630 DWORD size = GlobalSize(h);
632 if(size != ptr[1])
633 win_skip("Ole Private Data in win9x format\n");
634 else
636 HRESULT hr;
637 IEnumFORMATETC *enum_fmt;
638 DWORD count = 0;
639 FORMATETC fmt;
640 struct formatetcetc
642 FORMATETC fmt;
643 BOOL first_use_of_cf;
644 DWORD res[2];
645 } *fmt_ptr;
646 struct priv_data
648 DWORD res1;
649 DWORD size;
650 DWORD res2;
651 DWORD count;
652 DWORD res3[2];
653 struct formatetcetc fmts[1];
654 } *priv = (struct priv_data*)ptr;
655 CLIPFORMAT cfs_seen[10];
657 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
658 ok(hr == S_OK, "got %08x\n", hr);
659 fmt_ptr = priv->fmts;
661 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
663 int i;
664 BOOL seen_cf = FALSE;
666 ok(fmt_ptr->fmt.cfFormat == fmt.cfFormat,
667 "got %08x expected %08x\n", fmt_ptr->fmt.cfFormat, fmt.cfFormat);
668 ok(fmt_ptr->fmt.dwAspect == fmt.dwAspect, "got %08x expected %08x\n",
669 fmt_ptr->fmt.dwAspect, fmt.dwAspect);
670 ok(fmt_ptr->fmt.lindex == fmt.lindex, "got %08x expected %08x\n",
671 fmt_ptr->fmt.lindex, fmt.lindex);
672 ok(fmt_ptr->fmt.tymed == fmt.tymed, "got %08x expected %08x\n",
673 fmt_ptr->fmt.tymed, fmt.tymed);
674 for(i = 0; i < count; i++)
675 if(fmt_ptr->fmt.cfFormat == cfs_seen[i])
677 seen_cf = TRUE;
678 break;
680 cfs_seen[count] = fmt.cfFormat;
681 ok(fmt_ptr->first_use_of_cf == seen_cf ? FALSE : TRUE, "got %08x expected %08x\n",
682 fmt_ptr->first_use_of_cf, !seen_cf);
683 ok(fmt_ptr->res[0] == 0, "got %08x\n", fmt_ptr->res[1]);
684 ok(fmt_ptr->res[1] == 0, "got %08x\n", fmt_ptr->res[2]);
685 if(fmt.ptd)
687 DVTARGETDEVICE *target;
689 ok(fmt_ptr->fmt.ptd != NULL, "target device offset zero\n");
690 target = (DVTARGETDEVICE*)((char*)priv + (DWORD)fmt_ptr->fmt.ptd);
691 ok(!memcmp(target, fmt.ptd, fmt.ptd->tdSize), "target devices differ\n");
692 CoTaskMemFree(fmt.ptd);
694 fmt_ptr++;
695 count++;
697 ok(priv->res1 == 0, "got %08x\n", priv->res1);
698 ok(priv->res2 == 1, "got %08x\n", priv->res2);
699 ok(priv->count == count, "got %08x expected %08x\n", priv->count, count);
700 ok(priv->res3[0] == 0, "got %08x\n", priv->res3[0]);
701 ok(priv->res3[1] == 0, "got %08x\n", priv->res3[1]);
703 GlobalUnlock(h);
704 IEnumFORMATETC_Release(enum_fmt);
708 else if(cf == cf_stream)
710 HGLOBAL h;
711 void *ptr;
712 DWORD size;
714 DataObjectImpl_GetDataHere_calls = 0;
715 h = GetClipboardData(cf);
716 ok(DataObjectImpl_GetDataHere_calls == 1, "got %d\n", DataObjectImpl_GetDataHere_calls);
717 ptr = GlobalLock(h);
718 size = GlobalSize(h);
719 ok(size == strlen(cmpl_stm_data), "expected %d got %d\n", lstrlenA(cmpl_stm_data), size);
720 ok(!memcmp(ptr, cmpl_stm_data, size), "mismatch\n");
721 GlobalUnlock(h);
723 else if(cf == cf_global)
725 HGLOBAL h;
726 void *ptr;
727 DWORD size;
729 DataObjectImpl_GetDataHere_calls = 0;
730 h = GetClipboardData(cf);
731 ok(DataObjectImpl_GetDataHere_calls == 0, "got %d\n", DataObjectImpl_GetDataHere_calls);
732 ptr = GlobalLock(h);
733 size = GlobalSize(h);
734 ok(size == strlen(cmpl_text_data) + 1, "expected %d got %d\n", lstrlenA(cmpl_text_data) + 1, size);
735 ok(!memcmp(ptr, cmpl_text_data, size), "mismatch\n");
736 GlobalUnlock(h);
738 } while(cf);
739 CloseClipboard();
740 ok(found_dataobject, "didn't find cf_dataobject\n");
741 ok(found_priv_data, "didn't find cf_ole_priv_data\n");
744 static void test_set_clipboard(void)
746 HRESULT hr;
747 ULONG ref;
748 LPDATAOBJECT data1, data2, data_cmpl;
749 HGLOBAL hblob, h;
751 cf_stream = RegisterClipboardFormatA("stream format");
752 cf_storage = RegisterClipboardFormatA("storage format");
753 cf_global = RegisterClipboardFormatA("global format");
754 cf_another = RegisterClipboardFormatA("another format");
755 cf_onemore = RegisterClipboardFormatA("one more format");
757 hr = DataObjectImpl_CreateText("data1", &data1);
758 ok(SUCCEEDED(hr), "Failed to create data1 object: 0x%08x\n", hr);
759 if(FAILED(hr))
760 return;
761 hr = DataObjectImpl_CreateText("data2", &data2);
762 ok(SUCCEEDED(hr), "Failed to create data2 object: 0x%08x\n", hr);
763 if(FAILED(hr))
764 return;
765 hr = DataObjectImpl_CreateComplex(&data_cmpl);
766 ok(SUCCEEDED(hr), "Failed to create complex data object: 0x%08x\n", hr);
767 if(FAILED(hr))
768 return;
770 hr = OleSetClipboard(data1);
771 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
773 CoInitialize(NULL);
774 hr = OleSetClipboard(data1);
775 ok(hr == CO_E_NOTINITIALIZED ||
776 hr == CLIPBRD_E_CANT_SET, /* win9x */
777 "OleSetClipboard should have failed with "
778 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr);
779 CoUninitialize();
781 hr = OleInitialize(NULL);
782 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
784 hr = OleSetClipboard(data1);
785 ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr);
787 test_cf_dataobject(data1);
789 hr = OleIsCurrentClipboard(data1);
790 ok(hr == S_OK, "expected current clipboard to be data1, hr = 0x%08x\n", hr);
791 hr = OleIsCurrentClipboard(data2);
792 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
793 hr = OleIsCurrentClipboard(NULL);
794 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
796 test_get_clipboard();
798 hr = OleSetClipboard(data2);
799 ok(hr == S_OK, "failed to set clipboard to data2, hr = 0x%08x\n", hr);
800 hr = OleIsCurrentClipboard(data1);
801 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
802 hr = OleIsCurrentClipboard(data2);
803 ok(hr == S_OK, "expected current clipboard to be data2, hr = 0x%08x\n", hr);
804 hr = OleIsCurrentClipboard(NULL);
805 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
807 /* put a format directly onto the clipboard to show
808 OleFlushClipboard doesn't empty the clipboard */
809 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
810 OpenClipboard(NULL);
811 h = SetClipboardData(cf_onemore, hblob);
812 ok(h == hblob, "got %p\n", h);
813 h = GetClipboardData(cf_onemore);
814 ok(h == hblob ||
815 broken(h != NULL), /* win9x */
816 "got %p\n", h);
817 CloseClipboard();
819 hr = OleFlushClipboard();
820 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
821 hr = OleIsCurrentClipboard(data1);
822 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
823 hr = OleIsCurrentClipboard(data2);
824 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
825 hr = OleIsCurrentClipboard(NULL);
826 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
828 /* format should survive the flush */
829 OpenClipboard(NULL);
830 h = GetClipboardData(cf_onemore);
831 ok(h == hblob ||
832 broken(h != NULL), /* win9x */
833 "got %p\n", h);
834 CloseClipboard();
836 test_cf_dataobject(NULL);
838 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
840 OpenClipboard(NULL);
841 h = GetClipboardData(cf_onemore);
842 ok(h == NULL, "got %p\n", h);
843 CloseClipboard();
845 trace("setting complex\n");
846 hr = OleSetClipboard(data_cmpl);
847 ok(hr == S_OK, "failed to set clipboard to complex data, hr = 0x%08x\n", hr);
848 test_cf_dataobject(data_cmpl);
849 test_enum_fmtetc(data_cmpl);
851 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
853 test_enum_fmtetc(NULL);
855 ref = IDataObject_Release(data1);
856 ok(ref == 0, "expected data1 ref=0, got %d\n", ref);
857 ref = IDataObject_Release(data2);
858 ok(ref == 0, "expected data2 ref=0, got %d\n", ref);
859 ref = IDataObject_Release(data_cmpl);
860 ok(ref == 0, "expected data_cmpl ref=0, got %d\n", ref);
862 OleUninitialize();
866 START_TEST(clipboard)
868 test_set_clipboard();