ole32/tests: Add broken return value for win98.
[wine/hacks.git] / dlls / ole32 / tests / clipboard.c
blobf0296ac684a69ed62c85cc184a7bcb1510f9aa31
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>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
29 #include "wine/test.h"
31 #define InitFormatEtc(fe, cf, med) \
33 (fe).cfFormat=cf;\
34 (fe).dwAspect=DVASPECT_CONTENT;\
35 (fe).ptd=NULL;\
36 (fe).tymed=med;\
37 (fe).lindex=-1;\
40 typedef struct DataObjectImpl {
41 const IDataObjectVtbl *lpVtbl;
42 LONG ref;
44 FORMATETC *fmtetc;
45 UINT fmtetc_cnt;
47 HANDLE text;
48 IStream *stm;
49 IStorage *stg;
50 } DataObjectImpl;
52 typedef struct EnumFormatImpl {
53 const IEnumFORMATETCVtbl *lpVtbl;
54 LONG ref;
56 FORMATETC *fmtetc;
57 UINT fmtetc_cnt;
59 UINT cur;
60 } EnumFormatImpl;
62 static BOOL expect_DataObjectImpl_QueryGetData = TRUE;
63 static ULONG DataObjectImpl_GetData_calls = 0;
64 static ULONG DataObjectImpl_EnumFormatEtc_calls = 0;
66 static UINT cf_stream, cf_storage, cf_another, cf_onemore;
68 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
70 static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
72 EnumFormatImpl *This = (EnumFormatImpl*)iface;
74 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) {
75 IEnumFORMATETC_AddRef(iface);
76 *ppvObj = This;
77 return S_OK;
79 *ppvObj = NULL;
80 return E_NOINTERFACE;
83 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
85 EnumFormatImpl *This = (EnumFormatImpl*)iface;
86 LONG ref = InterlockedIncrement(&This->ref);
87 return ref;
90 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
92 EnumFormatImpl *This = (EnumFormatImpl*)iface;
93 ULONG ref = InterlockedDecrement(&This->ref);
95 if(!ref) {
96 HeapFree(GetProcessHeap(), 0, This->fmtetc);
97 HeapFree(GetProcessHeap(), 0, This);
100 return ref;
103 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
104 FORMATETC *rgelt, ULONG *pceltFetched)
106 EnumFormatImpl *This = (EnumFormatImpl*)iface;
107 ULONG count, i;
109 if(!rgelt)
110 return E_INVALIDARG;
112 count = min(celt, This->fmtetc_cnt - This->cur);
113 for(i = 0; i < count; i++, This->cur++, rgelt++)
115 *rgelt = This->fmtetc[This->cur];
116 if(rgelt->ptd)
118 DWORD size = This->fmtetc[This->cur].ptd->tdSize;
119 rgelt->ptd = CoTaskMemAlloc(size);
120 memcpy(rgelt->ptd, This->fmtetc[This->cur].ptd, size);
123 if(pceltFetched)
124 *pceltFetched = count;
125 return count == celt ? S_OK : S_FALSE;
128 static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt)
130 ok(0, "unexpected call\n");
131 return E_NOTIMPL;
134 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
136 EnumFormatImpl *This = (EnumFormatImpl*)iface;
138 This->cur = 0;
139 return S_OK;
142 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
144 ok(0, "unexpected call\n");
145 return E_NOTIMPL;
148 static const IEnumFORMATETCVtbl VT_EnumFormatImpl = {
149 EnumFormatImpl_QueryInterface,
150 EnumFormatImpl_AddRef,
151 EnumFormatImpl_Release,
152 EnumFormatImpl_Next,
153 EnumFormatImpl_Skip,
154 EnumFormatImpl_Reset,
155 EnumFormatImpl_Clone
158 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
160 EnumFormatImpl *ret;
162 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl));
163 ret->lpVtbl = &VT_EnumFormatImpl;
164 ret->ref = 1;
165 ret->cur = 0;
166 ret->fmtetc_cnt = fmtetc_cnt;
167 ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC));
168 memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
169 *lplpformatetc = (LPENUMFORMATETC)ret;
170 return S_OK;
173 static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj)
175 DataObjectImpl *This = (DataObjectImpl*)iface;
177 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) {
178 IDataObject_AddRef(iface);
179 *ppvObj = This;
180 return S_OK;
182 *ppvObj = NULL;
183 return E_NOINTERFACE;
186 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
188 DataObjectImpl *This = (DataObjectImpl*)iface;
189 ULONG ref = InterlockedIncrement(&This->ref);
190 return ref;
193 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
195 DataObjectImpl *This = (DataObjectImpl*)iface;
196 ULONG ref = InterlockedDecrement(&This->ref);
198 if(!ref)
200 int i;
201 if(This->text) GlobalFree(This->text);
202 for(i = 0; i < This->fmtetc_cnt; i++)
203 HeapFree(GetProcessHeap(), 0, This->fmtetc[i].ptd);
204 HeapFree(GetProcessHeap(), 0, This->fmtetc);
205 if(This->stm) IStream_Release(This->stm);
206 if(This->stg) IStorage_Release(This->stg);
207 HeapFree(GetProcessHeap(), 0, This);
210 return ref;
213 static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
215 DataObjectImpl *This = (DataObjectImpl*)iface;
216 UINT i;
217 BOOL foundFormat = FALSE;
219 DataObjectImpl_GetData_calls++;
221 if(pformatetc->lindex != -1)
222 return DV_E_FORMATETC;
224 for(i = 0; i < This->fmtetc_cnt; i++)
226 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat)
228 foundFormat = TRUE;
229 if(This->fmtetc[i].tymed & pformatetc->tymed)
231 pmedium->pUnkForRelease = (LPUNKNOWN)iface;
232 IUnknown_AddRef(pmedium->pUnkForRelease);
234 if(pformatetc->cfFormat == CF_TEXT)
235 U(*pmedium).hGlobal = This->text;
236 else if(pformatetc->cfFormat == cf_stream)
237 U(*pmedium).pstm = This->stm;
238 else if(pformatetc->cfFormat == cf_storage)
239 U(*pmedium).pstg = This->stg;
240 return S_OK;
245 return foundFormat ? DV_E_TYMED : DV_E_FORMATETC;
248 static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
250 ok(0, "unexpected call\n");
251 return E_NOTIMPL;
254 static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc)
256 DataObjectImpl *This = (DataObjectImpl*)iface;
257 UINT i;
258 BOOL foundFormat = FALSE;
260 if (!expect_DataObjectImpl_QueryGetData)
261 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
263 if(pformatetc->lindex != -1)
264 return DV_E_LINDEX;
266 for(i=0; i<This->fmtetc_cnt; i++) {
267 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) {
268 foundFormat = TRUE;
269 if(This->fmtetc[i].tymed == pformatetc->tymed)
270 return S_OK;
273 return foundFormat?DV_E_FORMATETC:DV_E_TYMED;
276 static HRESULT WINAPI DataObjectImpl_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC *pformatectIn,
277 FORMATETC *pformatetcOut)
279 ok(0, "unexpected call\n");
280 return E_NOTIMPL;
283 static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc,
284 STGMEDIUM *pmedium, BOOL fRelease)
286 ok(0, "unexpected call\n");
287 return E_NOTIMPL;
290 static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwDirection,
291 IEnumFORMATETC **ppenumFormatEtc)
293 DataObjectImpl *This = (DataObjectImpl*)iface;
295 DataObjectImpl_EnumFormatEtc_calls++;
297 if(dwDirection != DATADIR_GET) {
298 ok(0, "unexpected direction %d\n", dwDirection);
299 return E_NOTIMPL;
301 return EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenumFormatEtc);
304 static HRESULT WINAPI DataObjectImpl_DAdvise(IDataObject* iface, FORMATETC *pformatetc, DWORD advf,
305 IAdviseSink *pAdvSink, DWORD *pdwConnection)
307 ok(0, "unexpected call\n");
308 return E_NOTIMPL;
311 static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection)
313 ok(0, "unexpected call\n");
314 return E_NOTIMPL;
317 static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise)
319 ok(0, "unexpected call\n");
320 return E_NOTIMPL;
323 static const IDataObjectVtbl VT_DataObjectImpl =
325 DataObjectImpl_QueryInterface,
326 DataObjectImpl_AddRef,
327 DataObjectImpl_Release,
328 DataObjectImpl_GetData,
329 DataObjectImpl_GetDataHere,
330 DataObjectImpl_QueryGetData,
331 DataObjectImpl_GetCanonicalFormatEtc,
332 DataObjectImpl_SetData,
333 DataObjectImpl_EnumFormatEtc,
334 DataObjectImpl_DAdvise,
335 DataObjectImpl_DUnadvise,
336 DataObjectImpl_EnumDAdvise
339 static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
341 DataObjectImpl *obj;
343 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
344 obj->lpVtbl = &VT_DataObjectImpl;
345 obj->ref = 1;
346 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1);
347 strcpy(GlobalLock(obj->text), text);
348 GlobalUnlock(obj->text);
349 obj->stm = NULL;
350 obj->stg = NULL;
352 obj->fmtetc_cnt = 1;
353 obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
354 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
356 *lplpdataobj = (LPDATAOBJECT)obj;
357 return S_OK;
360 static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj)
362 DataObjectImpl *obj;
363 const char *stm_data = "complex stream";
364 const char *text_data = "complex text";
365 ILockBytes *lbs;
366 static const WCHAR devname[] = {'m','y','d','e','v',0};
367 DEVMODEW dm;
369 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
370 obj->lpVtbl = &VT_DataObjectImpl;
371 obj->ref = 1;
372 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text_data) + 1);
373 strcpy(GlobalLock(obj->text), text_data);
374 GlobalUnlock(obj->text);
375 CreateStreamOnHGlobal(NULL, TRUE, &obj->stm);
376 IStream_Write(obj->stm, stm_data, strlen(stm_data), NULL);
378 CreateILockBytesOnHGlobal(NULL, TRUE, &lbs);
379 StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &obj->stg);
380 ILockBytes_Release(lbs);
382 obj->fmtetc_cnt = 5;
383 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
384 obj->fmtetc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, obj->fmtetc_cnt*sizeof(FORMATETC));
385 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
386 InitFormatEtc(obj->fmtetc[1], cf_stream, TYMED_ISTREAM);
387 InitFormatEtc(obj->fmtetc[2], cf_storage, TYMED_ISTORAGE);
388 InitFormatEtc(obj->fmtetc[3], cf_another, TYMED_ISTORAGE|TYMED_ISTREAM|TYMED_HGLOBAL);
389 memset(&dm, 0, sizeof(dm));
390 dm.dmSize = sizeof(dm);
391 dm.dmDriverExtra = 0;
392 lstrcpyW(dm.dmDeviceName, devname);
393 obj->fmtetc[3].ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(devname) + dm.dmSize + dm.dmDriverExtra);
394 obj->fmtetc[3].ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(devname) + dm.dmSize + dm.dmDriverExtra;
395 obj->fmtetc[3].ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
396 obj->fmtetc[3].ptd->tdDeviceNameOffset = 0;
397 obj->fmtetc[3].ptd->tdPortNameOffset = 0;
398 obj->fmtetc[3].ptd->tdExtDevmodeOffset = obj->fmtetc[3].ptd->tdDriverNameOffset + sizeof(devname);
399 lstrcpyW((WCHAR*)obj->fmtetc[3].ptd->tdData, devname);
400 memcpy(obj->fmtetc[3].ptd->tdData + sizeof(devname), &dm, dm.dmSize + dm.dmDriverExtra);
402 InitFormatEtc(obj->fmtetc[4], cf_stream, 0xfffff);
403 obj->fmtetc[4].dwAspect = DVASPECT_ICON;
405 *lplpdataobj = (LPDATAOBJECT)obj;
406 return S_OK;
409 static void test_get_clipboard(void)
411 HRESULT hr;
412 IDataObject *data_obj;
413 FORMATETC fmtetc;
414 STGMEDIUM stgmedium;
416 hr = OleGetClipboard(NULL);
417 ok(hr == E_INVALIDARG, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr);
419 hr = OleGetClipboard(&data_obj);
420 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
422 /* test IDataObject_QueryGetData */
424 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
425 expect_DataObjectImpl_QueryGetData = FALSE;
427 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
428 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
429 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
431 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
432 fmtetc.dwAspect = 0xdeadbeef;
433 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
434 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
436 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
437 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
438 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
439 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
441 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
442 fmtetc.lindex = 256;
443 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
444 ok(hr == DV_E_FORMATETC || broken(hr == S_OK),
445 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
446 if (hr == S_OK)
447 ReleaseStgMedium(&stgmedium);
449 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
450 fmtetc.cfFormat = CF_RIFF;
451 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
452 ok(hr == DV_E_CLIPFORMAT, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr);
454 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
455 fmtetc.tymed = TYMED_FILE;
456 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
457 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
459 expect_DataObjectImpl_QueryGetData = TRUE;
461 /* test IDataObject_GetData */
463 DataObjectImpl_GetData_calls = 0;
465 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
466 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
467 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
468 ReleaseStgMedium(&stgmedium);
470 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
471 fmtetc.dwAspect = 0xdeadbeef;
472 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
473 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
474 ReleaseStgMedium(&stgmedium);
476 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
477 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
478 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
479 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
480 ReleaseStgMedium(&stgmedium);
482 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
483 fmtetc.lindex = 256;
484 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
485 ok(hr == DV_E_FORMATETC || broken(hr == S_OK), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
486 if (hr == S_OK)
488 /* undo the unexpected success */
489 DataObjectImpl_GetData_calls--;
490 ReleaseStgMedium(&stgmedium);
493 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
494 fmtetc.cfFormat = CF_RIFF;
495 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
496 ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
498 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
499 fmtetc.tymed = TYMED_FILE;
500 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
501 ok(hr == DV_E_TYMED, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr);
503 ok(DataObjectImpl_GetData_calls == 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls);
505 IDataObject_Release(data_obj);
508 static void test_enum_fmtetc(IDataObject *src)
510 HRESULT hr;
511 IDataObject *data;
512 IEnumFORMATETC *enum_fmt, *src_enum;
513 FORMATETC fmt, src_fmt;
514 DWORD count = 0;
516 hr = OleGetClipboard(&data);
517 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
519 hr = IDataObject_EnumFormatEtc(data, DATADIR_SET, &enum_fmt);
520 ok(hr == E_NOTIMPL ||
521 broken(hr == E_INVALIDARG), /* win98 (not win98SE) */
522 "got %08x\n", hr);
524 DataObjectImpl_EnumFormatEtc_calls = 0;
525 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
526 ok(hr == S_OK, "got %08x\n", hr);
527 ok(DataObjectImpl_EnumFormatEtc_calls == 0, "EnumFormatEtc was called\n");
529 if(src) IDataObject_EnumFormatEtc(src, DATADIR_GET, &src_enum);
531 while((hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL)) == S_OK)
533 ok(src != NULL, "shouldn't be here\n");
534 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
535 ok(hr == S_OK, "%d: got %08x\n", count, hr);
536 ok(fmt.cfFormat == src_fmt.cfFormat, "%d: %04x %04x\n", count, fmt.cfFormat, src_fmt.cfFormat);
537 ok(fmt.dwAspect == src_fmt.dwAspect, "%d: %08x %08x\n", count, fmt.dwAspect, src_fmt.dwAspect);
538 ok(fmt.lindex == src_fmt.lindex, "%d: %08x %08x\n", count, fmt.lindex, src_fmt.lindex);
539 ok(fmt.tymed == src_fmt.tymed, "%d: %08x %08x\n", count, fmt.tymed, src_fmt.tymed);
540 if(fmt.ptd)
542 ok(src_fmt.ptd != NULL, "%d: expected non-NULL\n", count);
543 CoTaskMemFree(fmt.ptd);
544 CoTaskMemFree(src_fmt.ptd);
546 count++;
549 ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
551 if(src)
553 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
554 ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
555 IEnumFORMATETC_Release(src_enum);
558 hr = IEnumFORMATETC_Reset(enum_fmt);
559 ok(hr == S_OK, "got %08x\n", hr);
561 IEnumFORMATETC_Release(enum_fmt);
562 IDataObject_Release(data);
565 static void test_cf_dataobject(IDataObject *data)
567 UINT cf = 0;
568 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
569 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
570 BOOL found_dataobject = FALSE, found_priv_data = FALSE;
572 OpenClipboard(NULL);
575 cf = EnumClipboardFormats(cf);
576 if(cf == cf_dataobject)
578 HGLOBAL h = GetClipboardData(cf);
579 HWND *ptr = GlobalLock(h);
580 DWORD size = GlobalSize(h);
581 HWND clip_owner = GetClipboardOwner();
583 found_dataobject = TRUE;
584 ok(size >= sizeof(*ptr), "size %d\n", size);
585 if(data)
586 ok(*ptr == clip_owner, "hwnd %p clip_owner %p\n", *ptr, clip_owner);
587 else /* ole clipboard flushed */
588 ok(*ptr == NULL, "hwnd %p\n", *ptr);
589 GlobalUnlock(h);
591 else if(cf == cf_ole_priv_data)
593 found_priv_data = TRUE;
594 if(data)
596 HGLOBAL h = GetClipboardData(cf);
597 DWORD *ptr = GlobalLock(h);
598 DWORD size = GlobalSize(h);
600 if(size != ptr[1])
601 win_skip("Ole Private Data in win9x format\n");
602 else
604 HRESULT hr;
605 IEnumFORMATETC *enum_fmt;
606 DWORD count = 0;
607 FORMATETC fmt;
608 struct formatetcetc
610 FORMATETC fmt;
611 BOOL first_use_of_cf;
612 DWORD res[2];
613 } *fmt_ptr;
614 struct priv_data
616 DWORD res1;
617 DWORD size;
618 DWORD res2;
619 DWORD count;
620 DWORD res3[2];
621 struct formatetcetc fmts[1];
622 } *priv = (struct priv_data*)ptr;
623 CLIPFORMAT cfs_seen[10];
625 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
626 ok(hr == S_OK, "got %08x\n", hr);
627 fmt_ptr = priv->fmts;
629 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
631 int i;
632 BOOL seen_cf = FALSE;
634 ok(fmt_ptr->fmt.cfFormat == fmt.cfFormat,
635 "got %08x expected %08x\n", fmt_ptr->fmt.cfFormat, fmt.cfFormat);
636 ok(fmt_ptr->fmt.dwAspect == fmt.dwAspect, "got %08x expected %08x\n",
637 fmt_ptr->fmt.dwAspect, fmt.dwAspect);
638 ok(fmt_ptr->fmt.lindex == fmt.lindex, "got %08x expected %08x\n",
639 fmt_ptr->fmt.lindex, fmt.lindex);
640 ok(fmt_ptr->fmt.tymed == fmt.tymed, "got %08x expected %08x\n",
641 fmt_ptr->fmt.tymed, fmt.tymed);
642 for(i = 0; i < count; i++)
643 if(fmt_ptr->fmt.cfFormat == cfs_seen[i])
645 seen_cf = TRUE;
646 break;
648 cfs_seen[count] = fmt.cfFormat;
649 ok(fmt_ptr->first_use_of_cf == seen_cf ? FALSE : TRUE, "got %08x expected %08x\n",
650 fmt_ptr->first_use_of_cf, !seen_cf);
651 ok(fmt_ptr->res[0] == 0, "got %08x\n", fmt_ptr->res[1]);
652 ok(fmt_ptr->res[1] == 0, "got %08x\n", fmt_ptr->res[2]);
653 if(fmt.ptd)
655 DVTARGETDEVICE *target;
657 ok(fmt_ptr->fmt.ptd != NULL, "target device offset zero\n");
658 target = (DVTARGETDEVICE*)((char*)priv + (DWORD)fmt_ptr->fmt.ptd);
659 ok(!memcmp(target, fmt.ptd, fmt.ptd->tdSize), "target devices differ\n");
660 CoTaskMemFree(fmt.ptd);
662 fmt_ptr++;
663 count++;
665 ok(priv->res1 == 0, "got %08x\n", priv->res1);
666 ok(priv->res2 == 1, "got %08x\n", priv->res2);
667 ok(priv->count == count, "got %08x expected %08x\n", priv->count, count);
668 ok(priv->res3[0] == 0, "got %08x\n", priv->res3[0]);
669 ok(priv->res3[1] == 0, "got %08x\n", priv->res3[1]);
671 GlobalUnlock(h);
672 IEnumFORMATETC_Release(enum_fmt);
676 } while(cf);
677 CloseClipboard();
678 ok(found_dataobject, "didn't find cf_dataobject\n");
679 ok(found_priv_data, "didn't find cf_ole_priv_data\n");
682 static void test_set_clipboard(void)
684 HRESULT hr;
685 ULONG ref;
686 LPDATAOBJECT data1, data2, data_cmpl;
687 HGLOBAL hblob, h;
689 cf_stream = RegisterClipboardFormatA("stream format");
690 cf_storage = RegisterClipboardFormatA("storage format");
691 cf_another = RegisterClipboardFormatA("another format");
692 cf_onemore = RegisterClipboardFormatA("one more format");
694 hr = DataObjectImpl_CreateText("data1", &data1);
695 ok(SUCCEEDED(hr), "Failed to create data1 object: 0x%08x\n", hr);
696 if(FAILED(hr))
697 return;
698 hr = DataObjectImpl_CreateText("data2", &data2);
699 ok(SUCCEEDED(hr), "Failed to create data2 object: 0x%08x\n", hr);
700 if(FAILED(hr))
701 return;
702 hr = DataObjectImpl_CreateComplex(&data_cmpl);
703 ok(SUCCEEDED(hr), "Failed to create complex data object: 0x%08x\n", hr);
704 if(FAILED(hr))
705 return;
707 hr = OleSetClipboard(data1);
708 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
710 CoInitialize(NULL);
711 hr = OleSetClipboard(data1);
712 ok(hr == CO_E_NOTINITIALIZED ||
713 hr == CLIPBRD_E_CANT_SET, /* win9x */
714 "OleSetClipboard should have failed with "
715 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr);
716 CoUninitialize();
718 hr = OleInitialize(NULL);
719 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
721 hr = OleSetClipboard(data1);
722 ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr);
724 test_cf_dataobject(data1);
726 hr = OleIsCurrentClipboard(data1);
727 ok(hr == S_OK, "expected current clipboard to be data1, hr = 0x%08x\n", hr);
728 hr = OleIsCurrentClipboard(data2);
729 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
730 hr = OleIsCurrentClipboard(NULL);
731 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
733 test_get_clipboard();
735 hr = OleSetClipboard(data2);
736 ok(hr == S_OK, "failed to set clipboard to data2, hr = 0x%08x\n", hr);
737 hr = OleIsCurrentClipboard(data1);
738 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
739 hr = OleIsCurrentClipboard(data2);
740 ok(hr == S_OK, "expected current clipboard to be data2, hr = 0x%08x\n", hr);
741 hr = OleIsCurrentClipboard(NULL);
742 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
744 /* put a format directly onto the clipboard to show
745 OleFlushClipboard doesn't empty the clipboard */
746 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
747 OpenClipboard(NULL);
748 h = SetClipboardData(cf_onemore, hblob);
749 ok(h == hblob, "got %p\n", h);
750 h = GetClipboardData(cf_onemore);
751 ok(h == hblob ||
752 broken(h != NULL), /* win9x */
753 "got %p\n", h);
754 CloseClipboard();
756 hr = OleFlushClipboard();
757 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
758 hr = OleIsCurrentClipboard(data1);
759 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
760 hr = OleIsCurrentClipboard(data2);
761 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
762 hr = OleIsCurrentClipboard(NULL);
763 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
765 /* format should survive the flush */
766 OpenClipboard(NULL);
767 h = GetClipboardData(cf_onemore);
768 ok(h == hblob ||
769 broken(h != NULL), /* win9x */
770 "got %p\n", h);
771 CloseClipboard();
773 test_cf_dataobject(NULL);
775 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
777 OpenClipboard(NULL);
778 h = GetClipboardData(cf_onemore);
779 ok(h == NULL, "got %p\n", h);
780 CloseClipboard();
782 hr = OleSetClipboard(data_cmpl);
783 ok(hr == S_OK, "failed to set clipboard to complex data, hr = 0x%08x\n", hr);
784 test_cf_dataobject(data_cmpl);
785 test_enum_fmtetc(data_cmpl);
787 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
789 test_enum_fmtetc(NULL);
791 ref = IDataObject_Release(data1);
792 ok(ref == 0, "expected data1 ref=0, got %d\n", ref);
793 ref = IDataObject_Release(data2);
794 ok(ref == 0, "expected data2 ref=0, got %d\n", ref);
795 ref = IDataObject_Release(data_cmpl);
796 ok(ref == 0, "expected data_cmpl ref=0, got %d\n", ref);
798 OleUninitialize();
802 START_TEST(clipboard)
804 test_set_clipboard();