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
22 #define NONAMELESSUNION
31 #include "wine/test.h"
33 #define InitFormatEtc(fe, cf, med) \
36 (fe).dwAspect=DVASPECT_CONTENT;\
42 static inline char *dump_fmtetc(FORMATETC
*fmt
)
46 snprintf(buf
, sizeof(buf
), "cf %04x ptd %p aspect %x lindex %d tymed %x",
47 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
51 typedef struct DataObjectImpl
{
52 const IDataObjectVtbl
*lpVtbl
;
63 typedef struct EnumFormatImpl
{
64 const IEnumFORMATETCVtbl
*lpVtbl
;
73 static BOOL expect_DataObjectImpl_QueryGetData
= TRUE
;
74 static ULONG DataObjectImpl_GetData_calls
= 0;
75 static ULONG DataObjectImpl_GetDataHere_calls
= 0;
76 static ULONG DataObjectImpl_EnumFormatEtc_calls
= 0;
78 static UINT cf_stream
, cf_storage
, cf_global
, cf_another
, cf_onemore
;
80 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT size
, LPENUMFORMATETC
*lplpformatetc
);
82 static HRESULT WINAPI
EnumFormatImpl_QueryInterface(IEnumFORMATETC
*iface
, REFIID riid
, LPVOID
*ppvObj
)
84 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
86 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumFORMATETC
)) {
87 IEnumFORMATETC_AddRef(iface
);
95 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
97 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
98 LONG ref
= InterlockedIncrement(&This
->ref
);
102 static ULONG WINAPI
EnumFormatImpl_Release(IEnumFORMATETC
*iface
)
104 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
105 ULONG ref
= InterlockedDecrement(&This
->ref
);
108 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
109 HeapFree(GetProcessHeap(), 0, This
);
115 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
116 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
118 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
121 trace("next: count %d cur %d\n", celt
, This
->cur
);
126 count
= min(celt
, This
->fmtetc_cnt
- This
->cur
);
127 for(i
= 0; i
< count
; i
++, This
->cur
++, rgelt
++)
129 *rgelt
= This
->fmtetc
[This
->cur
];
132 DWORD size
= This
->fmtetc
[This
->cur
].ptd
->tdSize
;
133 rgelt
->ptd
= CoTaskMemAlloc(size
);
134 memcpy(rgelt
->ptd
, This
->fmtetc
[This
->cur
].ptd
, size
);
138 *pceltFetched
= count
;
139 return count
== celt
? S_OK
: S_FALSE
;
142 static HRESULT WINAPI
EnumFormatImpl_Skip(IEnumFORMATETC
*iface
, ULONG celt
)
144 ok(0, "unexpected call\n");
148 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
150 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
156 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
158 ok(0, "unexpected call\n");
162 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
163 EnumFormatImpl_QueryInterface
,
164 EnumFormatImpl_AddRef
,
165 EnumFormatImpl_Release
,
168 EnumFormatImpl_Reset
,
172 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
176 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl
));
177 ret
->lpVtbl
= &VT_EnumFormatImpl
;
180 ret
->fmtetc_cnt
= fmtetc_cnt
;
181 ret
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt
*sizeof(FORMATETC
));
182 memcpy(ret
->fmtetc
, fmtetc
, fmtetc_cnt
*sizeof(FORMATETC
));
183 *lplpformatetc
= (LPENUMFORMATETC
)ret
;
187 static HRESULT WINAPI
DataObjectImpl_QueryInterface(IDataObject
*iface
, REFIID riid
, LPVOID
*ppvObj
)
189 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
191 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDataObject
)) {
192 IDataObject_AddRef(iface
);
197 return E_NOINTERFACE
;
200 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
202 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
203 ULONG ref
= InterlockedIncrement(&This
->ref
);
207 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
209 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
210 ULONG ref
= InterlockedDecrement(&This
->ref
);
215 if(This
->text
) GlobalFree(This
->text
);
216 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
217 HeapFree(GetProcessHeap(), 0, This
->fmtetc
[i
].ptd
);
218 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
219 if(This
->stm
) IStream_Release(This
->stm
);
220 if(This
->stg
) IStorage_Release(This
->stg
);
221 HeapFree(GetProcessHeap(), 0, This
);
227 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
229 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
231 BOOL foundFormat
= FALSE
;
233 trace("getdata: %s\n", dump_fmtetc(pformatetc
));
235 DataObjectImpl_GetData_calls
++;
237 if(pformatetc
->lindex
!= -1)
238 return DV_E_FORMATETC
;
240 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
242 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
)
245 if(This
->fmtetc
[i
].tymed
& pformatetc
->tymed
)
247 pmedium
->pUnkForRelease
= (LPUNKNOWN
)iface
;
248 IUnknown_AddRef(pmedium
->pUnkForRelease
);
250 if(pformatetc
->cfFormat
== CF_TEXT
|| pformatetc
->cfFormat
== cf_global
)
252 pmedium
->tymed
= TYMED_HGLOBAL
;
253 U(*pmedium
).hGlobal
= This
->text
;
255 else if(pformatetc
->cfFormat
== cf_stream
)
257 pmedium
->tymed
= TYMED_ISTREAM
;
258 IStream_AddRef(This
->stm
);
259 U(*pmedium
).pstm
= This
->stm
;
261 else if(pformatetc
->cfFormat
== cf_storage
|| pformatetc
->cfFormat
== cf_another
)
263 pmedium
->tymed
= TYMED_ISTORAGE
;
264 IStorage_AddRef(This
->stg
);
265 U(*pmedium
).pstg
= This
->stg
;
272 return foundFormat
? DV_E_TYMED
: DV_E_FORMATETC
;
275 static HRESULT WINAPI
DataObjectImpl_GetDataHere(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
277 trace("getdatahere: %s\n", dump_fmtetc(pformatetc
));
278 DataObjectImpl_GetDataHere_calls
++;
283 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
285 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
287 BOOL foundFormat
= FALSE
;
289 trace("querygetdata: %s\n", dump_fmtetc(pformatetc
));
290 if (!expect_DataObjectImpl_QueryGetData
)
291 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
293 if(pformatetc
->lindex
!= -1)
296 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
297 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
299 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
303 return foundFormat
?DV_E_FORMATETC
:DV_E_TYMED
;
306 static HRESULT WINAPI
DataObjectImpl_GetCanonicalFormatEtc(IDataObject
* iface
, FORMATETC
*pformatectIn
,
307 FORMATETC
*pformatetcOut
)
309 ok(0, "unexpected call\n");
313 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
314 STGMEDIUM
*pmedium
, BOOL fRelease
)
316 ok(0, "unexpected call\n");
320 static HRESULT WINAPI
DataObjectImpl_EnumFormatEtc(IDataObject
* iface
, DWORD dwDirection
,
321 IEnumFORMATETC
**ppenumFormatEtc
)
323 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
325 DataObjectImpl_EnumFormatEtc_calls
++;
327 if(dwDirection
!= DATADIR_GET
) {
328 ok(0, "unexpected direction %d\n", dwDirection
);
331 return EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenumFormatEtc
);
334 static HRESULT WINAPI
DataObjectImpl_DAdvise(IDataObject
* iface
, FORMATETC
*pformatetc
, DWORD advf
,
335 IAdviseSink
*pAdvSink
, DWORD
*pdwConnection
)
337 ok(0, "unexpected call\n");
341 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
343 ok(0, "unexpected call\n");
347 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
349 ok(0, "unexpected call\n");
353 static const IDataObjectVtbl VT_DataObjectImpl
=
355 DataObjectImpl_QueryInterface
,
356 DataObjectImpl_AddRef
,
357 DataObjectImpl_Release
,
358 DataObjectImpl_GetData
,
359 DataObjectImpl_GetDataHere
,
360 DataObjectImpl_QueryGetData
,
361 DataObjectImpl_GetCanonicalFormatEtc
,
362 DataObjectImpl_SetData
,
363 DataObjectImpl_EnumFormatEtc
,
364 DataObjectImpl_DAdvise
,
365 DataObjectImpl_DUnadvise
,
366 DataObjectImpl_EnumDAdvise
369 static HRESULT
DataObjectImpl_CreateText(LPCSTR text
, LPDATAOBJECT
*lplpdataobj
)
373 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
374 obj
->lpVtbl
= &VT_DataObjectImpl
;
376 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(text
) + 1);
377 strcpy(GlobalLock(obj
->text
), text
);
378 GlobalUnlock(obj
->text
);
383 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
384 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
386 *lplpdataobj
= (LPDATAOBJECT
)obj
;
390 const char *cmpl_stm_data
= "complex stream";
391 const char *cmpl_text_data
= "complex text";
392 const WCHAR device_name
[] = {'m','y','d','e','v',0};
394 static HRESULT
DataObjectImpl_CreateComplex(LPDATAOBJECT
*lplpdataobj
)
400 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
401 obj
->lpVtbl
= &VT_DataObjectImpl
;
403 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(cmpl_text_data
) + 1);
404 strcpy(GlobalLock(obj
->text
), cmpl_text_data
);
405 GlobalUnlock(obj
->text
);
406 CreateStreamOnHGlobal(NULL
, TRUE
, &obj
->stm
);
407 IStream_Write(obj
->stm
, cmpl_stm_data
, strlen(cmpl_stm_data
), NULL
);
409 CreateILockBytesOnHGlobal(NULL
, TRUE
, &lbs
);
410 StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &obj
->stg
);
411 ILockBytes_Release(lbs
);
414 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
415 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
416 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
417 InitFormatEtc(obj
->fmtetc
[1], cf_stream
, TYMED_ISTREAM
);
418 InitFormatEtc(obj
->fmtetc
[2], cf_storage
, TYMED_ISTORAGE
);
419 InitFormatEtc(obj
->fmtetc
[3], cf_another
, TYMED_ISTORAGE
|TYMED_ISTREAM
|TYMED_HGLOBAL
);
420 memset(&dm
, 0, sizeof(dm
));
421 dm
.dmSize
= sizeof(dm
);
422 dm
.dmDriverExtra
= 0;
423 lstrcpyW(dm
.dmDeviceName
, device_name
);
424 obj
->fmtetc
[3].ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
);
425 obj
->fmtetc
[3].ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
;
426 obj
->fmtetc
[3].ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
427 obj
->fmtetc
[3].ptd
->tdDeviceNameOffset
= 0;
428 obj
->fmtetc
[3].ptd
->tdPortNameOffset
= 0;
429 obj
->fmtetc
[3].ptd
->tdExtDevmodeOffset
= obj
->fmtetc
[3].ptd
->tdDriverNameOffset
+ sizeof(device_name
);
430 lstrcpyW((WCHAR
*)obj
->fmtetc
[3].ptd
->tdData
, device_name
);
431 memcpy(obj
->fmtetc
[3].ptd
->tdData
+ sizeof(device_name
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
433 InitFormatEtc(obj
->fmtetc
[4], cf_global
, TYMED_HGLOBAL
);
434 InitFormatEtc(obj
->fmtetc
[5], cf_another
, TYMED_HGLOBAL
);
435 InitFormatEtc(obj
->fmtetc
[6], cf_another
, 0xfffff);
436 InitFormatEtc(obj
->fmtetc
[7], cf_another
, 0xfffff);
437 obj
->fmtetc
[7].dwAspect
= DVASPECT_ICON
;
439 *lplpdataobj
= (LPDATAOBJECT
)obj
;
443 static void test_get_clipboard(void)
446 IDataObject
*data_obj
;
450 hr
= OleGetClipboard(NULL
);
451 ok(hr
== E_INVALIDARG
, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr
);
453 hr
= OleGetClipboard(&data_obj
);
454 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
456 /* test IDataObject_QueryGetData */
458 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
459 expect_DataObjectImpl_QueryGetData
= FALSE
;
461 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
462 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
463 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
465 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
466 fmtetc
.dwAspect
= 0xdeadbeef;
467 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
468 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
470 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
471 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
472 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
473 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
475 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
477 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
478 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
),
479 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
481 ReleaseStgMedium(&stgmedium
);
483 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
484 fmtetc
.cfFormat
= CF_RIFF
;
485 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
486 ok(hr
== DV_E_CLIPFORMAT
, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr
);
488 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
489 fmtetc
.tymed
= TYMED_FILE
;
490 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
491 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
493 expect_DataObjectImpl_QueryGetData
= TRUE
;
495 /* test IDataObject_GetData */
497 DataObjectImpl_GetData_calls
= 0;
499 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
500 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
501 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
502 ReleaseStgMedium(&stgmedium
);
504 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
505 fmtetc
.dwAspect
= 0xdeadbeef;
506 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
507 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
508 ReleaseStgMedium(&stgmedium
);
510 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
511 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
512 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
513 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
514 ReleaseStgMedium(&stgmedium
);
516 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
518 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
519 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
522 /* undo the unexpected success */
523 DataObjectImpl_GetData_calls
--;
524 ReleaseStgMedium(&stgmedium
);
527 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
528 fmtetc
.cfFormat
= CF_RIFF
;
529 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
530 ok(hr
== DV_E_FORMATETC
, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
532 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
533 fmtetc
.tymed
= TYMED_FILE
;
534 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
535 ok(hr
== DV_E_TYMED
, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr
);
537 ok(DataObjectImpl_GetData_calls
== 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls
);
539 IDataObject_Release(data_obj
);
542 static void test_enum_fmtetc(IDataObject
*src
)
546 IEnumFORMATETC
*enum_fmt
, *src_enum
;
547 FORMATETC fmt
, src_fmt
;
550 hr
= OleGetClipboard(&data
);
551 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
553 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_SET
, &enum_fmt
);
554 ok(hr
== E_NOTIMPL
||
555 broken(hr
== E_INVALIDARG
), /* win98 (not win98SE) */
558 DataObjectImpl_EnumFormatEtc_calls
= 0;
559 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
560 ok(hr
== S_OK
, "got %08x\n", hr
);
561 ok(DataObjectImpl_EnumFormatEtc_calls
== 0, "EnumFormatEtc was called\n");
563 if(src
) IDataObject_EnumFormatEtc(src
, DATADIR_GET
, &src_enum
);
565 while((hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
)) == S_OK
)
567 ok(src
!= NULL
, "shouldn't be here\n");
568 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
569 ok(hr
== S_OK
, "%d: got %08x\n", count
, hr
);
570 trace("%d: %s\n", count
, dump_fmtetc(&fmt
));
571 ok(fmt
.cfFormat
== src_fmt
.cfFormat
, "%d: %04x %04x\n", count
, fmt
.cfFormat
, src_fmt
.cfFormat
);
572 ok(fmt
.dwAspect
== src_fmt
.dwAspect
, "%d: %08x %08x\n", count
, fmt
.dwAspect
, src_fmt
.dwAspect
);
573 ok(fmt
.lindex
== src_fmt
.lindex
, "%d: %08x %08x\n", count
, fmt
.lindex
, src_fmt
.lindex
);
574 ok(fmt
.tymed
== src_fmt
.tymed
, "%d: %08x %08x\n", count
, fmt
.tymed
, src_fmt
.tymed
);
577 ok(src_fmt
.ptd
!= NULL
, "%d: expected non-NULL\n", count
);
578 CoTaskMemFree(fmt
.ptd
);
579 CoTaskMemFree(src_fmt
.ptd
);
584 ok(hr
== S_FALSE
, "%d: got %08x\n", count
, hr
);
588 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
590 broken(hr
== S_OK
&& count
== 5), /* win9x and winme don't enumerate duplicated cf's */
591 "%d: got %08x\n", count
, hr
);
592 IEnumFORMATETC_Release(src_enum
);
595 hr
= IEnumFORMATETC_Reset(enum_fmt
);
596 ok(hr
== S_OK
, "got %08x\n", hr
);
598 if(src
) /* Exercise the enumerator a bit */
600 IEnumFORMATETC
*clone
;
603 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
604 ok(hr
== S_OK
, "got %08x\n", hr
);
605 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
606 ok(hr
== S_OK
, "got %08x\n", hr
);
607 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
608 ok(hr
== S_OK
, "got %08x\n", hr
);
610 hr
= IEnumFORMATETC_Reset(enum_fmt
);
611 ok(hr
== S_OK
, "got %08x\n", hr
);
612 hr
= IEnumFORMATETC_Skip(enum_fmt
, 2);
613 ok(hr
== S_OK
, "got %08x\n", hr
);
615 hr
= IEnumFORMATETC_Clone(enum_fmt
, &clone
);
616 ok(hr
== S_OK
, "got %08x\n", hr
);
617 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
618 ok(hr
== S_OK
, "got %08x\n", hr
);
619 ok(fmt
.cfFormat
== third_fmt
.cfFormat
, "formats don't match\n");
620 hr
= IEnumFORMATETC_Next(clone
, 1, &fmt
, NULL
);
621 ok(hr
== S_OK
, "got %08x\n", hr
);
622 ok(fmt
.cfFormat
== third_fmt
.cfFormat
, "formats don't match\n");
623 IEnumFORMATETC_Release(clone
);
626 IEnumFORMATETC_Release(enum_fmt
);
627 IDataObject_Release(data
);
630 static void test_no_cf_dataobject(void)
632 UINT cf_dataobject
= RegisterClipboardFormatA("DataObject");
633 UINT cf_ole_priv_data
= RegisterClipboardFormatA("Ole Private Data");
637 h
= GetClipboardData(cf_dataobject
);
638 ok(!h
, "got %p\n", h
);
639 h
= GetClipboardData(cf_ole_priv_data
);
640 ok(!h
, "got %p\n", h
);
645 static void test_cf_dataobject(IDataObject
*data
)
648 UINT cf_dataobject
= RegisterClipboardFormatA("DataObject");
649 UINT cf_ole_priv_data
= RegisterClipboardFormatA("Ole Private Data");
650 BOOL found_dataobject
= FALSE
, found_priv_data
= FALSE
;
655 cf
= EnumClipboardFormats(cf
);
656 if(cf
== cf_dataobject
)
658 HGLOBAL h
= GetClipboardData(cf
);
659 HWND
*ptr
= GlobalLock(h
);
660 DWORD size
= GlobalSize(h
);
661 HWND clip_owner
= GetClipboardOwner();
663 found_dataobject
= TRUE
;
664 ok(size
>= sizeof(*ptr
), "size %d\n", size
);
666 ok(*ptr
== clip_owner
, "hwnd %p clip_owner %p\n", *ptr
, clip_owner
);
667 else /* ole clipboard flushed */
668 ok(*ptr
== NULL
, "hwnd %p\n", *ptr
);
671 else if(cf
== cf_ole_priv_data
)
673 found_priv_data
= TRUE
;
676 HGLOBAL h
= GetClipboardData(cf
);
677 DWORD
*ptr
= GlobalLock(h
);
678 DWORD size
= GlobalSize(h
);
681 win_skip("Ole Private Data in win9x format\n");
685 IEnumFORMATETC
*enum_fmt
;
691 BOOL first_use_of_cf
;
701 struct formatetcetc fmts
[1];
702 } *priv
= (struct priv_data
*)ptr
;
703 CLIPFORMAT cfs_seen
[10];
705 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
706 ok(hr
== S_OK
, "got %08x\n", hr
);
707 fmt_ptr
= priv
->fmts
;
709 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
712 BOOL seen_cf
= FALSE
;
714 ok(fmt_ptr
->fmt
.cfFormat
== fmt
.cfFormat
,
715 "got %08x expected %08x\n", fmt_ptr
->fmt
.cfFormat
, fmt
.cfFormat
);
716 ok(fmt_ptr
->fmt
.dwAspect
== fmt
.dwAspect
, "got %08x expected %08x\n",
717 fmt_ptr
->fmt
.dwAspect
, fmt
.dwAspect
);
718 ok(fmt_ptr
->fmt
.lindex
== fmt
.lindex
, "got %08x expected %08x\n",
719 fmt_ptr
->fmt
.lindex
, fmt
.lindex
);
720 ok(fmt_ptr
->fmt
.tymed
== fmt
.tymed
, "got %08x expected %08x\n",
721 fmt_ptr
->fmt
.tymed
, fmt
.tymed
);
722 for(i
= 0; i
< count
; i
++)
723 if(fmt_ptr
->fmt
.cfFormat
== cfs_seen
[i
])
728 cfs_seen
[count
] = fmt
.cfFormat
;
729 ok(fmt_ptr
->first_use_of_cf
== seen_cf
? FALSE
: TRUE
, "got %08x expected %08x\n",
730 fmt_ptr
->first_use_of_cf
, !seen_cf
);
731 ok(fmt_ptr
->res
[0] == 0, "got %08x\n", fmt_ptr
->res
[1]);
732 ok(fmt_ptr
->res
[1] == 0, "got %08x\n", fmt_ptr
->res
[2]);
735 DVTARGETDEVICE
*target
;
737 ok(fmt_ptr
->fmt
.ptd
!= NULL
, "target device offset zero\n");
738 target
= (DVTARGETDEVICE
*)((char*)priv
+ (DWORD_PTR
)fmt_ptr
->fmt
.ptd
);
739 ok(!memcmp(target
, fmt
.ptd
, fmt
.ptd
->tdSize
), "target devices differ\n");
740 CoTaskMemFree(fmt
.ptd
);
745 ok(priv
->res1
== 0, "got %08x\n", priv
->res1
);
746 ok(priv
->res2
== 1, "got %08x\n", priv
->res2
);
747 ok(priv
->count
== count
, "got %08x expected %08x\n", priv
->count
, count
);
748 ok(priv
->res3
[0] == 0, "got %08x\n", priv
->res3
[0]);
750 /* win64 sets the lsb */
751 if(sizeof(fmt_ptr
->fmt
.ptd
) == 8)
752 todo_wine
ok(priv
->res3
[1] == 1, "got %08x\n", priv
->res3
[1]);
754 ok(priv
->res3
[1] == 0, "got %08x\n", priv
->res3
[1]);
757 IEnumFORMATETC_Release(enum_fmt
);
761 else if(cf
== cf_stream
)
767 DataObjectImpl_GetDataHere_calls
= 0;
768 h
= GetClipboardData(cf
);
769 ok(DataObjectImpl_GetDataHere_calls
== 1, "got %d\n", DataObjectImpl_GetDataHere_calls
);
771 size
= GlobalSize(h
);
772 ok(size
== strlen(cmpl_stm_data
) ||
773 broken(size
> strlen(cmpl_stm_data
)), /* win9x, winme */
774 "expected %d got %d\n", lstrlenA(cmpl_stm_data
), size
);
775 ok(!memcmp(ptr
, cmpl_stm_data
, strlen(cmpl_stm_data
)), "mismatch\n");
778 else if(cf
== cf_global
)
784 DataObjectImpl_GetDataHere_calls
= 0;
785 h
= GetClipboardData(cf
);
786 ok(DataObjectImpl_GetDataHere_calls
== 0, "got %d\n", DataObjectImpl_GetDataHere_calls
);
788 size
= GlobalSize(h
);
789 ok(size
== strlen(cmpl_text_data
) + 1 ||
790 broken(size
> strlen(cmpl_text_data
) + 1), /* win9x, winme */
791 "expected %d got %d\n", lstrlenA(cmpl_text_data
) + 1, size
);
792 ok(!memcmp(ptr
, cmpl_text_data
, strlen(cmpl_text_data
) + 1), "mismatch\n");
797 ok(found_dataobject
, "didn't find cf_dataobject\n");
798 ok(found_priv_data
, "didn't find cf_ole_priv_data\n");
801 static void test_set_clipboard(void)
805 LPDATAOBJECT data1
, data2
, data_cmpl
;
808 cf_stream
= RegisterClipboardFormatA("stream format");
809 cf_storage
= RegisterClipboardFormatA("storage format");
810 cf_global
= RegisterClipboardFormatA("global format");
811 cf_another
= RegisterClipboardFormatA("another format");
812 cf_onemore
= RegisterClipboardFormatA("one more format");
814 hr
= DataObjectImpl_CreateText("data1", &data1
);
815 ok(SUCCEEDED(hr
), "Failed to create data1 object: 0x%08x\n", hr
);
818 hr
= DataObjectImpl_CreateText("data2", &data2
);
819 ok(SUCCEEDED(hr
), "Failed to create data2 object: 0x%08x\n", hr
);
822 hr
= DataObjectImpl_CreateComplex(&data_cmpl
);
823 ok(SUCCEEDED(hr
), "Failed to create complex data object: 0x%08x\n", hr
);
827 hr
= OleSetClipboard(data1
);
828 ok(hr
== CO_E_NOTINITIALIZED
, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr
);
831 hr
= OleSetClipboard(data1
);
832 ok(hr
== CO_E_NOTINITIALIZED
||
833 hr
== CLIPBRD_E_CANT_SET
, /* win9x */
834 "OleSetClipboard should have failed with "
835 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr
);
838 hr
= OleInitialize(NULL
);
839 ok(hr
== S_OK
, "OleInitialize failed with error 0x%08x\n", hr
);
841 hr
= OleSetClipboard(data1
);
842 ok(hr
== S_OK
, "failed to set clipboard to data1, hr = 0x%08x\n", hr
);
844 test_cf_dataobject(data1
);
846 hr
= OleIsCurrentClipboard(data1
);
847 ok(hr
== S_OK
, "expected current clipboard to be data1, hr = 0x%08x\n", hr
);
848 hr
= OleIsCurrentClipboard(data2
);
849 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
850 hr
= OleIsCurrentClipboard(NULL
);
851 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
853 test_get_clipboard();
855 hr
= OleSetClipboard(data2
);
856 ok(hr
== S_OK
, "failed to set clipboard to data2, hr = 0x%08x\n", hr
);
857 hr
= OleIsCurrentClipboard(data1
);
858 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
859 hr
= OleIsCurrentClipboard(data2
);
860 ok(hr
== S_OK
, "expected current clipboard to be data2, hr = 0x%08x\n", hr
);
861 hr
= OleIsCurrentClipboard(NULL
);
862 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
864 /* put a format directly onto the clipboard to show
865 OleFlushClipboard doesn't empty the clipboard */
866 hblob
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
|GMEM_ZEROINIT
, 10);
868 h
= SetClipboardData(cf_onemore
, hblob
);
869 ok(h
== hblob
, "got %p\n", h
);
870 h
= GetClipboardData(cf_onemore
);
872 broken(h
!= NULL
), /* win9x */
876 hr
= OleFlushClipboard();
877 ok(hr
== S_OK
, "failed to flush clipboard, hr = 0x%08x\n", hr
);
878 hr
= OleIsCurrentClipboard(data1
);
879 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
880 hr
= OleIsCurrentClipboard(data2
);
881 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
882 hr
= OleIsCurrentClipboard(NULL
);
883 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
885 /* format should survive the flush */
887 h
= GetClipboardData(cf_onemore
);
889 broken(h
!= NULL
), /* win9x */
893 test_cf_dataobject(NULL
);
895 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
898 h
= GetClipboardData(cf_onemore
);
899 ok(h
== NULL
, "got %p\n", h
);
902 trace("setting complex\n");
903 hr
= OleSetClipboard(data_cmpl
);
904 ok(hr
== S_OK
, "failed to set clipboard to complex data, hr = 0x%08x\n", hr
);
905 test_cf_dataobject(data_cmpl
);
906 test_enum_fmtetc(data_cmpl
);
908 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
910 test_no_cf_dataobject();
911 test_enum_fmtetc(NULL
);
913 ref
= IDataObject_Release(data1
);
914 ok(ref
== 0, "expected data1 ref=0, got %d\n", ref
);
915 ref
= IDataObject_Release(data2
);
916 ok(ref
== 0, "expected data2 ref=0, got %d\n", ref
);
917 ref
= IDataObject_Release(data_cmpl
);
918 ok(ref
== 0, "expected data_cmpl ref=0, got %d\n", ref
);
923 static inline ULONG
count_refs(IDataObject
*d
)
925 IDataObject_AddRef(d
);
926 return IDataObject_Release(d
);
929 static void test_consumer_refs(void)
932 IDataObject
*src
, *src2
, *get1
, *get2
, *get3
;
933 ULONG refs
, old_refs
;
937 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
941 /* First show that each clipboard state results in
942 a different data object */
944 hr
= DataObjectImpl_CreateText("data1", &src
);
945 ok(hr
== S_OK
, "got %08x\n", hr
);
946 hr
= DataObjectImpl_CreateText("data2", &src2
);
947 ok(hr
== S_OK
, "got %08x\n", hr
);
949 hr
= OleSetClipboard(src
);
950 ok(hr
== S_OK
, "got %08x\n", hr
);
952 hr
= OleGetClipboard(&get1
);
953 ok(hr
== S_OK
, "got %08x\n", hr
);
955 hr
= OleGetClipboard(&get2
);
956 ok(hr
== S_OK
, "got %08x\n", hr
);
959 broken(get1
!= get2
), /* win9x, winme & nt4 */
960 "data objects differ\n");
961 refs
= IDataObject_Release(get2
);
962 ok(refs
== (get1
== get2
? 1 : 0), "got %d\n", refs
);
966 DataObjectImpl_GetData_calls
= 0;
967 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
968 ok(hr
== S_OK
, "got %08x\n", hr
);
969 ok(DataObjectImpl_GetData_calls
== 0, "GetData called\n");
970 ReleaseStgMedium(&med
);
972 hr
= OleGetClipboard(&get2
);
973 ok(hr
== S_OK
, "got %08x\n", hr
);
975 ok(get1
!= get2
, "data objects match\n");
977 OleSetClipboard(NULL
);
979 hr
= OleGetClipboard(&get3
);
980 ok(hr
== S_OK
, "got %08x\n", hr
);
982 ok(get1
!= get3
, "data objects match\n");
983 ok(get2
!= get3
, "data objects match\n");
985 IDataObject_Release(get3
);
986 IDataObject_Release(get2
);
987 IDataObject_Release(get1
);
989 /* Now call GetData before the flush and show that this
990 takes a ref on our src data obj. */
992 hr
= OleSetClipboard(src
);
993 ok(hr
== S_OK
, "got %08x\n", hr
);
995 old_refs
= count_refs(src
);
997 hr
= OleGetClipboard(&get1
);
998 ok(hr
== S_OK
, "got %08x\n", hr
);
1000 refs
= count_refs(src
);
1001 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
1003 DataObjectImpl_GetData_calls
= 0;
1004 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1005 ok(hr
== S_OK
, "got %08x\n", hr
);
1006 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1007 ReleaseStgMedium(&med
);
1008 refs
= count_refs(src
);
1009 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
1011 OleFlushClipboard();
1013 DataObjectImpl_GetData_calls
= 0;
1014 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1015 ok(hr
== S_OK
, "got %08x\n", hr
);
1016 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1017 ReleaseStgMedium(&med
);
1019 refs
= count_refs(src
);
1020 ok(refs
== 2, "%d\n", refs
);
1022 IDataObject_Release(get1
);
1024 refs
= count_refs(src
);
1025 ok(refs
== 1, "%d\n", refs
);
1027 /* Now set a second src object before the call to GetData
1028 and show that GetData calls that second src. */
1030 hr
= OleSetClipboard(src
);
1031 ok(hr
== S_OK
, "got %08x\n", hr
);
1033 old_refs
= count_refs(src
);
1035 hr
= OleGetClipboard(&get1
);
1036 ok(hr
== S_OK
, "got %08x\n", hr
);
1038 refs
= count_refs(src
);
1039 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
1041 hr
= OleSetClipboard(src2
);
1042 ok(hr
== S_OK
, "got %08x\n", hr
);
1044 old_refs
= count_refs(src2
);
1046 DataObjectImpl_GetData_calls
= 0;
1047 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1048 ok(hr
== S_OK
, "got %08x\n", hr
);
1049 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1050 ReleaseStgMedium(&med
);
1052 refs
= count_refs(src
);
1053 ok(refs
== 1, "%d\n", refs
);
1054 refs
= count_refs(src2
);
1055 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
1057 OleSetClipboard(NULL
);
1059 refs
= count_refs(src2
);
1060 ok(refs
== 2, "%d\n", refs
);
1062 IDataObject_Release(get1
);
1064 IDataObject_Release(src2
);
1065 IDataObject_Release(src
);
1070 static void test_flushed_getdata(void)
1073 IDataObject
*src
, *get
;
1079 OleInitialize(NULL
);
1081 hr
= DataObjectImpl_CreateComplex(&src
);
1082 ok(hr
== S_OK
, "got %08x\n", hr
);
1084 hr
= OleSetClipboard(src
);
1085 ok(hr
== S_OK
, "got %08x\n", hr
);
1087 hr
= OleFlushClipboard();
1088 ok(hr
== S_OK
, "got %08x\n", hr
);
1090 hr
= OleGetClipboard(&get
);
1091 ok(hr
== S_OK
, "got %08x\n", hr
);
1093 /* global format -> global & stream */
1095 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1096 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1097 ok(hr
== S_OK
, "got %08x\n", hr
);
1098 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1099 ReleaseStgMedium(&med
);
1101 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTREAM
);
1102 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1103 ok(hr
== S_OK
, "got %08x\n", hr
);
1104 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1105 ReleaseStgMedium(&med
);
1107 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTORAGE
);
1108 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1109 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1111 InitFormatEtc(fmt
, CF_TEXT
, 0xffff);
1112 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1113 ok(hr
== S_OK
, "got %08x\n", hr
);
1114 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1115 ReleaseStgMedium(&med
);
1117 /* stream format -> global & stream */
1119 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTREAM
);
1120 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1121 ok(hr
== S_OK
, "got %08x\n", hr
);
1122 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1123 ReleaseStgMedium(&med
);
1125 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTORAGE
);
1126 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1127 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1129 InitFormatEtc(fmt
, cf_stream
, TYMED_HGLOBAL
);
1130 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1131 ok(hr
== S_OK
, "got %08x\n", hr
);
1132 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1133 ReleaseStgMedium(&med
);
1135 InitFormatEtc(fmt
, cf_stream
, 0xffff);
1136 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1137 ok(hr
== S_OK
, "got %08x\n", hr
);
1138 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1139 ReleaseStgMedium(&med
);
1141 /* storage format -> global, stream & storage */
1143 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTORAGE
);
1144 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1145 ok(hr
== S_OK
, "got %08x\n", hr
);
1146 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1147 hr
= IStorage_Stat(med
.u
.pstg
, &stat
, STATFLAG_NONAME
);
1148 ok(hr
== S_OK
, "got %08x\n", hr
);
1149 ok(stat
.grfMode
== (STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
), "got %08x\n", stat
.grfMode
);
1150 ReleaseStgMedium(&med
);
1152 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTREAM
);
1153 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1154 ok(hr
== S_OK
, "got %08x\n", hr
);
1155 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1156 ReleaseStgMedium(&med
);
1158 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
);
1159 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1160 ok(hr
== S_OK
, "got %08x\n", hr
);
1161 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1162 ReleaseStgMedium(&med
);
1164 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
| TYMED_ISTREAM
);
1165 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1166 ok(hr
== S_OK
, "got %08x\n", hr
);
1167 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1168 ReleaseStgMedium(&med
);
1170 InitFormatEtc(fmt
, cf_storage
, 0xffff);
1171 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1172 ok(hr
== S_OK
, "got %08x\n", hr
);
1173 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1174 ReleaseStgMedium(&med
);
1176 /* complex format with target device */
1178 InitFormatEtc(fmt
, cf_another
, 0xffff);
1179 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1180 ok(hr
== DV_E_FORMATETC
||
1181 broken(hr
== S_OK
), /* win9x, winme & nt4 */
1183 if(hr
== S_OK
) ReleaseStgMedium(&med
);
1185 InitFormatEtc(fmt
, cf_another
, 0xffff);
1186 memset(&dm
, 0, sizeof(dm
));
1187 dm
.dmSize
= sizeof(dm
);
1188 dm
.dmDriverExtra
= 0;
1189 lstrcpyW(dm
.dmDeviceName
, device_name
);
1190 fmt
.ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
);
1191 fmt
.ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
;
1192 fmt
.ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
1193 fmt
.ptd
->tdDeviceNameOffset
= 0;
1194 fmt
.ptd
->tdPortNameOffset
= 0;
1195 fmt
.ptd
->tdExtDevmodeOffset
= fmt
.ptd
->tdDriverNameOffset
+ sizeof(device_name
);
1196 lstrcpyW((WCHAR
*)fmt
.ptd
->tdData
, device_name
);
1197 memcpy(fmt
.ptd
->tdData
+ sizeof(device_name
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
1199 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1200 ok(hr
== S_OK
, "got %08x\n", hr
);
1201 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1202 ReleaseStgMedium(&med
);
1204 HeapFree(GetProcessHeap(), 0, fmt
.ptd
);
1207 IDataObject_Release(get
);
1208 IDataObject_Release(src
);
1212 static HGLOBAL
create_text(void)
1214 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 5);
1215 char *p
= GlobalLock(h
);
1221 static HENHMETAFILE
create_emf(void)
1223 const RECT rect
= {0, 0, 100, 100};
1224 HDC hdc
= CreateEnhMetaFileA(NULL
, NULL
, &rect
, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1225 ExtTextOutA(hdc
, 0, 0, ETO_OPAQUE
, &rect
, "Test String", strlen("Test String"), NULL
);
1226 return CloseEnhMetaFile(hdc
);
1229 static void test_nonole_clipboard(void)
1234 IEnumFORMATETC
*enum_fmt
;
1236 HGLOBAL h
, hblob
, htext
;
1241 r
= OpenClipboard(NULL
);
1242 ok(r
, "gle %d\n", GetLastError());
1243 r
= EmptyClipboard();
1244 ok(r
, "gle %d\n", GetLastError());
1245 r
= CloseClipboard();
1246 ok(r
, "gle %d\n", GetLastError());
1248 OleInitialize(NULL
);
1250 /* empty clipboard */
1251 hr
= OleGetClipboard(&get
);
1252 ok(hr
== S_OK
, "got %08x\n", hr
);
1253 hr
= IDataObject_EnumFormatEtc(get
, DATADIR_GET
, &enum_fmt
);
1254 ok(hr
== S_OK
, "got %08x\n", hr
);
1256 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1257 ok(hr
== S_FALSE
, "got %08x\n", hr
);
1258 IEnumFORMATETC_Release(enum_fmt
);
1260 IDataObject_Release(get
);
1262 /* set a user defined clipboard type */
1264 htext
= create_text();
1265 hblob
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
|GMEM_ZEROINIT
, 10);
1268 r
= OpenClipboard(NULL
);
1269 ok(r
, "gle %d\n", GetLastError());
1270 h
= SetClipboardData(CF_TEXT
, htext
);
1271 ok(h
== htext
, "got %p\n", h
);
1272 h
= SetClipboardData(cf_onemore
, hblob
);
1273 ok(h
== hblob
, "got %p\n", h
);
1274 h
= SetClipboardData(CF_ENHMETAFILE
, emf
);
1275 ok(h
== emf
, "got %p\n", h
);
1276 r
= CloseClipboard();
1277 ok(r
, "gle %d\n", GetLastError());
1279 hr
= OleGetClipboard(&get
);
1280 ok(hr
== S_OK
, "got %08x\n", hr
);
1281 hr
= IDataObject_EnumFormatEtc(get
, DATADIR_GET
, &enum_fmt
);
1282 ok(hr
== S_OK
, "got %08x\n", hr
);
1284 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1285 ok(hr
== S_OK
, "got %08x\n", hr
);
1286 ok(fmt
.cfFormat
== CF_TEXT
, "cf %04x\n", fmt
.cfFormat
);
1287 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1288 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1289 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1290 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1292 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1293 ok(hr
== S_OK
, "got %08x\n", hr
);
1294 ok(fmt
.cfFormat
== cf_onemore
, "cf %04x\n", fmt
.cfFormat
);
1295 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1296 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1297 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1298 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1300 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1301 ok(hr
== S_OK
, "got %08x\n", hr
);
1302 ok(fmt
.cfFormat
== CF_ENHMETAFILE
, "cf %04x\n", fmt
.cfFormat
);
1303 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1304 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1305 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1306 ok(fmt
.tymed
== TYMED_ENHMF
, "tymed %x\n", fmt
.tymed
);
1308 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1309 ok(hr
== S_OK
, "got %08x\n", hr
); /* User32 adds some synthesised formats */
1311 todo_wine
ok(fmt
.cfFormat
== CF_LOCALE
, "cf %04x\n", fmt
.cfFormat
);
1312 if(fmt
.cfFormat
== CF_LOCALE
)
1314 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1315 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1316 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1317 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1319 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1320 ok(hr
== S_OK
, "got %08x\n", hr
);
1323 ok(fmt
.cfFormat
== CF_OEMTEXT
, "cf %04x\n", fmt
.cfFormat
);
1324 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1325 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1326 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1327 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1329 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1330 ok(hr
== S_OK
, "got %08x\n", hr
);
1331 ok(fmt
.cfFormat
== CF_UNICODETEXT
||
1332 broken(fmt
.cfFormat
== CF_METAFILEPICT
), /* win9x and winme don't have CF_UNICODETEXT */
1333 "cf %04x\n", fmt
.cfFormat
);
1334 if(fmt
.cfFormat
== CF_UNICODETEXT
)
1336 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1337 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1338 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1339 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1341 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1342 ok(hr
== S_OK
, "got %08x\n", hr
);
1344 ok(fmt
.cfFormat
== CF_METAFILEPICT
, "cf %04x\n", fmt
.cfFormat
);
1345 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1346 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1347 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1348 ok(fmt
.tymed
== TYMED_MFPICT
, "tymed %x\n", fmt
.tymed
);
1350 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1351 ok(hr
== S_FALSE
, "got %08x\n", hr
);
1352 IEnumFORMATETC_Release(enum_fmt
);
1354 InitFormatEtc(fmt
, CF_ENHMETAFILE
, TYMED_ENHMF
);
1355 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1356 ok(hr
== S_OK
, "got %08x\n", hr
);
1357 obj_type
= GetObjectType(U(med
).hEnhMetaFile
);
1358 ok(obj_type
== OBJ_ENHMETAFILE
, "got %d\n", obj_type
);
1359 ReleaseStgMedium(&med
);
1361 IDataObject_Release(get
);
1363 r
= OpenClipboard(NULL
);
1364 ok(r
, "gle %d\n", GetLastError());
1365 r
= EmptyClipboard();
1366 ok(r
, "gle %d\n", GetLastError());
1367 r
= CloseClipboard();
1368 ok(r
, "gle %d\n", GetLastError());
1373 static void test_getdatahere(void)
1376 IDataObject
*src
, *get
;
1380 OleInitialize(NULL
);
1382 hr
= DataObjectImpl_CreateComplex(&src
);
1383 ok(hr
== S_OK
, "got %08x\n", hr
);
1385 hr
= OleSetClipboard(src
);
1386 ok(hr
== S_OK
, "got %08x\n", hr
);
1388 hr
= OleGetClipboard(&get
);
1389 ok(hr
== S_OK
, "got %08x\n", hr
);
1391 /* global format -> global & stream */
1393 DataObjectImpl_GetData_calls
= 0;
1394 DataObjectImpl_GetDataHere_calls
= 0;
1396 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1398 med
.pUnkForRelease
= NULL
;
1399 med
.tymed
= TYMED_HGLOBAL
;
1400 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1401 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1402 ok(hr
== S_OK
, "got %08x\n", hr
);
1403 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1404 ReleaseStgMedium(&med
);
1405 ok(DataObjectImpl_GetDataHere_calls
== 1, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1406 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1408 InitFormatEtc(fmt
, CF_TEXT
, 0);
1410 med
.pUnkForRelease
= NULL
;
1411 med
.tymed
= TYMED_HGLOBAL
;
1412 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1413 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1414 ok(hr
== S_OK
, "got %08x\n", hr
);
1415 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1416 ReleaseStgMedium(&med
);
1417 ok(DataObjectImpl_GetDataHere_calls
== 2, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1418 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1420 med
.pUnkForRelease
= NULL
;
1421 med
.tymed
= TYMED_HGLOBAL
;
1422 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 1);
1423 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1424 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1425 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1426 ReleaseStgMedium(&med
);
1427 ok(DataObjectImpl_GetDataHere_calls
== 3, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1428 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1430 med
.pUnkForRelease
= NULL
;
1431 med
.tymed
= TYMED_ISTREAM
;
1432 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1433 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1434 ok(hr
== S_OK
, "got %08x\n", hr
);
1435 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1436 ReleaseStgMedium(&med
);
1437 ok(DataObjectImpl_GetDataHere_calls
== 4, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1438 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1440 med
.pUnkForRelease
= NULL
;
1441 med
.tymed
= TYMED_ISTORAGE
;
1442 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1443 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1444 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1445 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1446 ReleaseStgMedium(&med
);
1447 ok(DataObjectImpl_GetDataHere_calls
== 5, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1448 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1450 InitFormatEtc(fmt
, cf_stream
, 0);
1452 med
.pUnkForRelease
= NULL
;
1453 med
.tymed
= TYMED_HGLOBAL
;
1454 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1455 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1456 ok(hr
== S_OK
, "got %08x\n", hr
);
1457 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1458 ReleaseStgMedium(&med
);
1459 ok(DataObjectImpl_GetDataHere_calls
== 7, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1460 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1462 med
.pUnkForRelease
= NULL
;
1463 med
.tymed
= TYMED_ISTREAM
;
1464 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1465 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1466 ok(hr
== S_OK
, "got %08x\n", hr
);
1467 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1468 ReleaseStgMedium(&med
);
1469 ok(DataObjectImpl_GetDataHere_calls
== 8, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1470 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1472 med
.pUnkForRelease
= NULL
;
1473 med
.tymed
= TYMED_ISTORAGE
;
1474 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1475 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1476 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1477 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1478 ReleaseStgMedium(&med
);
1479 ok(DataObjectImpl_GetDataHere_calls
== 9, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1480 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1482 InitFormatEtc(fmt
, cf_storage
, 0);
1484 med
.pUnkForRelease
= NULL
;
1485 med
.tymed
= TYMED_HGLOBAL
;
1486 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 3000);
1487 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1488 ok(hr
== S_OK
, "got %08x\n", hr
);
1489 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1490 ReleaseStgMedium(&med
);
1491 ok(DataObjectImpl_GetDataHere_calls
== 11, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1492 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1494 med
.pUnkForRelease
= NULL
;
1495 med
.tymed
= TYMED_ISTREAM
;
1496 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1497 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1498 ok(hr
== S_OK
, "got %08x\n", hr
);
1499 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1500 ReleaseStgMedium(&med
);
1501 ok(DataObjectImpl_GetDataHere_calls
== 12, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1502 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1504 med
.pUnkForRelease
= NULL
;
1505 med
.tymed
= TYMED_ISTORAGE
;
1506 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1507 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1508 ok(hr
== S_OK
, "got %08x\n", hr
);
1509 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1510 ReleaseStgMedium(&med
);
1511 ok(DataObjectImpl_GetDataHere_calls
== 13, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1512 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1515 IDataObject_Release(get
);
1516 IDataObject_Release(src
);
1522 START_TEST(clipboard
)
1524 test_set_clipboard();
1525 test_consumer_refs();
1526 test_flushed_getdata();
1527 test_nonole_clipboard();