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
23 #define NONAMELESSUNION
32 #include "wine/test.h"
34 #define InitFormatEtc(fe, cf, med) \
37 (fe).dwAspect=DVASPECT_CONTENT;\
43 static inline char *dump_fmtetc(FORMATETC
*fmt
)
47 snprintf(buf
, sizeof(buf
), "cf %04x ptd %p aspect %x lindex %d tymed %x",
48 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
52 typedef struct DataObjectImpl
{
53 IDataObject IDataObject_iface
;
64 typedef struct EnumFormatImpl
{
65 IEnumFORMATETC IEnumFORMATETC_iface
;
74 static BOOL expect_DataObjectImpl_QueryGetData
= TRUE
;
75 static ULONG DataObjectImpl_GetData_calls
= 0;
76 static ULONG DataObjectImpl_GetDataHere_calls
= 0;
77 static ULONG DataObjectImpl_EnumFormatEtc_calls
= 0;
79 static UINT cf_stream
, cf_storage
, cf_global
, cf_another
, cf_onemore
;
81 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT size
, LPENUMFORMATETC
*lplpformatetc
);
83 static inline DataObjectImpl
*impl_from_IDataObject(IDataObject
*iface
)
85 return CONTAINING_RECORD(iface
, DataObjectImpl
, IDataObject_iface
);
88 static inline EnumFormatImpl
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
90 return CONTAINING_RECORD(iface
, EnumFormatImpl
, IEnumFORMATETC_iface
);
93 static HRESULT WINAPI
EnumFormatImpl_QueryInterface(IEnumFORMATETC
*iface
, REFIID riid
, LPVOID
*ppvObj
)
95 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
97 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumFORMATETC
)) {
98 IEnumFORMATETC_AddRef(iface
);
99 *ppvObj
= &This
->IEnumFORMATETC_iface
;
103 return E_NOINTERFACE
;
106 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
108 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
109 LONG ref
= InterlockedIncrement(&This
->ref
);
113 static ULONG WINAPI
EnumFormatImpl_Release(IEnumFORMATETC
*iface
)
115 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
116 ULONG ref
= InterlockedDecrement(&This
->ref
);
119 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
120 HeapFree(GetProcessHeap(), 0, This
);
126 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
127 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
129 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
132 if (winetest_debug
> 1)
133 trace("next: count %d cur %d\n", celt
, This
->cur
);
138 count
= min(celt
, This
->fmtetc_cnt
- This
->cur
);
139 for(i
= 0; i
< count
; i
++, This
->cur
++, rgelt
++)
141 *rgelt
= This
->fmtetc
[This
->cur
];
144 DWORD size
= This
->fmtetc
[This
->cur
].ptd
->tdSize
;
145 rgelt
->ptd
= CoTaskMemAlloc(size
);
146 memcpy(rgelt
->ptd
, This
->fmtetc
[This
->cur
].ptd
, size
);
150 *pceltFetched
= count
;
151 return count
== celt
? S_OK
: S_FALSE
;
154 static HRESULT WINAPI
EnumFormatImpl_Skip(IEnumFORMATETC
*iface
, ULONG celt
)
156 ok(0, "unexpected call\n");
160 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
162 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
168 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
170 ok(0, "unexpected call\n");
174 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
175 EnumFormatImpl_QueryInterface
,
176 EnumFormatImpl_AddRef
,
177 EnumFormatImpl_Release
,
180 EnumFormatImpl_Reset
,
184 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
188 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl
));
189 ret
->IEnumFORMATETC_iface
.lpVtbl
= &VT_EnumFormatImpl
;
192 ret
->fmtetc_cnt
= fmtetc_cnt
;
193 ret
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt
*sizeof(FORMATETC
));
194 memcpy(ret
->fmtetc
, fmtetc
, fmtetc_cnt
*sizeof(FORMATETC
));
195 *lplpformatetc
= &ret
->IEnumFORMATETC_iface
;
199 static HRESULT WINAPI
DataObjectImpl_QueryInterface(IDataObject
*iface
, REFIID riid
, LPVOID
*ppvObj
)
201 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
203 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDataObject
)) {
204 IDataObject_AddRef(iface
);
205 *ppvObj
= &This
->IDataObject_iface
;
209 return E_NOINTERFACE
;
212 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
214 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
215 ULONG ref
= InterlockedIncrement(&This
->ref
);
219 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
221 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
222 ULONG ref
= InterlockedDecrement(&This
->ref
);
227 if(This
->text
) GlobalFree(This
->text
);
228 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
229 HeapFree(GetProcessHeap(), 0, This
->fmtetc
[i
].ptd
);
230 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
231 if(This
->stm
) IStream_Release(This
->stm
);
232 if(This
->stg
) IStorage_Release(This
->stg
);
233 HeapFree(GetProcessHeap(), 0, This
);
239 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
241 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
243 BOOL foundFormat
= FALSE
;
245 trace("getdata: %s\n", dump_fmtetc(pformatetc
));
247 DataObjectImpl_GetData_calls
++;
249 if(pformatetc
->lindex
!= -1)
250 return DV_E_FORMATETC
;
252 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
254 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
)
257 if(This
->fmtetc
[i
].tymed
& pformatetc
->tymed
)
259 pmedium
->pUnkForRelease
= (LPUNKNOWN
)iface
;
260 IUnknown_AddRef(pmedium
->pUnkForRelease
);
262 if(pformatetc
->cfFormat
== CF_TEXT
|| pformatetc
->cfFormat
== cf_global
)
264 pmedium
->tymed
= TYMED_HGLOBAL
;
265 U(*pmedium
).hGlobal
= This
->text
;
267 else if(pformatetc
->cfFormat
== cf_stream
)
269 pmedium
->tymed
= TYMED_ISTREAM
;
270 IStream_AddRef(This
->stm
);
271 U(*pmedium
).pstm
= This
->stm
;
273 else if(pformatetc
->cfFormat
== cf_storage
|| pformatetc
->cfFormat
== cf_another
)
275 pmedium
->tymed
= TYMED_ISTORAGE
;
276 IStorage_AddRef(This
->stg
);
277 U(*pmedium
).pstg
= This
->stg
;
284 return foundFormat
? DV_E_TYMED
: DV_E_FORMATETC
;
287 static HRESULT WINAPI
DataObjectImpl_GetDataHere(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
289 trace("getdatahere: %s\n", dump_fmtetc(pformatetc
));
290 DataObjectImpl_GetDataHere_calls
++;
295 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
297 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
299 BOOL foundFormat
= FALSE
;
301 trace("querygetdata: %s\n", dump_fmtetc(pformatetc
));
302 if (!expect_DataObjectImpl_QueryGetData
)
303 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
305 if(pformatetc
->lindex
!= -1)
308 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
309 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
311 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
315 return foundFormat
?DV_E_FORMATETC
:DV_E_TYMED
;
318 static HRESULT WINAPI
DataObjectImpl_GetCanonicalFormatEtc(IDataObject
* iface
, FORMATETC
*pformatectIn
,
319 FORMATETC
*pformatetcOut
)
321 ok(0, "unexpected call\n");
325 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
326 STGMEDIUM
*pmedium
, BOOL fRelease
)
328 ok(0, "unexpected call\n");
332 static HRESULT WINAPI
DataObjectImpl_EnumFormatEtc(IDataObject
* iface
, DWORD dwDirection
,
333 IEnumFORMATETC
**ppenumFormatEtc
)
335 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
337 DataObjectImpl_EnumFormatEtc_calls
++;
339 if(dwDirection
!= DATADIR_GET
) {
340 ok(0, "unexpected direction %d\n", dwDirection
);
343 return EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenumFormatEtc
);
346 static HRESULT WINAPI
DataObjectImpl_DAdvise(IDataObject
* iface
, FORMATETC
*pformatetc
, DWORD advf
,
347 IAdviseSink
*pAdvSink
, DWORD
*pdwConnection
)
349 ok(0, "unexpected call\n");
353 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
355 ok(0, "unexpected call\n");
359 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
361 ok(0, "unexpected call\n");
365 static const IDataObjectVtbl VT_DataObjectImpl
=
367 DataObjectImpl_QueryInterface
,
368 DataObjectImpl_AddRef
,
369 DataObjectImpl_Release
,
370 DataObjectImpl_GetData
,
371 DataObjectImpl_GetDataHere
,
372 DataObjectImpl_QueryGetData
,
373 DataObjectImpl_GetCanonicalFormatEtc
,
374 DataObjectImpl_SetData
,
375 DataObjectImpl_EnumFormatEtc
,
376 DataObjectImpl_DAdvise
,
377 DataObjectImpl_DUnadvise
,
378 DataObjectImpl_EnumDAdvise
381 static HRESULT
DataObjectImpl_CreateText(LPCSTR text
, LPDATAOBJECT
*lplpdataobj
)
385 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
386 obj
->IDataObject_iface
.lpVtbl
= &VT_DataObjectImpl
;
388 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(text
) + 1);
389 strcpy(GlobalLock(obj
->text
), text
);
390 GlobalUnlock(obj
->text
);
395 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
396 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
398 *lplpdataobj
= &obj
->IDataObject_iface
;
402 static const char *cmpl_stm_data
= "complex stream";
403 static const char *cmpl_text_data
= "complex text";
404 static const WCHAR device_name
[] = {'m','y','d','e','v',0};
406 static HRESULT
DataObjectImpl_CreateComplex(LPDATAOBJECT
*lplpdataobj
)
412 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
413 obj
->IDataObject_iface
.lpVtbl
= &VT_DataObjectImpl
;
415 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(cmpl_text_data
) + 1);
416 strcpy(GlobalLock(obj
->text
), cmpl_text_data
);
417 GlobalUnlock(obj
->text
);
418 CreateStreamOnHGlobal(NULL
, TRUE
, &obj
->stm
);
419 IStream_Write(obj
->stm
, cmpl_stm_data
, strlen(cmpl_stm_data
), NULL
);
421 CreateILockBytesOnHGlobal(NULL
, TRUE
, &lbs
);
422 StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &obj
->stg
);
423 ILockBytes_Release(lbs
);
426 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
427 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
428 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
429 InitFormatEtc(obj
->fmtetc
[1], cf_stream
, TYMED_ISTREAM
);
430 InitFormatEtc(obj
->fmtetc
[2], cf_storage
, TYMED_ISTORAGE
);
431 InitFormatEtc(obj
->fmtetc
[3], cf_another
, TYMED_ISTORAGE
|TYMED_ISTREAM
|TYMED_HGLOBAL
);
432 if (0) /* Causes crashes on both Wine and Windows */
434 memset(&dm
, 0, sizeof(dm
));
435 dm
.dmSize
= sizeof(dm
);
436 dm
.dmDriverExtra
= 0;
437 lstrcpyW(dm
.dmDeviceName
, device_name
);
438 obj
->fmtetc
[3].ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
);
439 obj
->fmtetc
[3].ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
;
440 obj
->fmtetc
[3].ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
441 obj
->fmtetc
[3].ptd
->tdDeviceNameOffset
= 0;
442 obj
->fmtetc
[3].ptd
->tdPortNameOffset
= 0;
443 obj
->fmtetc
[3].ptd
->tdExtDevmodeOffset
= obj
->fmtetc
[3].ptd
->tdDriverNameOffset
+ sizeof(device_name
);
444 lstrcpyW((WCHAR
*)obj
->fmtetc
[3].ptd
->tdData
, device_name
);
445 memcpy(obj
->fmtetc
[3].ptd
->tdData
+ sizeof(device_name
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
448 InitFormatEtc(obj
->fmtetc
[4], cf_global
, TYMED_HGLOBAL
);
449 InitFormatEtc(obj
->fmtetc
[5], cf_another
, TYMED_HGLOBAL
);
450 InitFormatEtc(obj
->fmtetc
[6], cf_another
, 0xfffff);
451 InitFormatEtc(obj
->fmtetc
[7], cf_another
, 0xfffff);
452 obj
->fmtetc
[7].dwAspect
= DVASPECT_ICON
;
454 *lplpdataobj
= &obj
->IDataObject_iface
;
458 static void test_get_clipboard_uninitialized(void)
463 pDObj
= (IDataObject
*)0xdeadbeef;
464 hr
= OleGetClipboard(&pDObj
);
465 todo_wine
ok(hr
== S_OK
, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr
, S_OK
);
466 if (pDObj
&& pDObj
!= (IDataObject
*)0xdeadbeef) IDataObject_Release(pDObj
);
469 static void test_get_clipboard(void)
472 IDataObject
*data_obj
;
476 hr
= OleGetClipboard(NULL
);
477 ok(hr
== E_INVALIDARG
, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr
);
479 hr
= OleGetClipboard(&data_obj
);
480 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
482 /* test IDataObject_QueryGetData */
484 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
485 expect_DataObjectImpl_QueryGetData
= FALSE
;
487 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
488 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
489 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
491 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
492 fmtetc
.dwAspect
= 0xdeadbeef;
493 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
494 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
496 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
497 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
498 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
499 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
501 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
503 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
504 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
),
505 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
507 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
508 fmtetc
.cfFormat
= CF_RIFF
;
509 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
510 ok(hr
== DV_E_CLIPFORMAT
, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr
);
512 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
513 fmtetc
.tymed
= TYMED_FILE
;
514 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
515 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
517 expect_DataObjectImpl_QueryGetData
= TRUE
;
519 /* test IDataObject_GetData */
521 DataObjectImpl_GetData_calls
= 0;
523 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
524 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
525 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
526 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
528 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
529 fmtetc
.dwAspect
= 0xdeadbeef;
530 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
531 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
532 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
534 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
535 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
536 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
537 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
538 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
540 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
542 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
543 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
546 /* undo the unexpected success */
547 DataObjectImpl_GetData_calls
--;
548 ReleaseStgMedium(&stgmedium
);
551 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
552 fmtetc
.cfFormat
= CF_RIFF
;
553 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
554 ok(hr
== DV_E_FORMATETC
, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
555 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
557 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
558 fmtetc
.tymed
= TYMED_FILE
;
559 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
560 ok(hr
== DV_E_TYMED
, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr
);
561 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
563 ok(DataObjectImpl_GetData_calls
== 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls
);
565 IDataObject_Release(data_obj
);
568 static void test_enum_fmtetc(IDataObject
*src
)
572 IEnumFORMATETC
*enum_fmt
, *src_enum
;
573 FORMATETC fmt
, src_fmt
;
576 hr
= OleGetClipboard(&data
);
577 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
579 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_SET
, &enum_fmt
);
580 ok(hr
== E_NOTIMPL
||
581 broken(hr
== E_INVALIDARG
), /* win98 (not win98SE) */
584 DataObjectImpl_EnumFormatEtc_calls
= 0;
585 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
586 ok(hr
== S_OK
, "got %08x\n", hr
);
587 ok(DataObjectImpl_EnumFormatEtc_calls
== 0, "EnumFormatEtc was called\n");
589 if(src
) IDataObject_EnumFormatEtc(src
, DATADIR_GET
, &src_enum
);
591 while((hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
)) == S_OK
)
593 ok(src
!= NULL
, "shouldn't be here\n");
594 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
595 ok(hr
== S_OK
, "%d: got %08x\n", count
, hr
);
596 trace("%d: %s\n", count
, dump_fmtetc(&fmt
));
597 ok(fmt
.cfFormat
== src_fmt
.cfFormat
, "%d: %04x %04x\n", count
, fmt
.cfFormat
, src_fmt
.cfFormat
);
598 ok(fmt
.dwAspect
== src_fmt
.dwAspect
, "%d: %08x %08x\n", count
, fmt
.dwAspect
, src_fmt
.dwAspect
);
599 ok(fmt
.lindex
== src_fmt
.lindex
, "%d: %08x %08x\n", count
, fmt
.lindex
, src_fmt
.lindex
);
600 ok(fmt
.tymed
== src_fmt
.tymed
, "%d: %08x %08x\n", count
, fmt
.tymed
, src_fmt
.tymed
);
603 ok(src_fmt
.ptd
!= NULL
, "%d: expected non-NULL\n", count
);
604 CoTaskMemFree(fmt
.ptd
);
605 CoTaskMemFree(src_fmt
.ptd
);
610 ok(hr
== S_FALSE
, "%d: got %08x\n", count
, hr
);
614 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
615 ok(hr
== S_FALSE
, "%d: got %08x\n", count
, hr
);
616 IEnumFORMATETC_Release(src_enum
);
619 hr
= IEnumFORMATETC_Reset(enum_fmt
);
620 ok(hr
== S_OK
, "got %08x\n", hr
);
622 if(src
) /* Exercise the enumerator a bit */
624 IEnumFORMATETC
*clone
;
627 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
628 ok(hr
== S_OK
, "got %08x\n", hr
);
629 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
630 ok(hr
== S_OK
, "got %08x\n", hr
);
631 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
632 ok(hr
== S_OK
, "got %08x\n", hr
);
634 hr
= IEnumFORMATETC_Reset(enum_fmt
);
635 ok(hr
== S_OK
, "got %08x\n", hr
);
636 hr
= IEnumFORMATETC_Skip(enum_fmt
, 2);
637 ok(hr
== S_OK
, "got %08x\n", hr
);
639 hr
= IEnumFORMATETC_Clone(enum_fmt
, &clone
);
640 ok(hr
== S_OK
, "got %08x\n", hr
);
641 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
642 ok(hr
== S_OK
, "got %08x\n", hr
);
643 ok(fmt
.cfFormat
== third_fmt
.cfFormat
, "formats don't match\n");
644 hr
= IEnumFORMATETC_Next(clone
, 1, &fmt
, NULL
);
645 ok(hr
== S_OK
, "got %08x\n", hr
);
646 ok(fmt
.cfFormat
== third_fmt
.cfFormat
, "formats don't match\n");
647 IEnumFORMATETC_Release(clone
);
650 IEnumFORMATETC_Release(enum_fmt
);
651 IDataObject_Release(data
);
654 static void test_no_cf_dataobject(void)
656 UINT cf_dataobject
= RegisterClipboardFormatA("DataObject");
657 UINT cf_ole_priv_data
= RegisterClipboardFormatA("Ole Private Data");
661 h
= GetClipboardData(cf_dataobject
);
662 ok(!h
, "got %p\n", h
);
663 h
= GetClipboardData(cf_ole_priv_data
);
664 ok(!h
, "got %p\n", h
);
669 static void test_cf_dataobject(IDataObject
*data
)
672 UINT cf_dataobject
= RegisterClipboardFormatA("DataObject");
673 UINT cf_ole_priv_data
= RegisterClipboardFormatA("Ole Private Data");
674 BOOL found_dataobject
= FALSE
, found_priv_data
= FALSE
;
679 cf
= EnumClipboardFormats(cf
);
680 if(cf
== cf_dataobject
)
682 HGLOBAL h
= GetClipboardData(cf
);
683 HWND
*ptr
= GlobalLock(h
);
684 DWORD size
= GlobalSize(h
);
685 HWND clip_owner
= GetClipboardOwner();
687 found_dataobject
= TRUE
;
688 ok(size
>= sizeof(*ptr
), "size %d\n", size
);
690 ok(*ptr
== clip_owner
, "hwnd %p clip_owner %p\n", *ptr
, clip_owner
);
691 else /* ole clipboard flushed */
692 ok(*ptr
== NULL
, "hwnd %p\n", *ptr
);
695 else if(cf
== cf_ole_priv_data
)
697 found_priv_data
= TRUE
;
700 HGLOBAL h
= GetClipboardData(cf
);
701 DWORD
*ptr
= GlobalLock(h
);
702 DWORD size
= GlobalSize(h
);
705 win_skip("Ole Private Data in win9x format\n");
709 IEnumFORMATETC
*enum_fmt
;
715 BOOL first_use_of_cf
;
725 struct formatetcetc fmts
[1];
726 } *priv
= (struct priv_data
*)ptr
;
727 CLIPFORMAT cfs_seen
[10];
729 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
730 ok(hr
== S_OK
, "got %08x\n", hr
);
731 fmt_ptr
= priv
->fmts
;
733 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
736 BOOL seen_cf
= FALSE
;
738 ok(fmt_ptr
->fmt
.cfFormat
== fmt
.cfFormat
,
739 "got %08x expected %08x\n", fmt_ptr
->fmt
.cfFormat
, fmt
.cfFormat
);
740 ok(fmt_ptr
->fmt
.dwAspect
== fmt
.dwAspect
, "got %08x expected %08x\n",
741 fmt_ptr
->fmt
.dwAspect
, fmt
.dwAspect
);
742 ok(fmt_ptr
->fmt
.lindex
== fmt
.lindex
, "got %08x expected %08x\n",
743 fmt_ptr
->fmt
.lindex
, fmt
.lindex
);
744 ok(fmt_ptr
->fmt
.tymed
== fmt
.tymed
, "got %08x expected %08x\n",
745 fmt_ptr
->fmt
.tymed
, fmt
.tymed
);
746 for(i
= 0; i
< count
; i
++)
747 if(fmt_ptr
->fmt
.cfFormat
== cfs_seen
[i
])
752 cfs_seen
[count
] = fmt
.cfFormat
;
753 ok(fmt_ptr
->first_use_of_cf
!= seen_cf
, "got %08x expected %08x\n",
754 fmt_ptr
->first_use_of_cf
, !seen_cf
);
755 ok(fmt_ptr
->res
[0] == 0, "got %08x\n", fmt_ptr
->res
[0]);
756 ok(fmt_ptr
->res
[1] == 0, "got %08x\n", fmt_ptr
->res
[1]);
759 DVTARGETDEVICE
*target
;
761 ok(fmt_ptr
->fmt
.ptd
!= NULL
, "target device offset zero\n");
762 target
= (DVTARGETDEVICE
*)((char*)priv
+ (DWORD_PTR
)fmt_ptr
->fmt
.ptd
);
763 ok(!memcmp(target
, fmt
.ptd
, fmt
.ptd
->tdSize
), "target devices differ\n");
764 CoTaskMemFree(fmt
.ptd
);
769 ok(priv
->res1
== 0, "got %08x\n", priv
->res1
);
770 ok(priv
->res2
== 1, "got %08x\n", priv
->res2
);
771 ok(priv
->count
== count
, "got %08x expected %08x\n", priv
->count
, count
);
772 ok(priv
->res3
[0] == 0, "got %08x\n", priv
->res3
[0]);
774 /* win64 sets the lsb */
775 if(sizeof(fmt_ptr
->fmt
.ptd
) == 8)
776 todo_wine
ok(priv
->res3
[1] == 1, "got %08x\n", priv
->res3
[1]);
778 ok(priv
->res3
[1] == 0, "got %08x\n", priv
->res3
[1]);
781 IEnumFORMATETC_Release(enum_fmt
);
785 else if(cf
== cf_stream
)
791 DataObjectImpl_GetDataHere_calls
= 0;
792 h
= GetClipboardData(cf
);
793 ok(DataObjectImpl_GetDataHere_calls
== 1, "got %d\n", DataObjectImpl_GetDataHere_calls
);
795 size
= GlobalSize(h
);
796 ok(size
== strlen(cmpl_stm_data
),
797 "expected %d got %d\n", lstrlenA(cmpl_stm_data
), size
);
798 ok(!memcmp(ptr
, cmpl_stm_data
, strlen(cmpl_stm_data
)), "mismatch\n");
801 else if(cf
== cf_global
)
807 DataObjectImpl_GetDataHere_calls
= 0;
808 h
= GetClipboardData(cf
);
809 ok(DataObjectImpl_GetDataHere_calls
== 0, "got %d\n", DataObjectImpl_GetDataHere_calls
);
811 size
= GlobalSize(h
);
812 ok(size
== strlen(cmpl_text_data
) + 1,
813 "expected %d got %d\n", lstrlenA(cmpl_text_data
) + 1, size
);
814 ok(!memcmp(ptr
, cmpl_text_data
, strlen(cmpl_text_data
) + 1), "mismatch\n");
819 ok(found_dataobject
, "didn't find cf_dataobject\n");
820 ok(found_priv_data
, "didn't find cf_ole_priv_data\n");
823 static void test_set_clipboard(void)
827 LPDATAOBJECT data1
, data2
, data_cmpl
;
831 cf_stream
= RegisterClipboardFormatA("stream format");
832 cf_storage
= RegisterClipboardFormatA("storage format");
833 cf_global
= RegisterClipboardFormatA("global format");
834 cf_another
= RegisterClipboardFormatA("another format");
835 cf_onemore
= RegisterClipboardFormatA("one more format");
837 hr
= DataObjectImpl_CreateText("data1", &data1
);
838 ok(hr
== S_OK
, "Failed to create data1 object: 0x%08x\n", hr
);
841 hr
= DataObjectImpl_CreateText("data2", &data2
);
842 ok(hr
== S_OK
, "Failed to create data2 object: 0x%08x\n", hr
);
845 hr
= DataObjectImpl_CreateComplex(&data_cmpl
);
846 ok(hr
== S_OK
, "Failed to create complex data object: 0x%08x\n", hr
);
850 hr
= OleSetClipboard(data1
);
851 ok(hr
== CO_E_NOTINITIALIZED
, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr
);
854 hr
= OleSetClipboard(data1
);
855 ok(hr
== CO_E_NOTINITIALIZED
, "OleSetClipboard failed with 0x%08x\n", hr
);
858 hr
= OleInitialize(NULL
);
859 ok(hr
== S_OK
, "OleInitialize failed with error 0x%08x\n", hr
);
861 hr
= OleSetClipboard(data1
);
862 ok(hr
== S_OK
, "failed to set clipboard to data1, hr = 0x%08x\n", hr
);
864 test_cf_dataobject(data1
);
866 hr
= OleIsCurrentClipboard(data1
);
867 ok(hr
== S_OK
, "expected current clipboard to be data1, hr = 0x%08x\n", hr
);
868 hr
= OleIsCurrentClipboard(data2
);
869 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
870 hr
= OleIsCurrentClipboard(NULL
);
871 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
873 test_get_clipboard();
875 hr
= OleSetClipboard(data2
);
876 ok(hr
== S_OK
, "failed to set clipboard to data2, hr = 0x%08x\n", hr
);
877 hr
= OleIsCurrentClipboard(data1
);
878 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
879 hr
= OleIsCurrentClipboard(data2
);
880 ok(hr
== S_OK
, "expected current clipboard to be data2, hr = 0x%08x\n", hr
);
881 hr
= OleIsCurrentClipboard(NULL
);
882 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
884 /* put a format directly onto the clipboard to show
885 OleFlushClipboard doesn't empty the clipboard */
886 hblob
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
|GMEM_ZEROINIT
, 10);
887 ptr
= GlobalLock( hblob
);
888 ok( ptr
&& ptr
!= hblob
, "got fixed block %p / %p\n", ptr
, hblob
);
889 GlobalUnlock( hblob
);
890 ok( OpenClipboard(NULL
), "OpenClipboard failed\n" );
891 h
= SetClipboardData(cf_onemore
, hblob
);
892 ok(h
== hblob
, "got %p\n", h
);
893 h
= GetClipboardData(cf_onemore
);
894 ok(h
== hblob
, "got %p / %p\n", h
, hblob
);
895 ptr
= GlobalLock( h
);
896 ok( ptr
&& ptr
!= h
, "got fixed block %p / %p\n", ptr
, h
);
897 GlobalUnlock( hblob
);
898 ok( CloseClipboard(), "CloseClipboard failed\n" );
900 hr
= OleFlushClipboard();
901 ok(hr
== S_OK
, "failed to flush clipboard, hr = 0x%08x\n", hr
);
902 hr
= OleIsCurrentClipboard(data1
);
903 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
904 hr
= OleIsCurrentClipboard(data2
);
905 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
906 hr
= OleIsCurrentClipboard(NULL
);
907 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
909 /* format should survive the flush */
910 ok( OpenClipboard(NULL
), "OpenClipboard failed\n" );
911 h
= GetClipboardData(cf_onemore
);
912 ok(h
== hblob
, "got %p\n", h
);
913 ptr
= GlobalLock( h
);
914 ok( ptr
&& ptr
!= h
, "got fixed block %p / %p\n", ptr
, h
);
915 GlobalUnlock( hblob
);
916 ok( CloseClipboard(), "CloseClipboard failed\n" );
918 test_cf_dataobject(NULL
);
920 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
923 h
= GetClipboardData(cf_onemore
);
924 ok(h
== NULL
, "got %p\n", h
);
927 trace("setting complex\n");
928 hr
= OleSetClipboard(data_cmpl
);
929 ok(hr
== S_OK
, "failed to set clipboard to complex data, hr = 0x%08x\n", hr
);
930 test_cf_dataobject(data_cmpl
);
931 test_enum_fmtetc(data_cmpl
);
933 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
935 test_no_cf_dataobject();
936 test_enum_fmtetc(NULL
);
938 ref
= IDataObject_Release(data1
);
939 ok(ref
== 0, "expected data1 ref=0, got %d\n", ref
);
940 ref
= IDataObject_Release(data2
);
941 ok(ref
== 0, "expected data2 ref=0, got %d\n", ref
);
942 ref
= IDataObject_Release(data_cmpl
);
943 ok(ref
== 0, "expected data_cmpl ref=0, got %d\n", ref
);
948 static LPDATAOBJECT clip_data
;
949 static HWND next_wnd
;
950 static UINT wm_drawclipboard
;
952 static LRESULT CALLBACK
clipboard_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
958 case WM_DRAWCLIPBOARD
:
962 /* if this is the WM_DRAWCLIPBOARD of a previous change, the data isn't current yet */
963 /* this demonstrates an issue in Qt where it will free the data while it's being set */
964 HRESULT hr
= OleIsCurrentClipboard( clip_data
);
965 ok( hr
== (wm_drawclipboard
> 1) ? S_OK
: S_FALSE
,
966 "OleIsCurrentClipboard returned %x\n", hr
);
969 case WM_CHANGECBCHAIN
:
970 if (next_wnd
== (HWND
)wp
) next_wnd
= (HWND
)lp
;
971 else if (next_wnd
) SendMessageA( next_wnd
, msg
, wp
, lp
);
974 ret
= wm_drawclipboard
;
975 wm_drawclipboard
= 0;
979 return DefWindowProcA(hwnd
, msg
, wp
, lp
);
982 static DWORD CALLBACK
set_clipboard_thread(void *arg
)
984 OpenClipboard( GetDesktopWindow() );
986 SetClipboardData( CF_WAVE
, 0 );
991 /* test that WM_DRAWCLIPBOARD can be delivered for a previous change during OleSetClipboard */
992 static void test_set_clipboard_DRAWCLIPBOARD(void)
1001 hr
= DataObjectImpl_CreateText("data", &data
);
1002 ok(hr
== S_OK
, "Failed to create data object: 0x%08x\n", hr
);
1004 memset(&cls
, 0, sizeof(cls
));
1005 cls
.lpfnWndProc
= clipboard_wnd_proc
;
1006 cls
.hInstance
= GetModuleHandleA(NULL
);
1007 cls
.lpszClassName
= "clipboard_test";
1008 RegisterClassA(&cls
);
1010 viewer
= CreateWindowA("clipboard_test", NULL
, 0, 0, 0, 0, 0, NULL
, 0, NULL
, 0);
1011 ok(viewer
!= NULL
, "CreateWindow failed: %d\n", GetLastError());
1012 next_wnd
= SetClipboardViewer( viewer
);
1014 ret
= SendMessageA( viewer
, WM_USER
, 0, 0 );
1015 ok( ret
== 1, "%u WM_DRAWCLIPBOARD received\n", ret
);
1017 hr
= OleInitialize(NULL
);
1018 ok(hr
== S_OK
, "OleInitialize failed with error 0x%08x\n", hr
);
1020 ret
= SendMessageA( viewer
, WM_USER
, 0, 0 );
1021 ok( !ret
, "%u WM_DRAWCLIPBOARD received\n", ret
);
1023 thread
= CreateThread(NULL
, 0, set_clipboard_thread
, NULL
, 0, NULL
);
1024 ok(thread
!= NULL
, "CreateThread failed (%d)\n", GetLastError());
1025 ret
= WaitForSingleObject(thread
, 5000);
1026 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %x\n", ret
);
1029 hr
= OleSetClipboard(data
);
1030 ok(hr
== S_OK
, "failed to set clipboard to data, hr = 0x%08x\n", hr
);
1032 ret
= SendMessageA( viewer
, WM_USER
, 0, 0 );
1033 ok( ret
== 2, "%u WM_DRAWCLIPBOARD received\n", ret
);
1036 hr
= OleFlushClipboard();
1037 ok(hr
== S_OK
, "failed to flush clipboard, hr = 0x%08x\n", hr
);
1038 ret
= IDataObject_Release(data
);
1039 ok(ret
== 0, "got %d\n", ret
);
1042 ChangeClipboardChain( viewer
, next_wnd
);
1043 DestroyWindow( viewer
);
1046 static inline ULONG
count_refs(IDataObject
*d
)
1048 IDataObject_AddRef(d
);
1049 return IDataObject_Release(d
);
1052 static void test_consumer_refs(void)
1055 IDataObject
*src
, *src2
, *get1
, *get2
, *get3
;
1056 ULONG refs
, old_refs
;
1060 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1062 OleInitialize(NULL
);
1064 /* First show that each clipboard state results in
1065 a different data object */
1067 hr
= DataObjectImpl_CreateText("data1", &src
);
1068 ok(hr
== S_OK
, "got %08x\n", hr
);
1069 hr
= DataObjectImpl_CreateText("data2", &src2
);
1070 ok(hr
== S_OK
, "got %08x\n", hr
);
1072 hr
= OleSetClipboard(src
);
1073 ok(hr
== S_OK
, "got %08x\n", hr
);
1075 hr
= OleGetClipboard(&get1
);
1076 ok(hr
== S_OK
, "got %08x\n", hr
);
1078 hr
= OleGetClipboard(&get2
);
1079 ok(hr
== S_OK
, "got %08x\n", hr
);
1081 ok(get1
== get2
, "data objects differ\n");
1082 refs
= IDataObject_Release(get2
);
1083 ok(refs
== (get1
== get2
? 1 : 0), "got %d\n", refs
);
1085 OleFlushClipboard();
1087 DataObjectImpl_GetData_calls
= 0;
1088 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1089 ok(hr
== S_OK
, "got %08x\n", hr
);
1090 ok(DataObjectImpl_GetData_calls
== 0, "GetData called\n");
1091 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1093 hr
= OleGetClipboard(&get2
);
1094 ok(hr
== S_OK
, "got %08x\n", hr
);
1096 ok(get1
!= get2
, "data objects match\n");
1098 OleSetClipboard(NULL
);
1100 hr
= OleGetClipboard(&get3
);
1101 ok(hr
== S_OK
, "got %08x\n", hr
);
1103 ok(get1
!= get3
, "data objects match\n");
1104 ok(get2
!= get3
, "data objects match\n");
1106 IDataObject_Release(get3
);
1107 IDataObject_Release(get2
);
1108 IDataObject_Release(get1
);
1110 /* Now call GetData before the flush and show that this
1111 takes a ref on our src data obj. */
1113 hr
= OleSetClipboard(src
);
1114 ok(hr
== S_OK
, "got %08x\n", hr
);
1116 old_refs
= count_refs(src
);
1118 hr
= OleGetClipboard(&get1
);
1119 ok(hr
== S_OK
, "got %08x\n", hr
);
1121 refs
= count_refs(src
);
1122 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
1124 DataObjectImpl_GetData_calls
= 0;
1125 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1126 ok(hr
== S_OK
, "got %08x\n", hr
);
1127 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1128 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1129 refs
= count_refs(src
);
1130 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
1132 OleFlushClipboard();
1134 DataObjectImpl_GetData_calls
= 0;
1135 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1136 ok(hr
== S_OK
, "got %08x\n", hr
);
1137 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1138 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1140 refs
= count_refs(src
);
1141 ok(refs
== 2, "%d\n", refs
);
1143 IDataObject_Release(get1
);
1145 refs
= count_refs(src
);
1146 ok(refs
== 1, "%d\n", refs
);
1148 /* Now set a second src object before the call to GetData
1149 and show that GetData calls that second src. */
1151 hr
= OleSetClipboard(src
);
1152 ok(hr
== S_OK
, "got %08x\n", hr
);
1154 old_refs
= count_refs(src
);
1156 hr
= OleGetClipboard(&get1
);
1157 ok(hr
== S_OK
, "got %08x\n", hr
);
1159 refs
= count_refs(src
);
1160 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
1162 hr
= OleSetClipboard(src2
);
1163 ok(hr
== S_OK
, "got %08x\n", hr
);
1165 old_refs
= count_refs(src2
);
1167 DataObjectImpl_GetData_calls
= 0;
1168 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1169 ok(hr
== S_OK
, "got %08x\n", hr
);
1170 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1171 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1173 refs
= count_refs(src
);
1174 ok(refs
== 1, "%d\n", refs
);
1175 refs
= count_refs(src2
);
1176 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
1178 OleSetClipboard(NULL
);
1180 refs
= count_refs(src2
);
1181 ok(refs
== 2, "%d\n", refs
);
1183 IDataObject_Release(get1
);
1185 IDataObject_Release(src2
);
1186 IDataObject_Release(src
);
1191 static void test_flushed_getdata(void)
1194 IDataObject
*src
, *get
;
1200 OleInitialize(NULL
);
1202 hr
= DataObjectImpl_CreateComplex(&src
);
1203 ok(hr
== S_OK
, "got %08x\n", hr
);
1205 hr
= OleSetClipboard(src
);
1206 ok(hr
== S_OK
, "got %08x\n", hr
);
1208 hr
= OleFlushClipboard();
1209 ok(hr
== S_OK
, "got %08x\n", hr
);
1211 hr
= OleGetClipboard(&get
);
1212 ok(hr
== S_OK
, "got %08x\n", hr
);
1214 /* global format -> global & stream */
1216 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1217 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1218 ok(hr
== S_OK
, "got %08x\n", hr
);
1219 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1220 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1222 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTREAM
);
1223 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1224 ok(hr
== S_OK
, "got %08x\n", hr
);
1225 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1226 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1228 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTORAGE
);
1229 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1230 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1231 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1233 InitFormatEtc(fmt
, CF_TEXT
, 0xffff);
1234 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1235 ok(hr
== S_OK
, "got %08x\n", hr
);
1236 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1237 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1239 /* stream format -> global & stream */
1241 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTREAM
);
1242 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1243 ok(hr
== S_OK
, "got %08x\n", hr
);
1244 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1245 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1247 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTORAGE
);
1248 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1249 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1250 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1252 InitFormatEtc(fmt
, cf_stream
, TYMED_HGLOBAL
);
1253 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1254 ok(hr
== S_OK
, "got %08x\n", hr
);
1255 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1256 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1258 InitFormatEtc(fmt
, cf_stream
, 0xffff);
1259 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1260 ok(hr
== S_OK
, "got %08x\n", hr
);
1261 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1262 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1264 /* storage format -> global, stream & storage */
1266 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTORAGE
);
1267 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1268 ok(hr
== S_OK
, "got %08x\n", hr
);
1269 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1271 hr
= IStorage_Stat(med
.u
.pstg
, &stat
, STATFLAG_NONAME
);
1272 ok(hr
== S_OK
, "got %08x\n", hr
);
1273 ok(stat
.grfMode
== (STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
), "got %08x\n", stat
.grfMode
);
1274 ReleaseStgMedium(&med
);
1277 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTREAM
);
1278 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1279 ok(hr
== S_OK
, "got %08x\n", hr
);
1280 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1281 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1283 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
);
1284 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1285 ok(hr
== S_OK
, "got %08x\n", hr
);
1286 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1287 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1289 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
| TYMED_ISTREAM
);
1290 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1291 ok(hr
== S_OK
, "got %08x\n", hr
);
1292 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1293 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1295 InitFormatEtc(fmt
, cf_storage
, 0xffff);
1296 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1297 ok(hr
== S_OK
, "got %08x\n", hr
);
1298 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1299 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1301 /* complex format with target device */
1303 InitFormatEtc(fmt
, cf_another
, 0xffff);
1304 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1305 ok(hr
== S_OK
, "got %08x\n", hr
);
1306 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1308 if (0) /* Causes crashes on both Wine and Windows */
1310 InitFormatEtc(fmt
, cf_another
, 0xffff);
1311 memset(&dm
, 0, sizeof(dm
));
1312 dm
.dmSize
= sizeof(dm
);
1313 dm
.dmDriverExtra
= 0;
1314 lstrcpyW(dm
.dmDeviceName
, device_name
);
1315 fmt
.ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
);
1316 fmt
.ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
;
1317 fmt
.ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
1318 fmt
.ptd
->tdDeviceNameOffset
= 0;
1319 fmt
.ptd
->tdPortNameOffset
= 0;
1320 fmt
.ptd
->tdExtDevmodeOffset
= fmt
.ptd
->tdDriverNameOffset
+ sizeof(device_name
);
1321 lstrcpyW((WCHAR
*)fmt
.ptd
->tdData
, device_name
);
1322 memcpy(fmt
.ptd
->tdData
+ sizeof(device_name
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
1324 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1325 ok(hr
== S_OK
, "got %08x\n", hr
);
1326 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1327 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1329 HeapFree(GetProcessHeap(), 0, fmt
.ptd
);
1333 IDataObject_Release(get
);
1334 IDataObject_Release(src
);
1338 static HGLOBAL
create_text(void)
1340 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 5);
1341 char *p
= GlobalLock(h
);
1347 static HENHMETAFILE
create_emf(void)
1349 const RECT rect
= {0, 0, 100, 100};
1350 HDC hdc
= CreateEnhMetaFileA(NULL
, NULL
, &rect
, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1351 ExtTextOutA(hdc
, 0, 0, ETO_OPAQUE
, &rect
, "Test String", strlen("Test String"), NULL
);
1352 return CloseEnhMetaFile(hdc
);
1355 static void test_nonole_clipboard(void)
1360 IEnumFORMATETC
*enum_fmt
;
1362 HGLOBAL h
, hblob
, htext
;
1367 r
= OpenClipboard(NULL
);
1368 ok(r
, "gle %d\n", GetLastError());
1369 r
= EmptyClipboard();
1370 ok(r
, "gle %d\n", GetLastError());
1371 r
= CloseClipboard();
1372 ok(r
, "gle %d\n", GetLastError());
1374 OleInitialize(NULL
);
1376 /* empty clipboard */
1377 hr
= OleGetClipboard(&get
);
1378 ok(hr
== S_OK
, "got %08x\n", hr
);
1379 hr
= IDataObject_EnumFormatEtc(get
, DATADIR_GET
, &enum_fmt
);
1380 ok(hr
== S_OK
, "got %08x\n", hr
);
1382 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1383 ok(hr
== S_FALSE
, "got %08x\n", hr
);
1384 IEnumFORMATETC_Release(enum_fmt
);
1386 IDataObject_Release(get
);
1388 /* set a user defined clipboard type */
1390 htext
= create_text();
1391 hblob
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
|GMEM_ZEROINIT
, 10);
1394 r
= OpenClipboard(NULL
);
1395 ok(r
, "gle %d\n", GetLastError());
1396 h
= SetClipboardData(CF_TEXT
, htext
);
1397 ok(h
== htext
, "got %p\n", h
);
1398 h
= SetClipboardData(cf_onemore
, hblob
);
1399 ok(h
== hblob
, "got %p\n", h
);
1400 h
= SetClipboardData(CF_ENHMETAFILE
, emf
);
1401 ok(h
== emf
, "got %p\n", h
);
1402 r
= CloseClipboard();
1403 ok(r
, "gle %d\n", GetLastError());
1405 hr
= OleGetClipboard(&get
);
1406 ok(hr
== S_OK
, "got %08x\n", hr
);
1407 hr
= IDataObject_EnumFormatEtc(get
, DATADIR_GET
, &enum_fmt
);
1408 ok(hr
== S_OK
, "got %08x\n", hr
);
1410 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1411 ok(hr
== S_OK
, "got %08x\n", hr
);
1412 ok(fmt
.cfFormat
== CF_TEXT
, "cf %04x\n", fmt
.cfFormat
);
1413 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1414 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1415 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1416 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1418 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1419 ok(hr
== S_OK
, "got %08x\n", hr
);
1420 ok(fmt
.cfFormat
== cf_onemore
, "cf %04x\n", fmt
.cfFormat
);
1421 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1422 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1423 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1424 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1426 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1427 ok(hr
== S_OK
, "got %08x\n", hr
);
1428 ok(fmt
.cfFormat
== CF_ENHMETAFILE
, "cf %04x\n", fmt
.cfFormat
);
1429 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1430 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1431 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1432 ok(fmt
.tymed
== TYMED_ENHMF
, "tymed %x\n", fmt
.tymed
);
1434 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1435 ok(hr
== S_OK
, "got %08x\n", hr
); /* User32 adds some synthesised formats */
1437 ok(fmt
.cfFormat
== CF_LOCALE
, "cf %04x\n", fmt
.cfFormat
);
1438 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1439 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1440 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1441 todo_wine
ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1443 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1444 ok(hr
== S_OK
, "got %08x\n", hr
);
1446 ok(fmt
.cfFormat
== CF_OEMTEXT
, "cf %04x\n", fmt
.cfFormat
);
1447 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1448 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1449 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1450 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1452 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1453 ok(hr
== S_OK
, "got %08x\n", hr
);
1454 ok(fmt
.cfFormat
== CF_UNICODETEXT
, "cf %04x\n", fmt
.cfFormat
);
1455 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1456 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1457 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1458 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1460 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1461 ok(hr
== S_OK
, "got %08x\n", hr
);
1462 ok(fmt
.cfFormat
== CF_METAFILEPICT
, "cf %04x\n", fmt
.cfFormat
);
1463 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1464 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1465 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1466 ok(fmt
.tymed
== TYMED_MFPICT
, "tymed %x\n", fmt
.tymed
);
1468 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1469 ok(hr
== S_FALSE
, "got %08x\n", hr
);
1470 IEnumFORMATETC_Release(enum_fmt
);
1472 InitFormatEtc(fmt
, CF_ENHMETAFILE
, TYMED_ENHMF
);
1473 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1474 ok(hr
== S_OK
, "got %08x\n", hr
);
1475 obj_type
= GetObjectType(U(med
).hEnhMetaFile
);
1476 ok(obj_type
== OBJ_ENHMETAFILE
, "got %d\n", obj_type
);
1477 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1479 IDataObject_Release(get
);
1481 r
= OpenClipboard(NULL
);
1482 ok(r
, "gle %d\n", GetLastError());
1483 r
= EmptyClipboard();
1484 ok(r
, "gle %d\n", GetLastError());
1485 r
= CloseClipboard();
1486 ok(r
, "gle %d\n", GetLastError());
1491 static void test_getdatahere(void)
1494 IDataObject
*src
, *get
;
1498 OleInitialize(NULL
);
1500 hr
= DataObjectImpl_CreateComplex(&src
);
1501 ok(hr
== S_OK
, "got %08x\n", hr
);
1503 hr
= OleSetClipboard(src
);
1504 ok(hr
== S_OK
, "got %08x\n", hr
);
1506 hr
= OleGetClipboard(&get
);
1507 ok(hr
== S_OK
, "got %08x\n", hr
);
1509 /* global format -> global & stream */
1511 DataObjectImpl_GetData_calls
= 0;
1512 DataObjectImpl_GetDataHere_calls
= 0;
1514 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1516 med
.pUnkForRelease
= NULL
;
1517 med
.tymed
= TYMED_HGLOBAL
;
1518 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1519 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1520 ok(hr
== S_OK
, "got %08x\n", hr
);
1521 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1522 ReleaseStgMedium(&med
);
1523 ok(DataObjectImpl_GetDataHere_calls
== 1, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1524 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1526 InitFormatEtc(fmt
, CF_TEXT
, 0);
1528 med
.pUnkForRelease
= NULL
;
1529 med
.tymed
= TYMED_HGLOBAL
;
1530 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1531 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1532 ok(hr
== S_OK
, "got %08x\n", hr
);
1533 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1534 ReleaseStgMedium(&med
);
1535 ok(DataObjectImpl_GetDataHere_calls
== 2, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1536 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1538 med
.pUnkForRelease
= NULL
;
1539 med
.tymed
= TYMED_HGLOBAL
;
1540 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 1);
1541 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1542 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1543 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1544 ReleaseStgMedium(&med
);
1545 ok(DataObjectImpl_GetDataHere_calls
== 3, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1546 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1548 med
.pUnkForRelease
= NULL
;
1549 med
.tymed
= TYMED_ISTREAM
;
1550 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1551 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1552 ok(hr
== S_OK
, "got %08x\n", hr
);
1553 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1554 ReleaseStgMedium(&med
);
1555 ok(DataObjectImpl_GetDataHere_calls
== 4, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1556 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1558 med
.pUnkForRelease
= NULL
;
1559 med
.tymed
= TYMED_ISTORAGE
;
1560 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1561 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1562 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1563 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1564 ReleaseStgMedium(&med
);
1565 ok(DataObjectImpl_GetDataHere_calls
== 5, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1566 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1568 InitFormatEtc(fmt
, cf_stream
, 0);
1570 med
.pUnkForRelease
= NULL
;
1571 med
.tymed
= TYMED_HGLOBAL
;
1572 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1573 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1574 ok(hr
== S_OK
, "got %08x\n", hr
);
1575 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1576 ReleaseStgMedium(&med
);
1577 ok(DataObjectImpl_GetDataHere_calls
== 7, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1578 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1580 med
.pUnkForRelease
= NULL
;
1581 med
.tymed
= TYMED_ISTREAM
;
1582 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1583 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1584 ok(hr
== S_OK
, "got %08x\n", hr
);
1585 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1586 ReleaseStgMedium(&med
);
1587 ok(DataObjectImpl_GetDataHere_calls
== 8, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1588 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1590 med
.pUnkForRelease
= NULL
;
1591 med
.tymed
= TYMED_ISTORAGE
;
1592 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1593 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1594 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1595 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1596 ReleaseStgMedium(&med
);
1597 ok(DataObjectImpl_GetDataHere_calls
== 9, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1598 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1600 InitFormatEtc(fmt
, cf_storage
, 0);
1602 med
.pUnkForRelease
= NULL
;
1603 med
.tymed
= TYMED_HGLOBAL
;
1604 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 3000);
1605 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1606 ok(hr
== S_OK
, "got %08x\n", hr
);
1607 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1608 ReleaseStgMedium(&med
);
1609 ok(DataObjectImpl_GetDataHere_calls
== 11, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1610 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1612 med
.pUnkForRelease
= NULL
;
1613 med
.tymed
= TYMED_ISTREAM
;
1614 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1615 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1616 ok(hr
== S_OK
, "got %08x\n", hr
);
1617 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1618 ReleaseStgMedium(&med
);
1619 ok(DataObjectImpl_GetDataHere_calls
== 12, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1620 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1622 med
.pUnkForRelease
= NULL
;
1623 med
.tymed
= TYMED_ISTORAGE
;
1624 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1625 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1626 ok(hr
== S_OK
, "got %08x\n", hr
);
1627 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1628 ReleaseStgMedium(&med
);
1629 ok(DataObjectImpl_GetDataHere_calls
== 13, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1630 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1633 IDataObject_Release(get
);
1634 IDataObject_Release(src
);
1640 static DWORD CALLBACK
test_data_obj(void *arg
)
1642 IDataObject
*data_obj
= arg
;
1644 IDataObject_Release(data_obj
);
1648 static void test_multithreaded_clipboard(void)
1650 IDataObject
*data_obj
;
1655 OleInitialize(NULL
);
1657 hr
= OleGetClipboard(&data_obj
);
1658 ok(hr
== S_OK
, "OleGetClipboard returned %x\n", hr
);
1660 thread
= CreateThread(NULL
, 0, test_data_obj
, data_obj
, 0, NULL
);
1661 ok(thread
!= NULL
, "CreateThread failed (%d)\n", GetLastError());
1662 ret
= WaitForSingleObject(thread
, 5000);
1663 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %x\n", ret
);
1665 hr
= OleGetClipboard(&data_obj
);
1666 ok(hr
== S_OK
, "OleGetClipboard returned %x\n", hr
);
1667 IDataObject_Release(data_obj
);
1672 static void test_get_clipboard_locked(void)
1677 OleInitialize(NULL
);
1679 pDObj
= (IDataObject
*)0xdeadbeef;
1680 /* lock clipboard */
1681 OpenClipboard(NULL
);
1682 hr
= OleGetClipboard(&pDObj
);
1683 todo_wine
ok(hr
== CLIPBRD_E_CANT_OPEN
, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr
, CLIPBRD_E_CANT_OPEN
);
1684 todo_wine
ok(pDObj
== NULL
, "OleGetClipboard() got 0x%p instead of NULL\n",pDObj
);
1685 if (pDObj
) IDataObject_Release(pDObj
);
1691 START_TEST(clipboard
)
1693 test_get_clipboard_uninitialized();
1694 test_set_clipboard();
1695 test_set_clipboard_DRAWCLIPBOARD();
1696 test_consumer_refs();
1697 test_flushed_getdata();
1698 test_nonole_clipboard();
1700 test_multithreaded_clipboard();
1701 test_get_clipboard_locked();