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
24 #define NONAMELESSUNION
34 #include "wine/test.h"
36 #define InitFormatEtc(fe, cf, med) \
39 (fe).dwAspect=DVASPECT_CONTENT;\
45 static inline char *dump_fmtetc(FORMATETC
*fmt
)
49 snprintf(buf
, sizeof(buf
), "cf %04x ptd %p aspect %x lindex %d tymed %x",
50 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
54 typedef struct DataObjectImpl
{
55 IDataObject IDataObject_iface
;
67 typedef struct EnumFormatImpl
{
68 IEnumFORMATETC IEnumFORMATETC_iface
;
77 static BOOL expect_DataObjectImpl_QueryGetData
= TRUE
;
78 static ULONG DataObjectImpl_GetData_calls
= 0;
79 static ULONG DataObjectImpl_GetDataHere_calls
= 0;
80 static ULONG DataObjectImpl_EnumFormatEtc_calls
= 0;
82 static UINT cf_stream
, cf_storage
, cf_global
, cf_another
, cf_onemore
;
84 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT size
, LPENUMFORMATETC
*lplpformatetc
);
86 static HMETAFILE
create_mf(void)
88 RECT rect
= {0, 0, 100, 100};
89 HDC hdc
= CreateMetaFileA(NULL
);
90 ExtTextOutA(hdc
, 0, 0, ETO_OPAQUE
, &rect
, "Test String", strlen("Test String"), NULL
);
91 return CloseMetaFile(hdc
);
94 static HMETAFILEPICT
create_metafilepict(void)
96 HGLOBAL ret
= GlobalAlloc(GMEM_MOVEABLE
, sizeof(METAFILEPICT
));
97 METAFILEPICT
*mf
= GlobalLock(ret
);
98 mf
->mm
= MM_ANISOTROPIC
;
101 mf
->hMF
= create_mf();
106 static inline DataObjectImpl
*impl_from_IDataObject(IDataObject
*iface
)
108 return CONTAINING_RECORD(iface
, DataObjectImpl
, IDataObject_iface
);
111 static inline EnumFormatImpl
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
113 return CONTAINING_RECORD(iface
, EnumFormatImpl
, IEnumFORMATETC_iface
);
116 static HRESULT WINAPI
EnumFormatImpl_QueryInterface(IEnumFORMATETC
*iface
, REFIID riid
, LPVOID
*ppvObj
)
118 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
120 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumFORMATETC
)) {
121 IEnumFORMATETC_AddRef(iface
);
122 *ppvObj
= &This
->IEnumFORMATETC_iface
;
126 return E_NOINTERFACE
;
129 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
131 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
132 LONG ref
= InterlockedIncrement(&This
->ref
);
136 static ULONG WINAPI
EnumFormatImpl_Release(IEnumFORMATETC
*iface
)
138 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
139 ULONG ref
= InterlockedDecrement(&This
->ref
);
142 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
143 HeapFree(GetProcessHeap(), 0, This
);
149 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
150 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
152 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
155 if (winetest_debug
> 1)
156 trace("next: count %d cur %d\n", celt
, This
->cur
);
161 count
= min(celt
, This
->fmtetc_cnt
- This
->cur
);
162 for(i
= 0; i
< count
; i
++, This
->cur
++, rgelt
++)
164 *rgelt
= This
->fmtetc
[This
->cur
];
167 DWORD size
= This
->fmtetc
[This
->cur
].ptd
->tdSize
;
168 rgelt
->ptd
= CoTaskMemAlloc(size
);
169 memcpy(rgelt
->ptd
, This
->fmtetc
[This
->cur
].ptd
, size
);
173 *pceltFetched
= count
;
174 return count
== celt
? S_OK
: S_FALSE
;
177 static HRESULT WINAPI
EnumFormatImpl_Skip(IEnumFORMATETC
*iface
, ULONG celt
)
179 ok(0, "unexpected call\n");
183 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
185 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
191 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
193 ok(0, "unexpected call\n");
197 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
198 EnumFormatImpl_QueryInterface
,
199 EnumFormatImpl_AddRef
,
200 EnumFormatImpl_Release
,
203 EnumFormatImpl_Reset
,
207 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
211 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl
));
212 ret
->IEnumFORMATETC_iface
.lpVtbl
= &VT_EnumFormatImpl
;
215 ret
->fmtetc_cnt
= fmtetc_cnt
;
216 ret
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt
*sizeof(FORMATETC
));
217 memcpy(ret
->fmtetc
, fmtetc
, fmtetc_cnt
*sizeof(FORMATETC
));
218 *lplpformatetc
= &ret
->IEnumFORMATETC_iface
;
222 static HRESULT WINAPI
DataObjectImpl_QueryInterface(IDataObject
*iface
, REFIID riid
, LPVOID
*ppvObj
)
224 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
226 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDataObject
)) {
227 IDataObject_AddRef(iface
);
228 *ppvObj
= &This
->IDataObject_iface
;
232 return E_NOINTERFACE
;
235 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
237 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
238 ULONG ref
= InterlockedIncrement(&This
->ref
);
242 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
244 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
245 ULONG ref
= InterlockedDecrement(&This
->ref
);
250 if(This
->text
) GlobalFree(This
->text
);
251 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
252 HeapFree(GetProcessHeap(), 0, This
->fmtetc
[i
].ptd
);
253 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
254 if(This
->stm
) IStream_Release(This
->stm
);
255 if(This
->stg
) IStorage_Release(This
->stg
);
257 METAFILEPICT
*mfp
= GlobalLock(This
->hmfp
);
258 DeleteMetaFile(mfp
->hMF
);
259 GlobalUnlock(This
->hmfp
);
260 GlobalFree(This
->hmfp
);
262 HeapFree(GetProcessHeap(), 0, This
);
268 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
270 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
273 trace("getdata: %s\n", dump_fmtetc(pformatetc
));
275 DataObjectImpl_GetData_calls
++;
277 ok(pmedium
->tymed
== 0, "pmedium->tymed = %u\n", pmedium
->tymed
);
278 ok(U(*pmedium
).hGlobal
== NULL
, "pmedium->hGlobal = %p\n", U(*pmedium
).hGlobal
);
279 ok(pmedium
->pUnkForRelease
== NULL
, "pmedium->pUnkForRelease = %p\n", pmedium
->pUnkForRelease
);
281 if(pformatetc
->lindex
!= -1)
282 return DV_E_FORMATETC
;
284 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
286 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
)
288 if(This
->fmtetc
[i
].tymed
& pformatetc
->tymed
)
290 pmedium
->pUnkForRelease
= (LPUNKNOWN
)iface
;
291 IUnknown_AddRef(pmedium
->pUnkForRelease
);
293 if(pformatetc
->cfFormat
== CF_TEXT
|| pformatetc
->cfFormat
== cf_global
)
295 pmedium
->tymed
= TYMED_HGLOBAL
;
296 U(*pmedium
).hGlobal
= This
->text
;
298 else if(pformatetc
->cfFormat
== cf_stream
)
300 pmedium
->tymed
= TYMED_ISTREAM
;
301 IStream_AddRef(This
->stm
);
302 U(*pmedium
).pstm
= This
->stm
;
304 else if(pformatetc
->cfFormat
== cf_storage
|| pformatetc
->cfFormat
== cf_another
)
306 pmedium
->tymed
= TYMED_ISTORAGE
;
307 IStorage_AddRef(This
->stg
);
308 U(*pmedium
).pstg
= This
->stg
;
310 else if(pformatetc
->cfFormat
== CF_METAFILEPICT
)
312 pmedium
->tymed
= TYMED_MFPICT
;
313 U(*pmedium
).hMetaFilePict
= This
->hmfp
;
323 static HRESULT WINAPI
DataObjectImpl_GetDataHere(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
325 trace("getdatahere: %s\n", dump_fmtetc(pformatetc
));
326 DataObjectImpl_GetDataHere_calls
++;
331 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
333 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
335 BOOL foundFormat
= FALSE
;
337 trace("querygetdata: %s\n", dump_fmtetc(pformatetc
));
338 if (!expect_DataObjectImpl_QueryGetData
)
339 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
341 if(pformatetc
->lindex
!= -1)
344 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
345 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
347 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
351 return foundFormat
?DV_E_FORMATETC
:DV_E_TYMED
;
354 static HRESULT WINAPI
DataObjectImpl_GetCanonicalFormatEtc(IDataObject
* iface
, FORMATETC
*pformatectIn
,
355 FORMATETC
*pformatetcOut
)
357 ok(0, "unexpected call\n");
361 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
362 STGMEDIUM
*pmedium
, BOOL fRelease
)
364 ok(0, "unexpected call\n");
368 static HRESULT WINAPI
DataObjectImpl_EnumFormatEtc(IDataObject
* iface
, DWORD dwDirection
,
369 IEnumFORMATETC
**ppenumFormatEtc
)
371 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
373 DataObjectImpl_EnumFormatEtc_calls
++;
375 if(dwDirection
!= DATADIR_GET
) {
376 ok(0, "unexpected direction %d\n", dwDirection
);
379 return EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenumFormatEtc
);
382 static HRESULT WINAPI
DataObjectImpl_DAdvise(IDataObject
* iface
, FORMATETC
*pformatetc
, DWORD advf
,
383 IAdviseSink
*pAdvSink
, DWORD
*pdwConnection
)
385 ok(0, "unexpected call\n");
389 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
391 ok(0, "unexpected call\n");
395 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
397 ok(0, "unexpected call\n");
401 static const IDataObjectVtbl VT_DataObjectImpl
=
403 DataObjectImpl_QueryInterface
,
404 DataObjectImpl_AddRef
,
405 DataObjectImpl_Release
,
406 DataObjectImpl_GetData
,
407 DataObjectImpl_GetDataHere
,
408 DataObjectImpl_QueryGetData
,
409 DataObjectImpl_GetCanonicalFormatEtc
,
410 DataObjectImpl_SetData
,
411 DataObjectImpl_EnumFormatEtc
,
412 DataObjectImpl_DAdvise
,
413 DataObjectImpl_DUnadvise
,
414 DataObjectImpl_EnumDAdvise
417 static HRESULT
DataObjectImpl_CreateFromHGlobal(HGLOBAL text
, LPDATAOBJECT
*dataobj
)
421 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
422 obj
->IDataObject_iface
.lpVtbl
= &VT_DataObjectImpl
;
430 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
431 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
433 *dataobj
= &obj
->IDataObject_iface
;
437 static HRESULT
DataObjectImpl_CreateText(LPCSTR text
, LPDATAOBJECT
*lplpdataobj
)
439 HGLOBAL h
= GlobalAlloc(GMEM_MOVEABLE
, strlen(text
) + 1);
440 strcpy(GlobalLock(h
), text
);
442 return DataObjectImpl_CreateFromHGlobal(h
, lplpdataobj
);
445 static const char *cmpl_stm_data
= "complex stream";
446 static const char *cmpl_text_data
= "complex text";
447 static const WCHAR device_name
[] = {'m','y','d','e','v',0};
449 static HRESULT
DataObjectImpl_CreateComplex(LPDATAOBJECT
*lplpdataobj
)
455 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
456 obj
->IDataObject_iface
.lpVtbl
= &VT_DataObjectImpl
;
458 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(cmpl_text_data
) + 1);
459 strcpy(GlobalLock(obj
->text
), cmpl_text_data
);
460 GlobalUnlock(obj
->text
);
461 CreateStreamOnHGlobal(NULL
, TRUE
, &obj
->stm
);
462 IStream_Write(obj
->stm
, cmpl_stm_data
, strlen(cmpl_stm_data
), NULL
);
464 CreateILockBytesOnHGlobal(NULL
, TRUE
, &lbs
);
465 StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &obj
->stg
);
466 ILockBytes_Release(lbs
);
468 obj
->hmfp
= create_metafilepict();
471 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
472 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
473 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
474 InitFormatEtc(obj
->fmtetc
[1], cf_stream
, TYMED_ISTREAM
);
475 InitFormatEtc(obj
->fmtetc
[2], cf_storage
, TYMED_ISTORAGE
);
476 InitFormatEtc(obj
->fmtetc
[3], cf_another
, TYMED_ISTORAGE
|TYMED_ISTREAM
|TYMED_HGLOBAL
);
477 if (0) /* Causes crashes on both Wine and Windows */
479 memset(&dm
, 0, sizeof(dm
));
480 dm
.dmSize
= sizeof(dm
);
481 dm
.dmDriverExtra
= 0;
482 lstrcpyW(dm
.dmDeviceName
, device_name
);
483 obj
->fmtetc
[3].ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
);
484 obj
->fmtetc
[3].ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
;
485 obj
->fmtetc
[3].ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
486 obj
->fmtetc
[3].ptd
->tdDeviceNameOffset
= 0;
487 obj
->fmtetc
[3].ptd
->tdPortNameOffset
= 0;
488 obj
->fmtetc
[3].ptd
->tdExtDevmodeOffset
= obj
->fmtetc
[3].ptd
->tdDriverNameOffset
+ sizeof(device_name
);
489 lstrcpyW((WCHAR
*)obj
->fmtetc
[3].ptd
->tdData
, device_name
);
490 memcpy(obj
->fmtetc
[3].ptd
->tdData
+ sizeof(device_name
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
493 InitFormatEtc(obj
->fmtetc
[4], cf_global
, TYMED_HGLOBAL
);
494 InitFormatEtc(obj
->fmtetc
[5], cf_another
, TYMED_HGLOBAL
);
495 InitFormatEtc(obj
->fmtetc
[6], cf_another
, 0xfffff);
496 InitFormatEtc(obj
->fmtetc
[7], cf_another
, 0xfffff);
497 obj
->fmtetc
[7].dwAspect
= DVASPECT_ICON
;
498 InitFormatEtc(obj
->fmtetc
[8], CF_METAFILEPICT
, TYMED_MFPICT
);
500 *lplpdataobj
= &obj
->IDataObject_iface
;
504 static void test_get_clipboard_uninitialized(void)
509 pDObj
= (IDataObject
*)0xdeadbeef;
510 hr
= OleGetClipboard(&pDObj
);
511 todo_wine
ok(hr
== S_OK
, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr
, S_OK
);
512 if (pDObj
&& pDObj
!= (IDataObject
*)0xdeadbeef) IDataObject_Release(pDObj
);
515 static void test_get_clipboard(void)
518 IDataObject
*data_obj
;
522 hr
= OleGetClipboard(NULL
);
523 ok(hr
== E_INVALIDARG
, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr
);
525 hr
= OleGetClipboard(&data_obj
);
526 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
528 /* test IDataObject_QueryGetData */
530 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
531 expect_DataObjectImpl_QueryGetData
= FALSE
;
533 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
534 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
535 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
537 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
538 fmtetc
.dwAspect
= 0xdeadbeef;
539 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
540 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
542 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
543 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
544 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
545 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
547 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
549 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
550 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
),
551 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
553 InitFormatEtc(fmtetc
, CF_RIFF
, TYMED_HGLOBAL
);
554 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
555 ok(hr
== DV_E_CLIPFORMAT
, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr
);
557 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_FILE
);
558 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
559 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
561 expect_DataObjectImpl_QueryGetData
= TRUE
;
563 /* test IDataObject_GetData */
565 DataObjectImpl_GetData_calls
= 0;
567 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
568 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
569 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
570 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
572 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
573 fmtetc
.dwAspect
= 0xdeadbeef;
574 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
575 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
576 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
578 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
579 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
580 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
581 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
582 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
584 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
586 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
587 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
590 /* undo the unexpected success */
591 DataObjectImpl_GetData_calls
--;
592 ReleaseStgMedium(&stgmedium
);
595 InitFormatEtc(fmtetc
, CF_RIFF
, TYMED_HGLOBAL
);
596 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
597 ok(hr
== DV_E_FORMATETC
, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
598 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
600 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_FILE
);
601 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
602 ok(hr
== DV_E_TYMED
, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr
);
603 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
605 ok(DataObjectImpl_GetData_calls
== 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls
);
607 IDataObject_Release(data_obj
);
610 static void test_enum_fmtetc(IDataObject
*src
)
614 IEnumFORMATETC
*enum_fmt
, *src_enum
;
615 FORMATETC fmt
, src_fmt
;
618 hr
= OleGetClipboard(&data
);
619 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
621 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_SET
, &enum_fmt
);
622 ok(hr
== E_NOTIMPL
||
623 broken(hr
== E_INVALIDARG
), /* win98 (not win98SE) */
626 DataObjectImpl_EnumFormatEtc_calls
= 0;
627 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
628 ok(hr
== S_OK
, "got %08x\n", hr
);
629 ok(DataObjectImpl_EnumFormatEtc_calls
== 0, "EnumFormatEtc was called\n");
632 skip("EnumFormatEtc failed, skipping tests.\n");
636 if(src
) IDataObject_EnumFormatEtc(src
, DATADIR_GET
, &src_enum
);
638 while((hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
)) == S_OK
)
640 ok(src
!= NULL
, "shouldn't be here\n");
641 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
642 ok(hr
== S_OK
, "%d: got %08x\n", count
, hr
);
643 trace("%d: %s\n", count
, dump_fmtetc(&fmt
));
644 ok(fmt
.cfFormat
== src_fmt
.cfFormat
, "%d: %04x %04x\n", count
, fmt
.cfFormat
, src_fmt
.cfFormat
);
645 ok(fmt
.dwAspect
== src_fmt
.dwAspect
, "%d: %08x %08x\n", count
, fmt
.dwAspect
, src_fmt
.dwAspect
);
646 ok(fmt
.lindex
== src_fmt
.lindex
, "%d: %08x %08x\n", count
, fmt
.lindex
, src_fmt
.lindex
);
647 ok(fmt
.tymed
== src_fmt
.tymed
, "%d: %08x %08x\n", count
, fmt
.tymed
, src_fmt
.tymed
);
650 ok(src_fmt
.ptd
!= NULL
, "%d: expected non-NULL\n", count
);
651 CoTaskMemFree(fmt
.ptd
);
652 CoTaskMemFree(src_fmt
.ptd
);
657 ok(hr
== S_FALSE
, "%d: got %08x\n", count
, hr
);
661 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
662 ok(hr
== S_FALSE
, "%d: got %08x\n", count
, hr
);
663 IEnumFORMATETC_Release(src_enum
);
666 hr
= IEnumFORMATETC_Reset(enum_fmt
);
667 ok(hr
== S_OK
, "got %08x\n", hr
);
669 if(src
) /* Exercise the enumerator a bit */
671 IEnumFORMATETC
*clone
;
674 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
675 ok(hr
== S_OK
, "got %08x\n", hr
);
676 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
677 ok(hr
== S_OK
, "got %08x\n", hr
);
678 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
679 ok(hr
== S_OK
, "got %08x\n", hr
);
681 hr
= IEnumFORMATETC_Reset(enum_fmt
);
682 ok(hr
== S_OK
, "got %08x\n", hr
);
683 hr
= IEnumFORMATETC_Skip(enum_fmt
, 2);
684 ok(hr
== S_OK
, "got %08x\n", hr
);
686 hr
= IEnumFORMATETC_Clone(enum_fmt
, &clone
);
687 ok(hr
== S_OK
, "got %08x\n", hr
);
688 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
689 ok(hr
== S_OK
, "got %08x\n", hr
);
690 ok(fmt
.cfFormat
== third_fmt
.cfFormat
, "formats don't match\n");
691 hr
= IEnumFORMATETC_Next(clone
, 1, &fmt
, NULL
);
692 ok(hr
== S_OK
, "got %08x\n", hr
);
693 ok(fmt
.cfFormat
== third_fmt
.cfFormat
, "formats don't match\n");
694 IEnumFORMATETC_Release(clone
);
697 IEnumFORMATETC_Release(enum_fmt
);
698 IDataObject_Release(data
);
701 static void test_no_cf_dataobject(void)
703 UINT cf_dataobject
= RegisterClipboardFormatA("DataObject");
704 UINT cf_ole_priv_data
= RegisterClipboardFormatA("Ole Private Data");
708 h
= GetClipboardData(cf_dataobject
);
709 ok(!h
, "got %p\n", h
);
710 h
= GetClipboardData(cf_ole_priv_data
);
711 ok(!h
, "got %p\n", h
);
716 static void test_cf_dataobject(IDataObject
*data
)
719 UINT cf_dataobject
= RegisterClipboardFormatA("DataObject");
720 UINT cf_ole_priv_data
= RegisterClipboardFormatA("Ole Private Data");
721 BOOL found_dataobject
= FALSE
, found_priv_data
= FALSE
;
726 cf
= EnumClipboardFormats(cf
);
727 if(cf
== cf_dataobject
)
729 HGLOBAL h
= GetClipboardData(cf
);
730 HWND
*ptr
= GlobalLock(h
);
731 DWORD size
= GlobalSize(h
);
732 HWND clip_owner
= GetClipboardOwner();
734 found_dataobject
= TRUE
;
735 ok(size
>= sizeof(*ptr
), "size %d\n", size
);
737 ok(*ptr
== clip_owner
, "hwnd %p clip_owner %p\n", *ptr
, clip_owner
);
738 else /* ole clipboard flushed */
739 ok(*ptr
== NULL
, "hwnd %p\n", *ptr
);
742 else if(cf
== cf_ole_priv_data
)
744 found_priv_data
= TRUE
;
747 HGLOBAL h
= GetClipboardData(cf
);
748 DWORD
*ptr
= GlobalLock(h
);
749 DWORD size
= GlobalSize(h
);
752 win_skip("Ole Private Data in win9x format\n");
756 IEnumFORMATETC
*enum_fmt
;
762 BOOL first_use_of_cf
;
772 struct formatetcetc fmts
[1];
773 } *priv
= (struct priv_data
*)ptr
;
774 CLIPFORMAT cfs_seen
[10];
776 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
777 ok(hr
== S_OK
, "got %08x\n", hr
);
778 fmt_ptr
= priv
->fmts
;
780 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
783 BOOL seen_cf
= FALSE
;
785 ok(fmt_ptr
->fmt
.cfFormat
== fmt
.cfFormat
,
786 "got %08x expected %08x\n", fmt_ptr
->fmt
.cfFormat
, fmt
.cfFormat
);
787 ok(fmt_ptr
->fmt
.dwAspect
== fmt
.dwAspect
, "got %08x expected %08x\n",
788 fmt_ptr
->fmt
.dwAspect
, fmt
.dwAspect
);
789 ok(fmt_ptr
->fmt
.lindex
== fmt
.lindex
, "got %08x expected %08x\n",
790 fmt_ptr
->fmt
.lindex
, fmt
.lindex
);
791 ok(fmt_ptr
->fmt
.tymed
== fmt
.tymed
, "got %08x expected %08x\n",
792 fmt_ptr
->fmt
.tymed
, fmt
.tymed
);
793 for(i
= 0; i
< count
; i
++)
794 if(fmt_ptr
->fmt
.cfFormat
== cfs_seen
[i
])
799 cfs_seen
[count
] = fmt
.cfFormat
;
800 ok(fmt_ptr
->first_use_of_cf
!= seen_cf
, "got %08x expected %08x\n",
801 fmt_ptr
->first_use_of_cf
, !seen_cf
);
802 ok(fmt_ptr
->res
[0] == 0, "got %08x\n", fmt_ptr
->res
[0]);
803 ok(fmt_ptr
->res
[1] == 0, "got %08x\n", fmt_ptr
->res
[1]);
806 DVTARGETDEVICE
*target
;
808 ok(fmt_ptr
->fmt
.ptd
!= NULL
, "target device offset zero\n");
809 target
= (DVTARGETDEVICE
*)((char*)priv
+ (DWORD_PTR
)fmt_ptr
->fmt
.ptd
);
810 ok(!memcmp(target
, fmt
.ptd
, fmt
.ptd
->tdSize
), "target devices differ\n");
811 CoTaskMemFree(fmt
.ptd
);
816 ok(priv
->res1
== 0, "got %08x\n", priv
->res1
);
817 ok(priv
->res2
== 1, "got %08x\n", priv
->res2
);
818 ok(priv
->count
== count
, "got %08x expected %08x\n", priv
->count
, count
);
819 ok(priv
->res3
[0] == 0, "got %08x\n", priv
->res3
[0]);
821 /* win64 sets the lsb */
822 if(sizeof(fmt_ptr
->fmt
.ptd
) == 8)
823 todo_wine
ok(priv
->res3
[1] == 1, "got %08x\n", priv
->res3
[1]);
825 ok(priv
->res3
[1] == 0, "got %08x\n", priv
->res3
[1]);
828 IEnumFORMATETC_Release(enum_fmt
);
832 else if(cf
== cf_stream
)
838 DataObjectImpl_GetDataHere_calls
= 0;
839 h
= GetClipboardData(cf
);
840 ok(DataObjectImpl_GetDataHere_calls
== 1, "got %d\n", DataObjectImpl_GetDataHere_calls
);
842 size
= GlobalSize(h
);
843 ok(size
== strlen(cmpl_stm_data
),
844 "expected %d got %d\n", lstrlenA(cmpl_stm_data
), size
);
845 ok(!memcmp(ptr
, cmpl_stm_data
, strlen(cmpl_stm_data
)), "mismatch\n");
848 else if(cf
== cf_global
)
854 DataObjectImpl_GetDataHere_calls
= 0;
855 h
= GetClipboardData(cf
);
856 ok(DataObjectImpl_GetDataHere_calls
== 0, "got %d\n", DataObjectImpl_GetDataHere_calls
);
858 size
= GlobalSize(h
);
859 ok(size
== strlen(cmpl_text_data
) + 1,
860 "expected %d got %d\n", lstrlenA(cmpl_text_data
) + 1, size
);
861 ok(!memcmp(ptr
, cmpl_text_data
, strlen(cmpl_text_data
) + 1), "mismatch\n");
866 ok(found_dataobject
, "didn't find cf_dataobject\n");
867 ok(found_priv_data
, "didn't find cf_ole_priv_data\n");
870 static void test_complex_get_clipboard(void)
873 IDataObject
*data_obj
;
877 hr
= OleGetClipboard(&data_obj
);
878 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
880 DataObjectImpl_GetData_calls
= 0;
882 InitFormatEtc(fmtetc
, CF_METAFILEPICT
, TYMED_MFPICT
);
883 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
884 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
885 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
887 InitFormatEtc(fmtetc
, CF_METAFILEPICT
, TYMED_HGLOBAL
);
888 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
889 ok(hr
== DV_E_TYMED
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
890 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
892 InitFormatEtc(fmtetc
, CF_ENHMETAFILE
, TYMED_HGLOBAL
);
893 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
894 ok(hr
== DV_E_TYMED
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
895 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
897 InitFormatEtc(fmtetc
, CF_ENHMETAFILE
, TYMED_ENHMF
);
898 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
899 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
900 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
902 ok(DataObjectImpl_GetData_calls
== 5,
903 "DataObjectImpl_GetData called 5 times instead of %d times\n",
904 DataObjectImpl_GetData_calls
);
905 IDataObject_Release(data_obj
);
908 static void test_set_clipboard(void)
912 LPDATAOBJECT data1
, data2
, data_cmpl
;
916 cf_stream
= RegisterClipboardFormatA("stream format");
917 cf_storage
= RegisterClipboardFormatA("storage format");
918 cf_global
= RegisterClipboardFormatA("global format");
919 cf_another
= RegisterClipboardFormatA("another format");
920 cf_onemore
= RegisterClipboardFormatA("one more format");
922 hr
= DataObjectImpl_CreateText("data1", &data1
);
923 ok(hr
== S_OK
, "Failed to create data1 object: 0x%08x\n", hr
);
926 hr
= DataObjectImpl_CreateText("data2", &data2
);
927 ok(hr
== S_OK
, "Failed to create data2 object: 0x%08x\n", hr
);
930 hr
= DataObjectImpl_CreateComplex(&data_cmpl
);
931 ok(hr
== S_OK
, "Failed to create complex data object: 0x%08x\n", hr
);
935 hr
= OleSetClipboard(data1
);
936 ok(hr
== CO_E_NOTINITIALIZED
, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr
);
939 hr
= OleSetClipboard(data1
);
940 ok(hr
== CO_E_NOTINITIALIZED
, "OleSetClipboard failed with 0x%08x\n", hr
);
943 hr
= OleInitialize(NULL
);
944 ok(hr
== S_OK
, "OleInitialize failed with error 0x%08x\n", hr
);
946 hr
= OleSetClipboard(data1
);
947 ok(hr
== S_OK
, "failed to set clipboard to data1, hr = 0x%08x\n", hr
);
949 test_cf_dataobject(data1
);
951 hr
= OleIsCurrentClipboard(data1
);
952 ok(hr
== S_OK
, "expected current clipboard to be data1, hr = 0x%08x\n", hr
);
953 hr
= OleIsCurrentClipboard(data2
);
954 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
955 hr
= OleIsCurrentClipboard(NULL
);
956 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
958 test_get_clipboard();
960 hr
= OleSetClipboard(data2
);
961 ok(hr
== S_OK
, "failed to set clipboard to data2, hr = 0x%08x\n", hr
);
962 hr
= OleIsCurrentClipboard(data1
);
963 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
964 hr
= OleIsCurrentClipboard(data2
);
965 ok(hr
== S_OK
, "expected current clipboard to be data2, hr = 0x%08x\n", hr
);
966 hr
= OleIsCurrentClipboard(NULL
);
967 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
969 /* put a format directly onto the clipboard to show
970 OleFlushClipboard doesn't empty the clipboard */
971 hblob
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
|GMEM_ZEROINIT
, 10);
972 ptr
= GlobalLock( hblob
);
973 ok( ptr
&& ptr
!= hblob
, "got fixed block %p / %p\n", ptr
, hblob
);
974 GlobalUnlock( hblob
);
975 ok( OpenClipboard(NULL
), "OpenClipboard failed\n" );
976 h
= SetClipboardData(cf_onemore
, hblob
);
977 ok(h
== hblob
, "got %p\n", h
);
978 h
= GetClipboardData(cf_onemore
);
979 ok(h
== hblob
, "got %p / %p\n", h
, hblob
);
980 ptr
= GlobalLock( h
);
981 ok( ptr
&& ptr
!= h
, "got fixed block %p / %p\n", ptr
, h
);
982 GlobalUnlock( hblob
);
983 ok( CloseClipboard(), "CloseClipboard failed\n" );
985 hr
= OleFlushClipboard();
986 ok(hr
== S_OK
, "failed to flush clipboard, hr = 0x%08x\n", hr
);
987 hr
= OleIsCurrentClipboard(data1
);
988 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
989 hr
= OleIsCurrentClipboard(data2
);
990 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
991 hr
= OleIsCurrentClipboard(NULL
);
992 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
994 /* format should survive the flush */
995 ok( OpenClipboard(NULL
), "OpenClipboard failed\n" );
996 h
= GetClipboardData(cf_onemore
);
997 ok(h
== hblob
, "got %p\n", h
);
998 ptr
= GlobalLock( h
);
999 ok( ptr
&& ptr
!= h
, "got fixed block %p / %p\n", ptr
, h
);
1000 GlobalUnlock( hblob
);
1001 ok( CloseClipboard(), "CloseClipboard failed\n" );
1003 test_cf_dataobject(NULL
);
1005 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
1007 OpenClipboard(NULL
);
1008 h
= GetClipboardData(cf_onemore
);
1009 ok(h
== NULL
, "got %p\n", h
);
1012 trace("setting complex\n");
1013 hr
= OleSetClipboard(data_cmpl
);
1014 ok(hr
== S_OK
, "failed to set clipboard to complex data, hr = 0x%08x\n", hr
);
1015 test_complex_get_clipboard();
1016 test_cf_dataobject(data_cmpl
);
1017 test_enum_fmtetc(data_cmpl
);
1019 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
1021 test_no_cf_dataobject();
1022 test_enum_fmtetc(NULL
);
1024 ref
= IDataObject_Release(data1
);
1025 ok(ref
== 0, "expected data1 ref=0, got %d\n", ref
);
1026 ref
= IDataObject_Release(data2
);
1027 ok(ref
== 0, "expected data2 ref=0, got %d\n", ref
);
1028 ref
= IDataObject_Release(data_cmpl
);
1029 ok(ref
== 0, "expected data_cmpl ref=0, got %d\n", ref
);
1034 static LPDATAOBJECT clip_data
;
1035 static HWND next_wnd
;
1036 static UINT wm_drawclipboard
;
1038 static LRESULT CALLBACK
clipboard_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1044 case WM_DRAWCLIPBOARD
:
1048 /* if this is the WM_DRAWCLIPBOARD of a previous change, the data isn't current yet */
1049 /* this demonstrates an issue in Qt where it will free the data while it's being set */
1050 HRESULT hr
= OleIsCurrentClipboard( clip_data
);
1051 ok( hr
== (wm_drawclipboard
> 1) ? S_OK
: S_FALSE
,
1052 "OleIsCurrentClipboard returned %x\n", hr
);
1055 case WM_CHANGECBCHAIN
:
1056 if (next_wnd
== (HWND
)wp
) next_wnd
= (HWND
)lp
;
1057 else if (next_wnd
) SendMessageA( next_wnd
, msg
, wp
, lp
);
1060 ret
= wm_drawclipboard
;
1061 wm_drawclipboard
= 0;
1065 return DefWindowProcA(hwnd
, msg
, wp
, lp
);
1068 static DWORD CALLBACK
set_clipboard_thread(void *arg
)
1070 OpenClipboard( GetDesktopWindow() );
1072 SetClipboardData( CF_WAVE
, 0 );
1077 /* test that WM_DRAWCLIPBOARD can be delivered for a previous change during OleSetClipboard */
1078 static void test_set_clipboard_DRAWCLIPBOARD(void)
1087 hr
= DataObjectImpl_CreateText("data", &data
);
1088 ok(hr
== S_OK
, "Failed to create data object: 0x%08x\n", hr
);
1090 memset(&cls
, 0, sizeof(cls
));
1091 cls
.lpfnWndProc
= clipboard_wnd_proc
;
1092 cls
.hInstance
= GetModuleHandleA(NULL
);
1093 cls
.lpszClassName
= "clipboard_test";
1094 RegisterClassA(&cls
);
1096 viewer
= CreateWindowA("clipboard_test", NULL
, 0, 0, 0, 0, 0, NULL
, 0, NULL
, 0);
1097 ok(viewer
!= NULL
, "CreateWindow failed: %d\n", GetLastError());
1098 next_wnd
= SetClipboardViewer( viewer
);
1100 ret
= SendMessageA( viewer
, WM_USER
, 0, 0 );
1101 ok( ret
== 1, "%u WM_DRAWCLIPBOARD received\n", ret
);
1103 hr
= OleInitialize(NULL
);
1104 ok(hr
== S_OK
, "OleInitialize failed with error 0x%08x\n", hr
);
1106 ret
= SendMessageA( viewer
, WM_USER
, 0, 0 );
1107 ok( !ret
, "%u WM_DRAWCLIPBOARD received\n", ret
);
1109 thread
= CreateThread(NULL
, 0, set_clipboard_thread
, NULL
, 0, NULL
);
1110 ok(thread
!= NULL
, "CreateThread failed (%d)\n", GetLastError());
1111 ret
= WaitForSingleObject(thread
, 5000);
1112 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %x\n", ret
);
1115 hr
= OleSetClipboard(data
);
1116 ok(hr
== S_OK
, "failed to set clipboard to data, hr = 0x%08x\n", hr
);
1118 ret
= SendMessageA( viewer
, WM_USER
, 0, 0 );
1119 ok( ret
== 2, "%u WM_DRAWCLIPBOARD received\n", ret
);
1122 hr
= OleFlushClipboard();
1123 ok(hr
== S_OK
, "failed to flush clipboard, hr = 0x%08x\n", hr
);
1124 ret
= IDataObject_Release(data
);
1125 ok(ret
== 0, "got %d\n", ret
);
1128 ChangeClipboardChain( viewer
, next_wnd
);
1129 DestroyWindow( viewer
);
1132 static inline ULONG
count_refs(IDataObject
*d
)
1134 IDataObject_AddRef(d
);
1135 return IDataObject_Release(d
);
1138 static void test_consumer_refs(void)
1141 IDataObject
*src
, *src2
, *get1
, *get2
, *get3
;
1142 ULONG refs
, old_refs
;
1146 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1148 OleInitialize(NULL
);
1150 /* First show that each clipboard state results in
1151 a different data object */
1153 hr
= DataObjectImpl_CreateText("data1", &src
);
1154 ok(hr
== S_OK
, "got %08x\n", hr
);
1155 hr
= DataObjectImpl_CreateText("data2", &src2
);
1156 ok(hr
== S_OK
, "got %08x\n", hr
);
1158 hr
= OleSetClipboard(src
);
1159 ok(hr
== S_OK
, "got %08x\n", hr
);
1161 hr
= OleGetClipboard(&get1
);
1162 ok(hr
== S_OK
, "got %08x\n", hr
);
1164 hr
= OleGetClipboard(&get2
);
1165 ok(hr
== S_OK
, "got %08x\n", hr
);
1167 ok(get1
== get2
, "data objects differ\n");
1168 refs
= IDataObject_Release(get2
);
1169 ok(refs
== (get1
== get2
? 1 : 0), "got %d\n", refs
);
1171 OleFlushClipboard();
1173 DataObjectImpl_GetData_calls
= 0;
1174 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1175 ok(hr
== S_OK
, "got %08x\n", hr
);
1176 ok(DataObjectImpl_GetData_calls
== 0, "GetData called\n");
1177 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1179 hr
= OleGetClipboard(&get2
);
1180 ok(hr
== S_OK
, "got %08x\n", hr
);
1182 ok(get1
!= get2
, "data objects match\n");
1184 OleSetClipboard(NULL
);
1186 hr
= OleGetClipboard(&get3
);
1187 ok(hr
== S_OK
, "got %08x\n", hr
);
1189 ok(get1
!= get3
, "data objects match\n");
1190 ok(get2
!= get3
, "data objects match\n");
1192 IDataObject_Release(get3
);
1193 IDataObject_Release(get2
);
1194 IDataObject_Release(get1
);
1196 /* Now call GetData before the flush and show that this
1197 takes a ref on our src data obj. */
1199 hr
= OleSetClipboard(src
);
1200 ok(hr
== S_OK
, "got %08x\n", hr
);
1202 old_refs
= count_refs(src
);
1204 hr
= OleGetClipboard(&get1
);
1205 ok(hr
== S_OK
, "got %08x\n", hr
);
1207 refs
= count_refs(src
);
1208 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
1210 DataObjectImpl_GetData_calls
= 0;
1211 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1212 ok(hr
== S_OK
, "got %08x\n", hr
);
1213 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1214 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1215 refs
= count_refs(src
);
1216 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
1218 OleFlushClipboard();
1220 DataObjectImpl_GetData_calls
= 0;
1221 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1222 ok(hr
== S_OK
, "got %08x\n", hr
);
1223 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1224 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1226 refs
= count_refs(src
);
1227 ok(refs
== 2, "%d\n", refs
);
1229 IDataObject_Release(get1
);
1231 refs
= count_refs(src
);
1232 ok(refs
== 1, "%d\n", refs
);
1234 /* Now set a second src object before the call to GetData
1235 and show that GetData calls that second src. */
1237 hr
= OleSetClipboard(src
);
1238 ok(hr
== S_OK
, "got %08x\n", hr
);
1240 old_refs
= count_refs(src
);
1242 hr
= OleGetClipboard(&get1
);
1243 ok(hr
== S_OK
, "got %08x\n", hr
);
1245 refs
= count_refs(src
);
1246 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
1248 hr
= OleSetClipboard(src2
);
1249 ok(hr
== S_OK
, "got %08x\n", hr
);
1251 old_refs
= count_refs(src2
);
1253 DataObjectImpl_GetData_calls
= 0;
1254 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1255 ok(hr
== S_OK
, "got %08x\n", hr
);
1256 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1257 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1259 refs
= count_refs(src
);
1260 ok(refs
== 1, "%d\n", refs
);
1261 refs
= count_refs(src2
);
1262 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
1264 OleSetClipboard(NULL
);
1266 refs
= count_refs(src2
);
1267 ok(refs
== 2, "%d\n", refs
);
1269 IDataObject_Release(get1
);
1271 IDataObject_Release(src2
);
1273 /* Show that OleUninitialize() doesn't release the
1274 dataobject's ref, and thus the object is leaked. */
1275 old_refs
= count_refs(src
);
1276 ok(old_refs
== 1, "%d\n", old_refs
);
1278 OleSetClipboard(src
);
1279 refs
= count_refs(src
);
1280 ok(refs
> old_refs
, "%d %d\n", refs
, old_refs
);
1283 refs
= count_refs(src
);
1284 ok(refs
== 2, "%d\n", refs
);
1286 IDataObject_Release(src
);
1289 static HGLOBAL
create_storage(void)
1296 hr
= CreateILockBytesOnHGlobal(NULL
, FALSE
, &ilb
);
1297 ok(hr
== S_OK
, "got %08x\n", hr
);
1298 hr
= StgCreateDocfileOnILockBytes(ilb
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &stg
);
1299 ok(hr
== S_OK
, "got %08x\n", hr
);
1300 IStorage_Release(stg
);
1301 hr
= GetHGlobalFromILockBytes(ilb
, &hg
);
1302 ok(hr
== S_OK
, "got %08x\n", hr
);
1303 ILockBytes_Release(ilb
);
1307 static void test_flushed_getdata(void)
1310 IDataObject
*src
, *get
;
1316 OleInitialize(NULL
);
1318 hr
= DataObjectImpl_CreateComplex(&src
);
1319 ok(hr
== S_OK
, "got %08x\n", hr
);
1321 hr
= OleSetClipboard(src
);
1322 ok(hr
== S_OK
, "got %08x\n", hr
);
1324 hr
= OleFlushClipboard();
1325 ok(hr
== S_OK
, "got %08x\n", hr
);
1327 hr
= OleGetClipboard(&get
);
1328 ok(hr
== S_OK
, "got %08x\n", hr
);
1330 /* global format -> global & stream */
1332 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1333 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1334 ok(hr
== S_OK
, "got %08x\n", hr
);
1335 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1336 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1338 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTREAM
);
1339 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1340 ok(hr
== S_OK
, "got %08x\n", hr
);
1341 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1342 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1344 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTORAGE
);
1345 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1346 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1347 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1349 InitFormatEtc(fmt
, CF_TEXT
, 0xffff);
1350 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1351 ok(hr
== S_OK
, "got %08x\n", hr
);
1352 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1353 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1355 /* stream format -> global & stream */
1357 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTREAM
);
1358 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1359 ok(hr
== S_OK
, "got %08x\n", hr
);
1360 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1361 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1363 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTORAGE
);
1364 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1365 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1366 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1368 InitFormatEtc(fmt
, cf_stream
, TYMED_HGLOBAL
);
1369 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1370 ok(hr
== S_OK
, "got %08x\n", hr
);
1371 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1372 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1374 InitFormatEtc(fmt
, cf_stream
, 0xffff);
1375 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1376 ok(hr
== S_OK
, "got %08x\n", hr
);
1377 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1378 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1380 /* storage format -> global, stream & storage */
1382 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTORAGE
);
1383 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1384 ok(hr
== S_OK
, "got %08x\n", hr
);
1385 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1387 hr
= IStorage_Stat(med
.pstg
, &stat
, STATFLAG_NONAME
);
1388 ok(hr
== S_OK
, "got %08x\n", hr
);
1389 ok(stat
.grfMode
== (STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
), "got %08x\n", stat
.grfMode
);
1390 ReleaseStgMedium(&med
);
1393 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTREAM
);
1394 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1395 ok(hr
== S_OK
, "got %08x\n", hr
);
1396 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1397 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1399 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
);
1400 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1401 ok(hr
== S_OK
, "got %08x\n", hr
);
1402 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1403 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1405 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
| TYMED_ISTREAM
);
1406 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1407 ok(hr
== S_OK
, "got %08x\n", hr
);
1408 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1409 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1411 InitFormatEtc(fmt
, cf_storage
, 0xffff);
1412 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1413 ok(hr
== S_OK
, "got %08x\n", hr
);
1414 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1415 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1417 /* complex format with target device */
1419 InitFormatEtc(fmt
, cf_another
, 0xffff);
1420 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1421 ok(hr
== S_OK
, "got %08x\n", hr
);
1422 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1424 if (0) /* Causes crashes on both Wine and Windows */
1426 InitFormatEtc(fmt
, cf_another
, 0xffff);
1427 memset(&dm
, 0, sizeof(dm
));
1428 dm
.dmSize
= sizeof(dm
);
1429 dm
.dmDriverExtra
= 0;
1430 lstrcpyW(dm
.dmDeviceName
, device_name
);
1431 fmt
.ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
);
1432 fmt
.ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
;
1433 fmt
.ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
1434 fmt
.ptd
->tdDeviceNameOffset
= 0;
1435 fmt
.ptd
->tdPortNameOffset
= 0;
1436 fmt
.ptd
->tdExtDevmodeOffset
= fmt
.ptd
->tdDriverNameOffset
+ sizeof(device_name
);
1437 lstrcpyW((WCHAR
*)fmt
.ptd
->tdData
, device_name
);
1438 memcpy(fmt
.ptd
->tdData
+ sizeof(device_name
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
1440 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1441 ok(hr
== S_OK
, "got %08x\n", hr
);
1442 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1443 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1445 HeapFree(GetProcessHeap(), 0, fmt
.ptd
);
1448 /* CF_ENHMETAFILE format */
1449 InitFormatEtc(fmt
, CF_ENHMETAFILE
, TYMED_ENHMF
);
1450 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1451 ok(hr
== S_OK
, "got %08x\n", hr
);
1452 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1454 IDataObject_Release(get
);
1455 IDataObject_Release(src
);
1457 hr
= DataObjectImpl_CreateFromHGlobal(create_storage(), &src
);
1458 ok(hr
== S_OK
, "got %08x\n", hr
);
1460 hr
= OleSetClipboard(src
);
1461 ok(hr
== S_OK
, "got %08x\n", hr
);
1463 hr
= OleGetClipboard(&get
);
1464 ok(hr
== S_OK
, "got %08x\n", hr
);
1465 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTORAGE
);
1466 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1467 ok(hr
== S_OK
, "got %08x\n", hr
);
1468 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1469 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1470 IDataObject_Release(get
);
1472 hr
= OleFlushClipboard();
1473 ok(hr
== S_OK
, "got %08x\n", hr
);
1475 hr
= OleGetClipboard(&get
);
1476 ok(hr
== S_OK
, "got %08x\n", hr
);
1478 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTORAGE
);
1479 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1480 ok(hr
== S_OK
, "got %08x\n", hr
);
1481 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1482 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1484 InitFormatEtc(fmt
, CF_TEXT
, 0xffff);
1485 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1486 ok(hr
== S_OK
, "got %08x\n", hr
);
1487 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1488 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1490 IDataObject_Release(get
);
1491 IDataObject_Release(src
);
1496 static HGLOBAL
create_text(void)
1498 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 5);
1499 char *p
= GlobalLock(h
);
1505 static HENHMETAFILE
create_emf(void)
1507 const RECT rect
= {0, 0, 100, 100};
1508 HDC hdc
= CreateEnhMetaFileA(NULL
, NULL
, &rect
, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1509 ExtTextOutA(hdc
, 0, 0, ETO_OPAQUE
, &rect
, "Test String", strlen("Test String"), NULL
);
1510 return CloseEnhMetaFile(hdc
);
1513 static void test_nonole_clipboard(void)
1518 IEnumFORMATETC
*enum_fmt
;
1520 HGLOBAL h
, hblob
, htext
, hstorage
;
1525 r
= OpenClipboard(NULL
);
1526 ok(r
, "gle %d\n", GetLastError());
1527 r
= EmptyClipboard();
1528 ok(r
, "gle %d\n", GetLastError());
1529 r
= CloseClipboard();
1530 ok(r
, "gle %d\n", GetLastError());
1532 OleInitialize(NULL
);
1534 /* empty clipboard */
1535 hr
= OleGetClipboard(&get
);
1536 ok(hr
== S_OK
, "got %08x\n", hr
);
1537 hr
= IDataObject_EnumFormatEtc(get
, DATADIR_GET
, &enum_fmt
);
1538 ok(hr
== S_OK
, "got %08x\n", hr
);
1540 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1541 ok(hr
== S_FALSE
, "got %08x\n", hr
);
1542 IEnumFORMATETC_Release(enum_fmt
);
1544 IDataObject_Release(get
);
1546 /* set a user defined clipboard type */
1548 htext
= create_text();
1549 hblob
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
|GMEM_ZEROINIT
, 10);
1551 hstorage
= create_storage();
1553 r
= OpenClipboard(NULL
);
1554 ok(r
, "gle %d\n", GetLastError());
1555 h
= SetClipboardData(CF_TEXT
, htext
);
1556 ok(h
== htext
, "got %p\n", h
);
1557 h
= SetClipboardData(cf_onemore
, hblob
);
1558 ok(h
== hblob
, "got %p\n", h
);
1559 h
= SetClipboardData(CF_ENHMETAFILE
, emf
);
1560 ok(h
== emf
, "got %p\n", h
);
1561 h
= SetClipboardData(cf_storage
, hstorage
);
1562 ok(h
== hstorage
, "got %p\n", h
);
1563 r
= CloseClipboard();
1564 ok(r
, "gle %d\n", GetLastError());
1566 hr
= OleGetClipboard(&get
);
1567 ok(hr
== S_OK
, "got %08x\n", hr
);
1568 hr
= IDataObject_EnumFormatEtc(get
, DATADIR_GET
, &enum_fmt
);
1569 ok(hr
== S_OK
, "got %08x\n", hr
);
1572 skip("EnumFormatEtc failed, skipping tests.\n");
1576 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1577 ok(hr
== S_OK
, "got %08x\n", hr
);
1578 ok(fmt
.cfFormat
== CF_TEXT
, "cf %04x\n", fmt
.cfFormat
);
1579 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1580 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1581 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1582 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1584 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1585 ok(hr
== S_OK
, "got %08x\n", hr
);
1586 ok(fmt
.cfFormat
== cf_onemore
, "cf %04x\n", fmt
.cfFormat
);
1587 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1588 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1589 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1590 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1592 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1593 ok(hr
== S_OK
, "got %08x\n", hr
);
1594 ok(fmt
.cfFormat
== CF_ENHMETAFILE
, "cf %04x\n", fmt
.cfFormat
);
1595 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1596 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1597 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1598 ok(fmt
.tymed
== TYMED_ENHMF
, "tymed %x\n", fmt
.tymed
);
1600 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1601 ok(hr
== S_OK
, "got %08x\n", hr
);
1602 ok(fmt
.cfFormat
== cf_storage
, "cf %04x\n", fmt
.cfFormat
);
1603 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1604 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1605 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1606 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1608 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1609 ok(hr
== S_OK
, "got %08x\n", hr
); /* User32 adds some synthesised formats */
1611 ok(fmt
.cfFormat
== CF_LOCALE
, "cf %04x\n", fmt
.cfFormat
);
1612 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1613 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1614 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1615 todo_wine
ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1617 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1618 ok(hr
== S_OK
, "got %08x\n", hr
);
1620 ok(fmt
.cfFormat
== CF_OEMTEXT
, "cf %04x\n", fmt
.cfFormat
);
1621 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1622 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1623 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1624 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1626 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1627 ok(hr
== S_OK
, "got %08x\n", hr
);
1628 ok(fmt
.cfFormat
== CF_UNICODETEXT
, "cf %04x\n", fmt
.cfFormat
);
1629 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1630 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1631 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1632 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1634 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1635 ok(hr
== S_OK
, "got %08x\n", hr
);
1636 ok(fmt
.cfFormat
== CF_METAFILEPICT
, "cf %04x\n", fmt
.cfFormat
);
1637 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1638 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1639 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1640 ok(fmt
.tymed
== TYMED_MFPICT
, "tymed %x\n", fmt
.tymed
);
1642 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1643 ok(hr
== S_FALSE
, "got %08x\n", hr
);
1644 IEnumFORMATETC_Release(enum_fmt
);
1646 InitFormatEtc(fmt
, CF_ENHMETAFILE
, TYMED_ENHMF
);
1647 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1648 ok(hr
== S_OK
, "got %08x\n", hr
);
1649 obj_type
= GetObjectType(U(med
).hEnhMetaFile
);
1650 ok(obj_type
== OBJ_ENHMETAFILE
, "got %d\n", obj_type
);
1651 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1653 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTORAGE
);
1654 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1655 ok(hr
== S_OK
, "got %08x\n", hr
);
1656 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1657 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1659 IDataObject_Release(get
);
1661 r
= OpenClipboard(NULL
);
1662 ok(r
, "gle %d\n", GetLastError());
1663 r
= EmptyClipboard();
1664 ok(r
, "gle %d\n", GetLastError());
1665 r
= CloseClipboard();
1666 ok(r
, "gle %d\n", GetLastError());
1671 static void test_getdatahere(void)
1674 IDataObject
*src
, *get
;
1678 OleInitialize(NULL
);
1680 hr
= DataObjectImpl_CreateComplex(&src
);
1681 ok(hr
== S_OK
, "got %08x\n", hr
);
1683 hr
= OleSetClipboard(src
);
1684 ok(hr
== S_OK
, "got %08x\n", hr
);
1686 hr
= OleGetClipboard(&get
);
1687 ok(hr
== S_OK
, "got %08x\n", hr
);
1689 /* global format -> global & stream */
1691 DataObjectImpl_GetData_calls
= 0;
1692 DataObjectImpl_GetDataHere_calls
= 0;
1694 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1696 med
.pUnkForRelease
= NULL
;
1697 med
.tymed
= TYMED_HGLOBAL
;
1698 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1699 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1700 ok(hr
== S_OK
, "got %08x\n", hr
);
1701 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1702 ReleaseStgMedium(&med
);
1703 ok(DataObjectImpl_GetDataHere_calls
== 1, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1704 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1706 InitFormatEtc(fmt
, CF_TEXT
, 0);
1708 med
.pUnkForRelease
= NULL
;
1709 med
.tymed
= TYMED_HGLOBAL
;
1710 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1711 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1712 ok(hr
== S_OK
, "got %08x\n", hr
);
1713 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1714 ReleaseStgMedium(&med
);
1715 ok(DataObjectImpl_GetDataHere_calls
== 2, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1716 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1718 med
.pUnkForRelease
= NULL
;
1719 med
.tymed
= TYMED_HGLOBAL
;
1720 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 1);
1721 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1722 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1723 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1724 ReleaseStgMedium(&med
);
1725 ok(DataObjectImpl_GetDataHere_calls
== 3, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1726 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1728 med
.pUnkForRelease
= NULL
;
1729 med
.tymed
= TYMED_ISTREAM
;
1730 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1731 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1732 ok(hr
== S_OK
, "got %08x\n", hr
);
1733 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1734 ReleaseStgMedium(&med
);
1735 ok(DataObjectImpl_GetDataHere_calls
== 4, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1736 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1738 med
.pUnkForRelease
= NULL
;
1739 med
.tymed
= TYMED_ISTORAGE
;
1740 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1741 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1742 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1743 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1744 ReleaseStgMedium(&med
);
1745 ok(DataObjectImpl_GetDataHere_calls
== 5, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1746 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1748 InitFormatEtc(fmt
, cf_stream
, 0);
1750 med
.pUnkForRelease
= NULL
;
1751 med
.tymed
= TYMED_HGLOBAL
;
1752 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1753 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1754 ok(hr
== S_OK
, "got %08x\n", hr
);
1755 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1756 ReleaseStgMedium(&med
);
1757 ok(DataObjectImpl_GetDataHere_calls
== 7, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1758 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1760 med
.pUnkForRelease
= NULL
;
1761 med
.tymed
= TYMED_ISTREAM
;
1762 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1763 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1764 ok(hr
== S_OK
, "got %08x\n", hr
);
1765 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1766 ReleaseStgMedium(&med
);
1767 ok(DataObjectImpl_GetDataHere_calls
== 8, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1768 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1770 med
.pUnkForRelease
= NULL
;
1771 med
.tymed
= TYMED_ISTORAGE
;
1772 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1773 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1774 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1775 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1776 ReleaseStgMedium(&med
);
1777 ok(DataObjectImpl_GetDataHere_calls
== 9, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1778 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1780 InitFormatEtc(fmt
, cf_storage
, 0);
1782 med
.pUnkForRelease
= NULL
;
1783 med
.tymed
= TYMED_HGLOBAL
;
1784 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 3000);
1785 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1786 ok(hr
== S_OK
, "got %08x\n", hr
);
1787 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1788 ReleaseStgMedium(&med
);
1789 ok(DataObjectImpl_GetDataHere_calls
== 11, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1790 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1792 med
.pUnkForRelease
= NULL
;
1793 med
.tymed
= TYMED_ISTREAM
;
1794 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1795 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1796 ok(hr
== S_OK
, "got %08x\n", hr
);
1797 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1798 ReleaseStgMedium(&med
);
1799 ok(DataObjectImpl_GetDataHere_calls
== 12, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1800 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1802 med
.pUnkForRelease
= NULL
;
1803 med
.tymed
= TYMED_ISTORAGE
;
1804 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1805 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1806 ok(hr
== S_OK
, "got %08x\n", hr
);
1807 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1808 ReleaseStgMedium(&med
);
1809 ok(DataObjectImpl_GetDataHere_calls
== 13, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1810 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1813 IDataObject_Release(get
);
1814 IDataObject_Release(src
);
1820 static DWORD CALLBACK
test_data_obj(void *arg
)
1822 IDataObject
*data_obj
= arg
;
1824 IDataObject_Release(data_obj
);
1828 static void test_multithreaded_clipboard(void)
1830 IDataObject
*data_obj
;
1835 OleInitialize(NULL
);
1837 hr
= OleGetClipboard(&data_obj
);
1838 ok(hr
== S_OK
, "OleGetClipboard returned %x\n", hr
);
1840 thread
= CreateThread(NULL
, 0, test_data_obj
, data_obj
, 0, NULL
);
1841 ok(thread
!= NULL
, "CreateThread failed (%d)\n", GetLastError());
1842 ret
= WaitForSingleObject(thread
, 5000);
1843 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %x\n", ret
);
1845 hr
= OleGetClipboard(&data_obj
);
1846 ok(hr
== S_OK
, "OleGetClipboard returned %x\n", hr
);
1847 IDataObject_Release(data_obj
);
1852 static void test_get_clipboard_locked(void)
1857 OleInitialize(NULL
);
1859 pDObj
= (IDataObject
*)0xdeadbeef;
1860 /* lock clipboard */
1861 OpenClipboard(NULL
);
1862 hr
= OleGetClipboard(&pDObj
);
1863 todo_wine
ok(hr
== CLIPBRD_E_CANT_OPEN
, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr
, CLIPBRD_E_CANT_OPEN
);
1864 todo_wine
ok(pDObj
== NULL
, "OleGetClipboard() got 0x%p instead of NULL\n",pDObj
);
1865 if (pDObj
) IDataObject_Release(pDObj
);
1871 START_TEST(clipboard
)
1873 test_get_clipboard_uninitialized();
1874 test_set_clipboard();
1875 test_set_clipboard_DRAWCLIPBOARD();
1876 test_consumer_refs();
1877 test_flushed_getdata();
1878 test_nonole_clipboard();
1880 test_multithreaded_clipboard();
1881 test_get_clipboard_locked();