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
29 #include "wine/test.h"
31 #define InitFormatEtc(fe, cf, med) \
34 (fe).dwAspect=DVASPECT_CONTENT;\
40 typedef struct DataObjectImpl
{
41 const IDataObjectVtbl
*lpVtbl
;
52 typedef struct EnumFormatImpl
{
53 const IEnumFORMATETCVtbl
*lpVtbl
;
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
);
83 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
85 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
86 LONG ref
= InterlockedIncrement(&This
->ref
);
90 static ULONG WINAPI
EnumFormatImpl_Release(IEnumFORMATETC
*iface
)
92 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
93 ULONG ref
= InterlockedDecrement(&This
->ref
);
96 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
97 HeapFree(GetProcessHeap(), 0, This
);
103 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
104 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
106 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
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
];
118 DWORD size
= This
->fmtetc
[This
->cur
].ptd
->tdSize
;
119 rgelt
->ptd
= CoTaskMemAlloc(size
);
120 memcpy(rgelt
->ptd
, This
->fmtetc
[This
->cur
].ptd
, size
);
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");
134 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
136 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
142 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
144 ok(0, "unexpected call\n");
148 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
149 EnumFormatImpl_QueryInterface
,
150 EnumFormatImpl_AddRef
,
151 EnumFormatImpl_Release
,
154 EnumFormatImpl_Reset
,
158 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
162 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl
));
163 ret
->lpVtbl
= &VT_EnumFormatImpl
;
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
;
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
);
183 return E_NOINTERFACE
;
186 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
188 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
189 ULONG ref
= InterlockedIncrement(&This
->ref
);
193 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
195 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
196 ULONG ref
= InterlockedDecrement(&This
->ref
);
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
);
213 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
215 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
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
)
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
;
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");
254 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
256 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
258 BOOL foundFormat
= FALSE
;
260 if (!expect_DataObjectImpl_QueryGetData
)
261 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
263 if(pformatetc
->lindex
!= -1)
266 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
267 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
269 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
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");
283 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
284 STGMEDIUM
*pmedium
, BOOL fRelease
)
286 ok(0, "unexpected call\n");
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
);
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");
311 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
313 ok(0, "unexpected call\n");
317 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
319 ok(0, "unexpected call\n");
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
)
343 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
344 obj
->lpVtbl
= &VT_DataObjectImpl
;
346 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(text
) + 1);
347 strcpy(GlobalLock(obj
->text
), text
);
348 GlobalUnlock(obj
->text
);
353 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
354 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
356 *lplpdataobj
= (LPDATAOBJECT
)obj
;
360 static HRESULT
DataObjectImpl_CreateComplex(LPDATAOBJECT
*lplpdataobj
)
363 const char *stm_data
= "complex stream";
364 const char *text_data
= "complex text";
366 static const WCHAR devname
[] = {'m','y','d','e','v',0};
369 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
370 obj
->lpVtbl
= &VT_DataObjectImpl
;
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
);
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
;
409 static void test_get_clipboard(void)
412 IDataObject
*data_obj
;
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
);
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
);
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
);
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
);
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
)
512 IEnumFORMATETC
*enum_fmt
, *src_enum
;
513 FORMATETC fmt
, src_fmt
;
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) */
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
);
542 ok(src_fmt
.ptd
!= NULL
, "%d: expected non-NULL\n", count
);
543 CoTaskMemFree(fmt
.ptd
);
544 CoTaskMemFree(src_fmt
.ptd
);
549 ok(hr
== S_FALSE
, "%d: got %08x\n", count
, hr
);
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
)
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
;
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
);
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
);
591 else if(cf
== cf_ole_priv_data
)
593 found_priv_data
= TRUE
;
596 HGLOBAL h
= GetClipboardData(cf
);
597 DWORD
*ptr
= GlobalLock(h
);
598 DWORD size
= GlobalSize(h
);
601 win_skip("Ole Private Data in win9x format\n");
605 IEnumFORMATETC
*enum_fmt
;
611 BOOL first_use_of_cf
;
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
)
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
])
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]);
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
);
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]);
672 IEnumFORMATETC_Release(enum_fmt
);
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)
686 LPDATAOBJECT data1
, data2
, data_cmpl
;
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
);
698 hr
= DataObjectImpl_CreateText("data2", &data2
);
699 ok(SUCCEEDED(hr
), "Failed to create data2 object: 0x%08x\n", hr
);
702 hr
= DataObjectImpl_CreateComplex(&data_cmpl
);
703 ok(SUCCEEDED(hr
), "Failed to create complex data object: 0x%08x\n", hr
);
707 hr
= OleSetClipboard(data1
);
708 ok(hr
== CO_E_NOTINITIALIZED
, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr
);
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
);
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);
748 h
= SetClipboardData(cf_onemore
, hblob
);
749 ok(h
== hblob
, "got %p\n", h
);
750 h
= GetClipboardData(cf_onemore
);
752 broken(h
!= NULL
), /* win9x */
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 */
767 h
= GetClipboardData(cf_onemore
);
769 broken(h
!= NULL
), /* win9x */
773 test_cf_dataobject(NULL
);
775 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
778 h
= GetClipboardData(cf_onemore
);
779 ok(h
== NULL
, "got %p\n", h
);
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
);
802 START_TEST(clipboard
)
804 test_set_clipboard();