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
30 #include "wine/test.h"
32 #define InitFormatEtc(fe, cf, med) \
35 (fe).dwAspect=DVASPECT_CONTENT;\
41 static inline char *dump_fmtetc(FORMATETC
*fmt
)
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
);
50 typedef struct DataObjectImpl
{
51 const IDataObjectVtbl
*lpVtbl
;
62 typedef struct EnumFormatImpl
{
63 const IEnumFORMATETCVtbl
*lpVtbl
;
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
);
94 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
96 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
97 LONG ref
= InterlockedIncrement(&This
->ref
);
101 static ULONG WINAPI
EnumFormatImpl_Release(IEnumFORMATETC
*iface
)
103 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
104 ULONG ref
= InterlockedDecrement(&This
->ref
);
107 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
108 HeapFree(GetProcessHeap(), 0, This
);
114 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
115 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
117 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
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
];
129 DWORD size
= This
->fmtetc
[This
->cur
].ptd
->tdSize
;
130 rgelt
->ptd
= CoTaskMemAlloc(size
);
131 memcpy(rgelt
->ptd
, This
->fmtetc
[This
->cur
].ptd
, size
);
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");
145 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
147 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
153 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
155 ok(0, "unexpected call\n");
159 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
160 EnumFormatImpl_QueryInterface
,
161 EnumFormatImpl_AddRef
,
162 EnumFormatImpl_Release
,
165 EnumFormatImpl_Reset
,
169 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
173 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl
));
174 ret
->lpVtbl
= &VT_EnumFormatImpl
;
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
;
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
);
194 return E_NOINTERFACE
;
197 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
199 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
200 ULONG ref
= InterlockedIncrement(&This
->ref
);
204 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
206 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
207 ULONG ref
= InterlockedDecrement(&This
->ref
);
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
);
224 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
226 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
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
)
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
;
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
++;
280 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
282 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
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)
293 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
294 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
296 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
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");
310 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
311 STGMEDIUM
*pmedium
, BOOL fRelease
)
313 ok(0, "unexpected call\n");
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
);
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");
338 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
340 ok(0, "unexpected call\n");
344 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
346 ok(0, "unexpected call\n");
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
)
370 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
371 obj
->lpVtbl
= &VT_DataObjectImpl
;
373 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(text
) + 1);
374 strcpy(GlobalLock(obj
->text
), text
);
375 GlobalUnlock(obj
->text
);
380 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
381 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
383 *lplpdataobj
= (LPDATAOBJECT
)obj
;
387 const char *cmpl_stm_data
= "complex stream";
388 const char *cmpl_text_data
= "complex text";
390 static HRESULT
DataObjectImpl_CreateComplex(LPDATAOBJECT
*lplpdataobj
)
394 static const WCHAR devname
[] = {'m','y','d','e','v',0};
397 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
398 obj
->lpVtbl
= &VT_DataObjectImpl
;
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
);
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
;
440 static void test_get_clipboard(void)
443 IDataObject
*data_obj
;
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
);
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
);
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
);
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
);
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
)
543 IEnumFORMATETC
*enum_fmt
, *src_enum
;
544 FORMATETC fmt
, src_fmt
;
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) */
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
);
574 ok(src_fmt
.ptd
!= NULL
, "%d: expected non-NULL\n", count
);
575 CoTaskMemFree(fmt
.ptd
);
576 CoTaskMemFree(src_fmt
.ptd
);
581 ok(hr
== S_FALSE
, "%d: got %08x\n", count
, hr
);
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
)
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
;
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
);
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
);
623 else if(cf
== cf_ole_priv_data
)
625 found_priv_data
= TRUE
;
628 HGLOBAL h
= GetClipboardData(cf
);
629 DWORD
*ptr
= GlobalLock(h
);
630 DWORD size
= GlobalSize(h
);
633 win_skip("Ole Private Data in win9x format\n");
637 IEnumFORMATETC
*enum_fmt
;
643 BOOL first_use_of_cf
;
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
)
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
])
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]);
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
);
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]);
704 IEnumFORMATETC_Release(enum_fmt
);
708 else if(cf
== cf_stream
)
714 DataObjectImpl_GetDataHere_calls
= 0;
715 h
= GetClipboardData(cf
);
716 ok(DataObjectImpl_GetDataHere_calls
== 1, "got %d\n", DataObjectImpl_GetDataHere_calls
);
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");
723 else if(cf
== cf_global
)
729 DataObjectImpl_GetDataHere_calls
= 0;
730 h
= GetClipboardData(cf
);
731 ok(DataObjectImpl_GetDataHere_calls
== 0, "got %d\n", DataObjectImpl_GetDataHere_calls
);
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");
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)
748 LPDATAOBJECT data1
, data2
, data_cmpl
;
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
);
761 hr
= DataObjectImpl_CreateText("data2", &data2
);
762 ok(SUCCEEDED(hr
), "Failed to create data2 object: 0x%08x\n", hr
);
765 hr
= DataObjectImpl_CreateComplex(&data_cmpl
);
766 ok(SUCCEEDED(hr
), "Failed to create complex data object: 0x%08x\n", hr
);
770 hr
= OleSetClipboard(data1
);
771 ok(hr
== CO_E_NOTINITIALIZED
, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr
);
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
);
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);
811 h
= SetClipboardData(cf_onemore
, hblob
);
812 ok(h
== hblob
, "got %p\n", h
);
813 h
= GetClipboardData(cf_onemore
);
815 broken(h
!= NULL
), /* win9x */
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 */
830 h
= GetClipboardData(cf_onemore
);
832 broken(h
!= NULL
), /* win9x */
836 test_cf_dataobject(NULL
);
838 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
841 h
= GetClipboardData(cf_onemore
);
842 ok(h
== NULL
, "got %p\n", h
);
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
);
866 START_TEST(clipboard
)
868 test_set_clipboard();