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
21 #define WIN32_NO_STATUS
23 #define COM_NO_WINDOWS_H
27 #define NONAMELESSUNION
36 //#include "objbase.h"
38 #include <wine/test.h>
40 #define InitFormatEtc(fe, cf, med) \
43 (fe).dwAspect=DVASPECT_CONTENT;\
49 static inline char *dump_fmtetc(FORMATETC
*fmt
)
53 snprintf(buf
, sizeof(buf
), "cf %04x ptd %p aspect %x lindex %d tymed %x",
54 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
58 typedef struct DataObjectImpl
{
59 IDataObject IDataObject_iface
;
70 typedef struct EnumFormatImpl
{
71 IEnumFORMATETC IEnumFORMATETC_iface
;
80 static BOOL expect_DataObjectImpl_QueryGetData
= TRUE
;
81 static ULONG DataObjectImpl_GetData_calls
= 0;
82 static ULONG DataObjectImpl_GetDataHere_calls
= 0;
83 static ULONG DataObjectImpl_EnumFormatEtc_calls
= 0;
85 static UINT cf_stream
, cf_storage
, cf_global
, cf_another
, cf_onemore
;
87 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT size
, LPENUMFORMATETC
*lplpformatetc
);
89 static inline DataObjectImpl
*impl_from_IDataObject(IDataObject
*iface
)
91 return CONTAINING_RECORD(iface
, DataObjectImpl
, IDataObject_iface
);
94 static inline EnumFormatImpl
*impl_from_IEnumFORMATETC(IEnumFORMATETC
*iface
)
96 return CONTAINING_RECORD(iface
, EnumFormatImpl
, IEnumFORMATETC_iface
);
99 static HRESULT WINAPI
EnumFormatImpl_QueryInterface(IEnumFORMATETC
*iface
, REFIID riid
, LPVOID
*ppvObj
)
101 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
103 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumFORMATETC
)) {
104 IEnumFORMATETC_AddRef(iface
);
105 *ppvObj
= &This
->IEnumFORMATETC_iface
;
109 return E_NOINTERFACE
;
112 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
114 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
115 LONG ref
= InterlockedIncrement(&This
->ref
);
119 static ULONG WINAPI
EnumFormatImpl_Release(IEnumFORMATETC
*iface
)
121 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
122 ULONG ref
= InterlockedDecrement(&This
->ref
);
125 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
126 HeapFree(GetProcessHeap(), 0, This
);
132 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
133 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
135 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
138 if (winetest_debug
> 1)
139 trace("next: count %d cur %d\n", celt
, This
->cur
);
144 count
= min(celt
, This
->fmtetc_cnt
- This
->cur
);
145 for(i
= 0; i
< count
; i
++, This
->cur
++, rgelt
++)
147 *rgelt
= This
->fmtetc
[This
->cur
];
150 DWORD size
= This
->fmtetc
[This
->cur
].ptd
->tdSize
;
151 rgelt
->ptd
= CoTaskMemAlloc(size
);
152 memcpy(rgelt
->ptd
, This
->fmtetc
[This
->cur
].ptd
, size
);
156 *pceltFetched
= count
;
157 return count
== celt
? S_OK
: S_FALSE
;
160 static HRESULT WINAPI
EnumFormatImpl_Skip(IEnumFORMATETC
*iface
, ULONG celt
)
162 ok(0, "unexpected call\n");
166 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
168 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
174 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
176 ok(0, "unexpected call\n");
180 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
181 EnumFormatImpl_QueryInterface
,
182 EnumFormatImpl_AddRef
,
183 EnumFormatImpl_Release
,
186 EnumFormatImpl_Reset
,
190 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
194 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl
));
195 ret
->IEnumFORMATETC_iface
.lpVtbl
= &VT_EnumFormatImpl
;
198 ret
->fmtetc_cnt
= fmtetc_cnt
;
199 ret
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt
*sizeof(FORMATETC
));
200 memcpy(ret
->fmtetc
, fmtetc
, fmtetc_cnt
*sizeof(FORMATETC
));
201 *lplpformatetc
= (LPENUMFORMATETC
)ret
;
205 static HRESULT WINAPI
DataObjectImpl_QueryInterface(IDataObject
*iface
, REFIID riid
, LPVOID
*ppvObj
)
207 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
209 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDataObject
)) {
210 IDataObject_AddRef(iface
);
211 *ppvObj
= &This
->IDataObject_iface
;
215 return E_NOINTERFACE
;
218 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
220 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
221 ULONG ref
= InterlockedIncrement(&This
->ref
);
225 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
227 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
228 ULONG ref
= InterlockedDecrement(&This
->ref
);
233 if(This
->text
) GlobalFree(This
->text
);
234 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
235 HeapFree(GetProcessHeap(), 0, This
->fmtetc
[i
].ptd
);
236 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
237 if(This
->stm
) IStream_Release(This
->stm
);
238 if(This
->stg
) IStorage_Release(This
->stg
);
239 HeapFree(GetProcessHeap(), 0, This
);
245 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
247 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
249 BOOL foundFormat
= FALSE
;
251 trace("getdata: %s\n", dump_fmtetc(pformatetc
));
253 DataObjectImpl_GetData_calls
++;
255 if(pformatetc
->lindex
!= -1)
256 return DV_E_FORMATETC
;
258 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
260 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
)
263 if(This
->fmtetc
[i
].tymed
& pformatetc
->tymed
)
265 pmedium
->pUnkForRelease
= (LPUNKNOWN
)iface
;
266 IUnknown_AddRef(pmedium
->pUnkForRelease
);
268 if(pformatetc
->cfFormat
== CF_TEXT
|| pformatetc
->cfFormat
== cf_global
)
270 pmedium
->tymed
= TYMED_HGLOBAL
;
271 U(*pmedium
).hGlobal
= This
->text
;
273 else if(pformatetc
->cfFormat
== cf_stream
)
275 pmedium
->tymed
= TYMED_ISTREAM
;
276 IStream_AddRef(This
->stm
);
277 U(*pmedium
).pstm
= This
->stm
;
279 else if(pformatetc
->cfFormat
== cf_storage
|| pformatetc
->cfFormat
== cf_another
)
281 pmedium
->tymed
= TYMED_ISTORAGE
;
282 IStorage_AddRef(This
->stg
);
283 U(*pmedium
).pstg
= This
->stg
;
290 return foundFormat
? DV_E_TYMED
: DV_E_FORMATETC
;
293 static HRESULT WINAPI
DataObjectImpl_GetDataHere(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
295 trace("getdatahere: %s\n", dump_fmtetc(pformatetc
));
296 DataObjectImpl_GetDataHere_calls
++;
301 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
303 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
305 BOOL foundFormat
= FALSE
;
307 trace("querygetdata: %s\n", dump_fmtetc(pformatetc
));
308 if (!expect_DataObjectImpl_QueryGetData
)
309 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
311 if(pformatetc
->lindex
!= -1)
314 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
315 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
317 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
321 return foundFormat
?DV_E_FORMATETC
:DV_E_TYMED
;
324 static HRESULT WINAPI
DataObjectImpl_GetCanonicalFormatEtc(IDataObject
* iface
, FORMATETC
*pformatectIn
,
325 FORMATETC
*pformatetcOut
)
327 ok(0, "unexpected call\n");
331 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
332 STGMEDIUM
*pmedium
, BOOL fRelease
)
334 ok(0, "unexpected call\n");
338 static HRESULT WINAPI
DataObjectImpl_EnumFormatEtc(IDataObject
* iface
, DWORD dwDirection
,
339 IEnumFORMATETC
**ppenumFormatEtc
)
341 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
343 DataObjectImpl_EnumFormatEtc_calls
++;
345 if(dwDirection
!= DATADIR_GET
) {
346 ok(0, "unexpected direction %d\n", dwDirection
);
349 return EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenumFormatEtc
);
352 static HRESULT WINAPI
DataObjectImpl_DAdvise(IDataObject
* iface
, FORMATETC
*pformatetc
, DWORD advf
,
353 IAdviseSink
*pAdvSink
, DWORD
*pdwConnection
)
355 ok(0, "unexpected call\n");
359 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
361 ok(0, "unexpected call\n");
365 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
367 ok(0, "unexpected call\n");
371 static const IDataObjectVtbl VT_DataObjectImpl
=
373 DataObjectImpl_QueryInterface
,
374 DataObjectImpl_AddRef
,
375 DataObjectImpl_Release
,
376 DataObjectImpl_GetData
,
377 DataObjectImpl_GetDataHere
,
378 DataObjectImpl_QueryGetData
,
379 DataObjectImpl_GetCanonicalFormatEtc
,
380 DataObjectImpl_SetData
,
381 DataObjectImpl_EnumFormatEtc
,
382 DataObjectImpl_DAdvise
,
383 DataObjectImpl_DUnadvise
,
384 DataObjectImpl_EnumDAdvise
387 static HRESULT
DataObjectImpl_CreateText(LPCSTR text
, LPDATAOBJECT
*lplpdataobj
)
391 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
392 obj
->IDataObject_iface
.lpVtbl
= &VT_DataObjectImpl
;
394 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(text
) + 1);
395 strcpy(GlobalLock(obj
->text
), text
);
396 GlobalUnlock(obj
->text
);
401 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
402 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
404 *lplpdataobj
= (LPDATAOBJECT
)obj
;
408 static const char *cmpl_stm_data
= "complex stream";
409 static const char *cmpl_text_data
= "complex text";
410 static const WCHAR device_name
[] = {'m','y','d','e','v',0};
412 static HRESULT
DataObjectImpl_CreateComplex(LPDATAOBJECT
*lplpdataobj
)
418 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
419 obj
->IDataObject_iface
.lpVtbl
= &VT_DataObjectImpl
;
421 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(cmpl_text_data
) + 1);
422 strcpy(GlobalLock(obj
->text
), cmpl_text_data
);
423 GlobalUnlock(obj
->text
);
424 CreateStreamOnHGlobal(NULL
, TRUE
, &obj
->stm
);
425 IStream_Write(obj
->stm
, cmpl_stm_data
, strlen(cmpl_stm_data
), NULL
);
427 CreateILockBytesOnHGlobal(NULL
, TRUE
, &lbs
);
428 StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &obj
->stg
);
429 ILockBytes_Release(lbs
);
432 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
433 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
434 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
435 InitFormatEtc(obj
->fmtetc
[1], cf_stream
, TYMED_ISTREAM
);
436 InitFormatEtc(obj
->fmtetc
[2], cf_storage
, TYMED_ISTORAGE
);
437 InitFormatEtc(obj
->fmtetc
[3], cf_another
, TYMED_ISTORAGE
|TYMED_ISTREAM
|TYMED_HGLOBAL
);
438 if (0) /* Causes crashes on both Wine and Windows */
440 memset(&dm
, 0, sizeof(dm
));
441 dm
.dmSize
= sizeof(dm
);
442 dm
.dmDriverExtra
= 0;
443 lstrcpyW(dm
.dmDeviceName
, device_name
);
444 obj
->fmtetc
[3].ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
);
445 obj
->fmtetc
[3].ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
;
446 obj
->fmtetc
[3].ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
447 obj
->fmtetc
[3].ptd
->tdDeviceNameOffset
= 0;
448 obj
->fmtetc
[3].ptd
->tdPortNameOffset
= 0;
449 obj
->fmtetc
[3].ptd
->tdExtDevmodeOffset
= obj
->fmtetc
[3].ptd
->tdDriverNameOffset
+ sizeof(device_name
);
450 lstrcpyW((WCHAR
*)obj
->fmtetc
[3].ptd
->tdData
, device_name
);
451 memcpy(obj
->fmtetc
[3].ptd
->tdData
+ sizeof(device_name
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
454 InitFormatEtc(obj
->fmtetc
[4], cf_global
, TYMED_HGLOBAL
);
455 InitFormatEtc(obj
->fmtetc
[5], cf_another
, TYMED_HGLOBAL
);
456 InitFormatEtc(obj
->fmtetc
[6], cf_another
, 0xfffff);
457 InitFormatEtc(obj
->fmtetc
[7], cf_another
, 0xfffff);
458 obj
->fmtetc
[7].dwAspect
= DVASPECT_ICON
;
460 *lplpdataobj
= (LPDATAOBJECT
)obj
;
464 static void test_get_clipboard_unitialized(void)
469 pDObj
= (IDataObject
*)0xdeadbeef;
470 hr
= OleGetClipboard(&pDObj
);
471 todo_wine
ok(hr
== S_OK
, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr
, S_OK
);
472 if (pDObj
&& pDObj
!= (IDataObject
*)0xdeadbeef) IDataObject_Release(pDObj
);
475 static void test_get_clipboard(void)
478 IDataObject
*data_obj
;
482 hr
= OleGetClipboard(NULL
);
483 ok(hr
== E_INVALIDARG
, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr
);
485 hr
= OleGetClipboard(&data_obj
);
486 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
488 /* test IDataObject_QueryGetData */
490 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
491 expect_DataObjectImpl_QueryGetData
= FALSE
;
493 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
494 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
495 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
497 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
498 fmtetc
.dwAspect
= 0xdeadbeef;
499 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
500 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
502 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
503 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
504 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
505 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
507 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
509 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
510 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
),
511 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
513 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
514 fmtetc
.cfFormat
= CF_RIFF
;
515 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
516 ok(hr
== DV_E_CLIPFORMAT
, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr
);
518 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
519 fmtetc
.tymed
= TYMED_FILE
;
520 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
521 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
523 expect_DataObjectImpl_QueryGetData
= TRUE
;
525 /* test IDataObject_GetData */
527 DataObjectImpl_GetData_calls
= 0;
529 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
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
= 0xdeadbeef;
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
);
541 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
542 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
543 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
544 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
546 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
548 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
549 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
552 /* undo the unexpected success */
553 DataObjectImpl_GetData_calls
--;
554 ReleaseStgMedium(&stgmedium
);
557 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
558 fmtetc
.cfFormat
= CF_RIFF
;
559 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
560 ok(hr
== DV_E_FORMATETC
, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
561 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
563 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
564 fmtetc
.tymed
= TYMED_FILE
;
565 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
566 ok(hr
== DV_E_TYMED
, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr
);
567 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
569 ok(DataObjectImpl_GetData_calls
== 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls
);
571 IDataObject_Release(data_obj
);
574 static void test_enum_fmtetc(IDataObject
*src
)
578 IEnumFORMATETC
*enum_fmt
, *src_enum
;
579 FORMATETC fmt
, src_fmt
;
582 hr
= OleGetClipboard(&data
);
583 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
585 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_SET
, &enum_fmt
);
586 ok(hr
== E_NOTIMPL
||
587 broken(hr
== E_INVALIDARG
), /* win98 (not win98SE) */
590 DataObjectImpl_EnumFormatEtc_calls
= 0;
591 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
592 ok(hr
== S_OK
, "got %08x\n", hr
);
593 ok(DataObjectImpl_EnumFormatEtc_calls
== 0, "EnumFormatEtc was called\n");
595 if(src
) IDataObject_EnumFormatEtc(src
, DATADIR_GET
, &src_enum
);
597 while((hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
)) == S_OK
)
599 ok(src
!= NULL
, "shouldn't be here\n");
600 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
601 ok(hr
== S_OK
, "%d: got %08x\n", count
, hr
);
602 trace("%d: %s\n", count
, dump_fmtetc(&fmt
));
603 ok(fmt
.cfFormat
== src_fmt
.cfFormat
, "%d: %04x %04x\n", count
, fmt
.cfFormat
, src_fmt
.cfFormat
);
604 ok(fmt
.dwAspect
== src_fmt
.dwAspect
, "%d: %08x %08x\n", count
, fmt
.dwAspect
, src_fmt
.dwAspect
);
605 ok(fmt
.lindex
== src_fmt
.lindex
, "%d: %08x %08x\n", count
, fmt
.lindex
, src_fmt
.lindex
);
606 ok(fmt
.tymed
== src_fmt
.tymed
, "%d: %08x %08x\n", count
, fmt
.tymed
, src_fmt
.tymed
);
609 ok(src_fmt
.ptd
!= NULL
, "%d: expected non-NULL\n", count
);
610 CoTaskMemFree(fmt
.ptd
);
611 CoTaskMemFree(src_fmt
.ptd
);
616 ok(hr
== S_FALSE
, "%d: got %08x\n", count
, hr
);
620 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
622 broken(hr
== S_OK
&& count
== 5), /* win9x and winme don't enumerate duplicated cf's */
623 "%d: got %08x\n", count
, hr
);
624 IEnumFORMATETC_Release(src_enum
);
627 hr
= IEnumFORMATETC_Reset(enum_fmt
);
628 ok(hr
== S_OK
, "got %08x\n", hr
);
630 if(src
) /* Exercise the enumerator a bit */
632 IEnumFORMATETC
*clone
;
635 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
636 ok(hr
== S_OK
, "got %08x\n", hr
);
637 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
638 ok(hr
== S_OK
, "got %08x\n", hr
);
639 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
640 ok(hr
== S_OK
, "got %08x\n", hr
);
642 hr
= IEnumFORMATETC_Reset(enum_fmt
);
643 ok(hr
== S_OK
, "got %08x\n", hr
);
644 hr
= IEnumFORMATETC_Skip(enum_fmt
, 2);
645 ok(hr
== S_OK
, "got %08x\n", hr
);
647 hr
= IEnumFORMATETC_Clone(enum_fmt
, &clone
);
648 ok(hr
== S_OK
, "got %08x\n", hr
);
649 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
650 ok(hr
== S_OK
, "got %08x\n", hr
);
651 ok(fmt
.cfFormat
== third_fmt
.cfFormat
, "formats don't match\n");
652 hr
= IEnumFORMATETC_Next(clone
, 1, &fmt
, NULL
);
653 ok(hr
== S_OK
, "got %08x\n", hr
);
654 ok(fmt
.cfFormat
== third_fmt
.cfFormat
, "formats don't match\n");
655 IEnumFORMATETC_Release(clone
);
658 IEnumFORMATETC_Release(enum_fmt
);
659 IDataObject_Release(data
);
662 static void test_no_cf_dataobject(void)
664 UINT cf_dataobject
= RegisterClipboardFormatA("DataObject");
665 UINT cf_ole_priv_data
= RegisterClipboardFormatA("Ole Private Data");
669 h
= GetClipboardData(cf_dataobject
);
670 ok(!h
, "got %p\n", h
);
671 h
= GetClipboardData(cf_ole_priv_data
);
672 ok(!h
, "got %p\n", h
);
677 static void test_cf_dataobject(IDataObject
*data
)
680 UINT cf_dataobject
= RegisterClipboardFormatA("DataObject");
681 UINT cf_ole_priv_data
= RegisterClipboardFormatA("Ole Private Data");
682 BOOL found_dataobject
= FALSE
, found_priv_data
= FALSE
;
687 cf
= EnumClipboardFormats(cf
);
688 if(cf
== cf_dataobject
)
690 HGLOBAL h
= GetClipboardData(cf
);
691 HWND
*ptr
= GlobalLock(h
);
692 DWORD size
= GlobalSize(h
);
693 HWND clip_owner
= GetClipboardOwner();
695 found_dataobject
= TRUE
;
696 ok(size
>= sizeof(*ptr
), "size %d\n", size
);
698 ok(*ptr
== clip_owner
, "hwnd %p clip_owner %p\n", *ptr
, clip_owner
);
699 else /* ole clipboard flushed */
700 ok(*ptr
== NULL
, "hwnd %p\n", *ptr
);
703 else if(cf
== cf_ole_priv_data
)
705 found_priv_data
= TRUE
;
708 HGLOBAL h
= GetClipboardData(cf
);
709 DWORD
*ptr
= GlobalLock(h
);
710 DWORD size
= GlobalSize(h
);
713 win_skip("Ole Private Data in win9x format\n");
717 IEnumFORMATETC
*enum_fmt
;
723 BOOL first_use_of_cf
;
733 struct formatetcetc fmts
[1];
734 } *priv
= (struct priv_data
*)ptr
;
735 CLIPFORMAT cfs_seen
[10];
737 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
738 ok(hr
== S_OK
, "got %08x\n", hr
);
739 fmt_ptr
= priv
->fmts
;
741 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
744 BOOL seen_cf
= FALSE
;
746 ok(fmt_ptr
->fmt
.cfFormat
== fmt
.cfFormat
,
747 "got %08x expected %08x\n", fmt_ptr
->fmt
.cfFormat
, fmt
.cfFormat
);
748 ok(fmt_ptr
->fmt
.dwAspect
== fmt
.dwAspect
, "got %08x expected %08x\n",
749 fmt_ptr
->fmt
.dwAspect
, fmt
.dwAspect
);
750 ok(fmt_ptr
->fmt
.lindex
== fmt
.lindex
, "got %08x expected %08x\n",
751 fmt_ptr
->fmt
.lindex
, fmt
.lindex
);
752 ok(fmt_ptr
->fmt
.tymed
== fmt
.tymed
, "got %08x expected %08x\n",
753 fmt_ptr
->fmt
.tymed
, fmt
.tymed
);
754 for(i
= 0; i
< count
; i
++)
755 if(fmt_ptr
->fmt
.cfFormat
== cfs_seen
[i
])
760 cfs_seen
[count
] = fmt
.cfFormat
;
761 ok(fmt_ptr
->first_use_of_cf
!= seen_cf
, "got %08x expected %08x\n",
762 fmt_ptr
->first_use_of_cf
, !seen_cf
);
763 ok(fmt_ptr
->res
[0] == 0, "got %08x\n", fmt_ptr
->res
[0]);
764 ok(fmt_ptr
->res
[1] == 0, "got %08x\n", fmt_ptr
->res
[1]);
767 DVTARGETDEVICE
*target
;
769 ok(fmt_ptr
->fmt
.ptd
!= NULL
, "target device offset zero\n");
770 target
= (DVTARGETDEVICE
*)((char*)priv
+ (DWORD_PTR
)fmt_ptr
->fmt
.ptd
);
771 ok(!memcmp(target
, fmt
.ptd
, fmt
.ptd
->tdSize
), "target devices differ\n");
772 CoTaskMemFree(fmt
.ptd
);
777 ok(priv
->res1
== 0, "got %08x\n", priv
->res1
);
778 ok(priv
->res2
== 1, "got %08x\n", priv
->res2
);
779 ok(priv
->count
== count
, "got %08x expected %08x\n", priv
->count
, count
);
780 ok(priv
->res3
[0] == 0, "got %08x\n", priv
->res3
[0]);
782 /* win64 sets the lsb */
783 if(sizeof(fmt_ptr
->fmt
.ptd
) == 8)
784 todo_wine
ok(priv
->res3
[1] == 1, "got %08x\n", priv
->res3
[1]);
786 ok(priv
->res3
[1] == 0, "got %08x\n", priv
->res3
[1]);
789 IEnumFORMATETC_Release(enum_fmt
);
793 else if(cf
== cf_stream
)
799 DataObjectImpl_GetDataHere_calls
= 0;
800 h
= GetClipboardData(cf
);
801 ok(DataObjectImpl_GetDataHere_calls
== 1, "got %d\n", DataObjectImpl_GetDataHere_calls
);
803 size
= GlobalSize(h
);
804 ok(size
== strlen(cmpl_stm_data
) ||
805 broken(size
> strlen(cmpl_stm_data
)), /* win9x, winme */
806 "expected %d got %d\n", lstrlenA(cmpl_stm_data
), size
);
807 ok(!memcmp(ptr
, cmpl_stm_data
, strlen(cmpl_stm_data
)), "mismatch\n");
810 else if(cf
== cf_global
)
816 DataObjectImpl_GetDataHere_calls
= 0;
817 h
= GetClipboardData(cf
);
818 ok(DataObjectImpl_GetDataHere_calls
== 0, "got %d\n", DataObjectImpl_GetDataHere_calls
);
820 size
= GlobalSize(h
);
821 ok(size
== strlen(cmpl_text_data
) + 1 ||
822 broken(size
> strlen(cmpl_text_data
) + 1), /* win9x, winme */
823 "expected %d got %d\n", lstrlenA(cmpl_text_data
) + 1, size
);
824 ok(!memcmp(ptr
, cmpl_text_data
, strlen(cmpl_text_data
) + 1), "mismatch\n");
829 ok(found_dataobject
, "didn't find cf_dataobject\n");
830 ok(found_priv_data
, "didn't find cf_ole_priv_data\n");
833 static void test_set_clipboard(void)
837 LPDATAOBJECT data1
, data2
, data_cmpl
;
840 cf_stream
= RegisterClipboardFormatA("stream format");
841 cf_storage
= RegisterClipboardFormatA("storage format");
842 cf_global
= RegisterClipboardFormatA("global format");
843 cf_another
= RegisterClipboardFormatA("another format");
844 cf_onemore
= RegisterClipboardFormatA("one more format");
846 hr
= DataObjectImpl_CreateText("data1", &data1
);
847 ok(hr
== S_OK
, "Failed to create data1 object: 0x%08x\n", hr
);
850 hr
= DataObjectImpl_CreateText("data2", &data2
);
851 ok(hr
== S_OK
, "Failed to create data2 object: 0x%08x\n", hr
);
854 hr
= DataObjectImpl_CreateComplex(&data_cmpl
);
855 ok(hr
== S_OK
, "Failed to create complex data object: 0x%08x\n", hr
);
859 hr
= OleSetClipboard(data1
);
860 ok(hr
== CO_E_NOTINITIALIZED
, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr
);
863 hr
= OleSetClipboard(data1
);
864 ok(hr
== CO_E_NOTINITIALIZED
||
865 hr
== CLIPBRD_E_CANT_SET
, /* win9x */
866 "OleSetClipboard should have failed with "
867 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr
);
870 hr
= OleInitialize(NULL
);
871 ok(hr
== S_OK
, "OleInitialize failed with error 0x%08x\n", hr
);
873 hr
= OleSetClipboard(data1
);
874 ok(hr
== S_OK
, "failed to set clipboard to data1, hr = 0x%08x\n", hr
);
876 test_cf_dataobject(data1
);
878 hr
= OleIsCurrentClipboard(data1
);
879 ok(hr
== S_OK
, "expected current clipboard to be data1, hr = 0x%08x\n", hr
);
880 hr
= OleIsCurrentClipboard(data2
);
881 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
882 hr
= OleIsCurrentClipboard(NULL
);
883 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
885 test_get_clipboard();
887 hr
= OleSetClipboard(data2
);
888 ok(hr
== S_OK
, "failed to set clipboard to data2, hr = 0x%08x\n", hr
);
889 hr
= OleIsCurrentClipboard(data1
);
890 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
891 hr
= OleIsCurrentClipboard(data2
);
892 ok(hr
== S_OK
, "expected current clipboard to be data2, hr = 0x%08x\n", hr
);
893 hr
= OleIsCurrentClipboard(NULL
);
894 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
896 /* put a format directly onto the clipboard to show
897 OleFlushClipboard doesn't empty the clipboard */
898 hblob
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
|GMEM_ZEROINIT
, 10);
900 h
= SetClipboardData(cf_onemore
, hblob
);
901 ok(h
== hblob
, "got %p\n", h
);
902 h
= GetClipboardData(cf_onemore
);
904 broken(h
!= NULL
), /* win9x */
908 hr
= OleFlushClipboard();
909 ok(hr
== S_OK
, "failed to flush clipboard, hr = 0x%08x\n", hr
);
910 hr
= OleIsCurrentClipboard(data1
);
911 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
912 hr
= OleIsCurrentClipboard(data2
);
913 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
914 hr
= OleIsCurrentClipboard(NULL
);
915 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
917 /* format should survive the flush */
919 h
= GetClipboardData(cf_onemore
);
921 broken(h
!= NULL
), /* win9x */
925 test_cf_dataobject(NULL
);
927 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
930 h
= GetClipboardData(cf_onemore
);
931 ok(h
== NULL
, "got %p\n", h
);
934 trace("setting complex\n");
935 hr
= OleSetClipboard(data_cmpl
);
936 ok(hr
== S_OK
, "failed to set clipboard to complex data, hr = 0x%08x\n", hr
);
937 test_cf_dataobject(data_cmpl
);
938 test_enum_fmtetc(data_cmpl
);
940 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
942 test_no_cf_dataobject();
943 test_enum_fmtetc(NULL
);
945 ref
= IDataObject_Release(data1
);
946 ok(ref
== 0, "expected data1 ref=0, got %d\n", ref
);
947 ref
= IDataObject_Release(data2
);
948 ok(ref
== 0, "expected data2 ref=0, got %d\n", ref
);
949 ref
= IDataObject_Release(data_cmpl
);
950 ok(ref
== 0, "expected data_cmpl ref=0, got %d\n", ref
);
955 static inline ULONG
count_refs(IDataObject
*d
)
957 IDataObject_AddRef(d
);
958 return IDataObject_Release(d
);
961 static void test_consumer_refs(void)
964 IDataObject
*src
, *src2
, *get1
, *get2
, *get3
;
965 ULONG refs
, old_refs
;
969 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
973 /* First show that each clipboard state results in
974 a different data object */
976 hr
= DataObjectImpl_CreateText("data1", &src
);
977 ok(hr
== S_OK
, "got %08x\n", hr
);
978 hr
= DataObjectImpl_CreateText("data2", &src2
);
979 ok(hr
== S_OK
, "got %08x\n", hr
);
981 hr
= OleSetClipboard(src
);
982 ok(hr
== S_OK
, "got %08x\n", hr
);
984 hr
= OleGetClipboard(&get1
);
985 ok(hr
== S_OK
, "got %08x\n", hr
);
987 hr
= OleGetClipboard(&get2
);
988 ok(hr
== S_OK
, "got %08x\n", hr
);
991 broken(get1
!= get2
), /* win9x, winme & nt4 */
992 "data objects differ\n");
993 refs
= IDataObject_Release(get2
);
994 ok(refs
== (get1
== get2
? 1 : 0), "got %d\n", refs
);
998 DataObjectImpl_GetData_calls
= 0;
999 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1000 ok(hr
== S_OK
, "got %08x\n", hr
);
1001 ok(DataObjectImpl_GetData_calls
== 0, "GetData called\n");
1002 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1004 hr
= OleGetClipboard(&get2
);
1005 ok(hr
== S_OK
, "got %08x\n", hr
);
1007 ok(get1
!= get2
, "data objects match\n");
1009 OleSetClipboard(NULL
);
1011 hr
= OleGetClipboard(&get3
);
1012 ok(hr
== S_OK
, "got %08x\n", hr
);
1014 ok(get1
!= get3
, "data objects match\n");
1015 ok(get2
!= get3
, "data objects match\n");
1017 IDataObject_Release(get3
);
1018 IDataObject_Release(get2
);
1019 IDataObject_Release(get1
);
1021 /* Now call GetData before the flush and show that this
1022 takes a ref on our src data obj. */
1024 hr
= OleSetClipboard(src
);
1025 ok(hr
== S_OK
, "got %08x\n", hr
);
1027 old_refs
= count_refs(src
);
1029 hr
= OleGetClipboard(&get1
);
1030 ok(hr
== S_OK
, "got %08x\n", hr
);
1032 refs
= count_refs(src
);
1033 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
1035 DataObjectImpl_GetData_calls
= 0;
1036 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1037 ok(hr
== S_OK
, "got %08x\n", hr
);
1038 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1039 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1040 refs
= count_refs(src
);
1041 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
1043 OleFlushClipboard();
1045 DataObjectImpl_GetData_calls
= 0;
1046 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1047 ok(hr
== S_OK
, "got %08x\n", hr
);
1048 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1049 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1051 refs
= count_refs(src
);
1052 ok(refs
== 2, "%d\n", refs
);
1054 IDataObject_Release(get1
);
1056 refs
= count_refs(src
);
1057 ok(refs
== 1, "%d\n", refs
);
1059 /* Now set a second src object before the call to GetData
1060 and show that GetData calls that second src. */
1062 hr
= OleSetClipboard(src
);
1063 ok(hr
== S_OK
, "got %08x\n", hr
);
1065 old_refs
= count_refs(src
);
1067 hr
= OleGetClipboard(&get1
);
1068 ok(hr
== S_OK
, "got %08x\n", hr
);
1070 refs
= count_refs(src
);
1071 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
1073 hr
= OleSetClipboard(src2
);
1074 ok(hr
== S_OK
, "got %08x\n", hr
);
1076 old_refs
= count_refs(src2
);
1078 DataObjectImpl_GetData_calls
= 0;
1079 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1080 ok(hr
== S_OK
, "got %08x\n", hr
);
1081 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1082 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1084 refs
= count_refs(src
);
1085 ok(refs
== 1, "%d\n", refs
);
1086 refs
= count_refs(src2
);
1087 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
1089 OleSetClipboard(NULL
);
1091 refs
= count_refs(src2
);
1092 ok(refs
== 2, "%d\n", refs
);
1094 IDataObject_Release(get1
);
1096 IDataObject_Release(src2
);
1097 IDataObject_Release(src
);
1102 static void test_flushed_getdata(void)
1105 IDataObject
*src
, *get
;
1111 OleInitialize(NULL
);
1113 hr
= DataObjectImpl_CreateComplex(&src
);
1114 ok(hr
== S_OK
, "got %08x\n", hr
);
1116 hr
= OleSetClipboard(src
);
1117 ok(hr
== S_OK
, "got %08x\n", hr
);
1119 hr
= OleFlushClipboard();
1120 ok(hr
== S_OK
, "got %08x\n", hr
);
1122 hr
= OleGetClipboard(&get
);
1123 ok(hr
== S_OK
, "got %08x\n", hr
);
1125 /* global format -> global & stream */
1127 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1128 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1129 ok(hr
== S_OK
, "got %08x\n", hr
);
1130 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1131 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1133 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTREAM
);
1134 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1135 ok(hr
== S_OK
, "got %08x\n", hr
);
1136 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1137 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1139 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTORAGE
);
1140 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1141 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1142 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1144 InitFormatEtc(fmt
, CF_TEXT
, 0xffff);
1145 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1146 ok(hr
== S_OK
, "got %08x\n", hr
);
1147 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1148 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1150 /* stream format -> global & stream */
1152 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTREAM
);
1153 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1154 ok(hr
== S_OK
, "got %08x\n", hr
);
1155 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1156 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1158 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTORAGE
);
1159 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1160 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1161 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1163 InitFormatEtc(fmt
, cf_stream
, TYMED_HGLOBAL
);
1164 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1165 ok(hr
== S_OK
, "got %08x\n", hr
);
1166 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1167 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1169 InitFormatEtc(fmt
, cf_stream
, 0xffff);
1170 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1171 ok(hr
== S_OK
, "got %08x\n", hr
);
1172 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1173 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1175 /* storage format -> global, stream & storage */
1177 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTORAGE
);
1178 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1179 ok(hr
== S_OK
, "got %08x\n", hr
);
1180 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1182 hr
= IStorage_Stat(med
.u
.pstg
, &stat
, STATFLAG_NONAME
);
1183 ok(hr
== S_OK
, "got %08x\n", hr
);
1184 ok(stat
.grfMode
== (STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
), "got %08x\n", stat
.grfMode
);
1185 ReleaseStgMedium(&med
);
1188 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTREAM
);
1189 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1190 ok(hr
== S_OK
, "got %08x\n", hr
);
1191 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1192 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1194 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
);
1195 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1196 ok(hr
== S_OK
, "got %08x\n", hr
);
1197 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1198 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1200 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
| TYMED_ISTREAM
);
1201 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1202 ok(hr
== S_OK
, "got %08x\n", hr
);
1203 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1204 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1206 InitFormatEtc(fmt
, cf_storage
, 0xffff);
1207 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1208 ok(hr
== S_OK
, "got %08x\n", hr
);
1209 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1210 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1212 /* complex format with target device */
1214 InitFormatEtc(fmt
, cf_another
, 0xffff);
1215 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1216 ok(hr
== S_OK
, "got %08x\n", hr
);
1217 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1219 if (0) /* Causes crashes on both Wine and Windows */
1221 InitFormatEtc(fmt
, cf_another
, 0xffff);
1222 memset(&dm
, 0, sizeof(dm
));
1223 dm
.dmSize
= sizeof(dm
);
1224 dm
.dmDriverExtra
= 0;
1225 lstrcpyW(dm
.dmDeviceName
, device_name
);
1226 fmt
.ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
);
1227 fmt
.ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
;
1228 fmt
.ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
1229 fmt
.ptd
->tdDeviceNameOffset
= 0;
1230 fmt
.ptd
->tdPortNameOffset
= 0;
1231 fmt
.ptd
->tdExtDevmodeOffset
= fmt
.ptd
->tdDriverNameOffset
+ sizeof(device_name
);
1232 lstrcpyW((WCHAR
*)fmt
.ptd
->tdData
, device_name
);
1233 memcpy(fmt
.ptd
->tdData
+ sizeof(device_name
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
1235 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1236 ok(hr
== S_OK
, "got %08x\n", hr
);
1237 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1238 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1240 HeapFree(GetProcessHeap(), 0, fmt
.ptd
);
1244 IDataObject_Release(get
);
1245 IDataObject_Release(src
);
1249 static HGLOBAL
create_text(void)
1251 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 5);
1252 char *p
= GlobalLock(h
);
1258 static HENHMETAFILE
create_emf(void)
1260 const RECT rect
= {0, 0, 100, 100};
1261 HDC hdc
= CreateEnhMetaFileA(NULL
, NULL
, &rect
, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1262 ExtTextOutA(hdc
, 0, 0, ETO_OPAQUE
, &rect
, "Test String", strlen("Test String"), NULL
);
1263 return CloseEnhMetaFile(hdc
);
1266 static void test_nonole_clipboard(void)
1271 IEnumFORMATETC
*enum_fmt
;
1273 HGLOBAL h
, hblob
, htext
;
1278 r
= OpenClipboard(NULL
);
1279 ok(r
, "gle %d\n", GetLastError());
1280 r
= EmptyClipboard();
1281 ok(r
, "gle %d\n", GetLastError());
1282 r
= CloseClipboard();
1283 ok(r
, "gle %d\n", GetLastError());
1285 OleInitialize(NULL
);
1287 /* empty clipboard */
1288 hr
= OleGetClipboard(&get
);
1289 ok(hr
== S_OK
, "got %08x\n", hr
);
1290 hr
= IDataObject_EnumFormatEtc(get
, DATADIR_GET
, &enum_fmt
);
1291 ok(hr
== S_OK
, "got %08x\n", hr
);
1293 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1294 ok(hr
== S_FALSE
, "got %08x\n", hr
);
1295 IEnumFORMATETC_Release(enum_fmt
);
1297 IDataObject_Release(get
);
1299 /* set a user defined clipboard type */
1301 htext
= create_text();
1302 hblob
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
|GMEM_ZEROINIT
, 10);
1305 r
= OpenClipboard(NULL
);
1306 ok(r
, "gle %d\n", GetLastError());
1307 h
= SetClipboardData(CF_TEXT
, htext
);
1308 ok(h
== htext
, "got %p\n", h
);
1309 h
= SetClipboardData(cf_onemore
, hblob
);
1310 ok(h
== hblob
, "got %p\n", h
);
1311 h
= SetClipboardData(CF_ENHMETAFILE
, emf
);
1312 ok(h
== emf
, "got %p\n", h
);
1313 r
= CloseClipboard();
1314 ok(r
, "gle %d\n", GetLastError());
1316 hr
= OleGetClipboard(&get
);
1317 ok(hr
== S_OK
, "got %08x\n", hr
);
1318 hr
= IDataObject_EnumFormatEtc(get
, DATADIR_GET
, &enum_fmt
);
1319 ok(hr
== S_OK
, "got %08x\n", hr
);
1321 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1322 ok(hr
== S_OK
, "got %08x\n", hr
);
1323 ok(fmt
.cfFormat
== CF_TEXT
, "cf %04x\n", fmt
.cfFormat
);
1324 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1325 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1326 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1327 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1329 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1330 ok(hr
== S_OK
, "got %08x\n", hr
);
1331 ok(fmt
.cfFormat
== cf_onemore
, "cf %04x\n", fmt
.cfFormat
);
1332 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1333 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1334 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1335 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1337 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1338 ok(hr
== S_OK
, "got %08x\n", hr
);
1339 ok(fmt
.cfFormat
== CF_ENHMETAFILE
, "cf %04x\n", fmt
.cfFormat
);
1340 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1341 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1342 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1343 ok(fmt
.tymed
== TYMED_ENHMF
, "tymed %x\n", fmt
.tymed
);
1345 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1346 ok(hr
== S_OK
, "got %08x\n", hr
); /* User32 adds some synthesised formats */
1348 todo_wine
ok(fmt
.cfFormat
== CF_LOCALE
, "cf %04x\n", fmt
.cfFormat
);
1349 if(fmt
.cfFormat
== CF_LOCALE
)
1351 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1352 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1353 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1354 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1356 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1357 ok(hr
== S_OK
, "got %08x\n", hr
);
1360 ok(fmt
.cfFormat
== CF_OEMTEXT
, "cf %04x\n", fmt
.cfFormat
);
1361 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1362 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1363 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1364 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1366 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1367 ok(hr
== S_OK
, "got %08x\n", hr
);
1368 ok(fmt
.cfFormat
== CF_UNICODETEXT
||
1369 broken(fmt
.cfFormat
== CF_METAFILEPICT
), /* win9x and winme don't have CF_UNICODETEXT */
1370 "cf %04x\n", fmt
.cfFormat
);
1371 if(fmt
.cfFormat
== CF_UNICODETEXT
)
1373 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1374 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1375 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1376 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1378 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1379 ok(hr
== S_OK
, "got %08x\n", hr
);
1381 ok(fmt
.cfFormat
== CF_METAFILEPICT
, "cf %04x\n", fmt
.cfFormat
);
1382 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1383 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1384 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1385 ok(fmt
.tymed
== TYMED_MFPICT
, "tymed %x\n", fmt
.tymed
);
1387 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1388 ok(hr
== S_FALSE
, "got %08x\n", hr
);
1389 IEnumFORMATETC_Release(enum_fmt
);
1391 InitFormatEtc(fmt
, CF_ENHMETAFILE
, TYMED_ENHMF
);
1392 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1393 ok(hr
== S_OK
, "got %08x\n", hr
);
1394 obj_type
= GetObjectType(U(med
).hEnhMetaFile
);
1395 ok(obj_type
== OBJ_ENHMETAFILE
, "got %d\n", obj_type
);
1396 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1398 IDataObject_Release(get
);
1400 r
= OpenClipboard(NULL
);
1401 ok(r
, "gle %d\n", GetLastError());
1402 r
= EmptyClipboard();
1403 ok(r
, "gle %d\n", GetLastError());
1404 r
= CloseClipboard();
1405 ok(r
, "gle %d\n", GetLastError());
1410 static void test_getdatahere(void)
1413 IDataObject
*src
, *get
;
1417 OleInitialize(NULL
);
1419 hr
= DataObjectImpl_CreateComplex(&src
);
1420 ok(hr
== S_OK
, "got %08x\n", hr
);
1422 hr
= OleSetClipboard(src
);
1423 ok(hr
== S_OK
, "got %08x\n", hr
);
1425 hr
= OleGetClipboard(&get
);
1426 ok(hr
== S_OK
, "got %08x\n", hr
);
1428 /* global format -> global & stream */
1430 DataObjectImpl_GetData_calls
= 0;
1431 DataObjectImpl_GetDataHere_calls
= 0;
1433 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1435 med
.pUnkForRelease
= NULL
;
1436 med
.tymed
= TYMED_HGLOBAL
;
1437 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1438 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1439 ok(hr
== S_OK
, "got %08x\n", hr
);
1440 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1441 ReleaseStgMedium(&med
);
1442 ok(DataObjectImpl_GetDataHere_calls
== 1, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1443 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1445 InitFormatEtc(fmt
, CF_TEXT
, 0);
1447 med
.pUnkForRelease
= NULL
;
1448 med
.tymed
= TYMED_HGLOBAL
;
1449 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1450 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1451 ok(hr
== S_OK
, "got %08x\n", hr
);
1452 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1453 ReleaseStgMedium(&med
);
1454 ok(DataObjectImpl_GetDataHere_calls
== 2, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1455 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1457 med
.pUnkForRelease
= NULL
;
1458 med
.tymed
= TYMED_HGLOBAL
;
1459 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 1);
1460 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1461 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1462 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1463 ReleaseStgMedium(&med
);
1464 ok(DataObjectImpl_GetDataHere_calls
== 3, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1465 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1467 med
.pUnkForRelease
= NULL
;
1468 med
.tymed
= TYMED_ISTREAM
;
1469 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1470 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1471 ok(hr
== S_OK
, "got %08x\n", hr
);
1472 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1473 ReleaseStgMedium(&med
);
1474 ok(DataObjectImpl_GetDataHere_calls
== 4, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1475 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1477 med
.pUnkForRelease
= NULL
;
1478 med
.tymed
= TYMED_ISTORAGE
;
1479 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1480 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1481 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1482 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1483 ReleaseStgMedium(&med
);
1484 ok(DataObjectImpl_GetDataHere_calls
== 5, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1485 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1487 InitFormatEtc(fmt
, cf_stream
, 0);
1489 med
.pUnkForRelease
= NULL
;
1490 med
.tymed
= TYMED_HGLOBAL
;
1491 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1492 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1493 ok(hr
== S_OK
, "got %08x\n", hr
);
1494 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1495 ReleaseStgMedium(&med
);
1496 ok(DataObjectImpl_GetDataHere_calls
== 7, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1497 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1499 med
.pUnkForRelease
= NULL
;
1500 med
.tymed
= TYMED_ISTREAM
;
1501 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1502 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1503 ok(hr
== S_OK
, "got %08x\n", hr
);
1504 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1505 ReleaseStgMedium(&med
);
1506 ok(DataObjectImpl_GetDataHere_calls
== 8, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1507 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1509 med
.pUnkForRelease
= NULL
;
1510 med
.tymed
= TYMED_ISTORAGE
;
1511 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1512 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1513 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1514 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1515 ReleaseStgMedium(&med
);
1516 ok(DataObjectImpl_GetDataHere_calls
== 9, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1517 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1519 InitFormatEtc(fmt
, cf_storage
, 0);
1521 med
.pUnkForRelease
= NULL
;
1522 med
.tymed
= TYMED_HGLOBAL
;
1523 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 3000);
1524 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1525 ok(hr
== S_OK
, "got %08x\n", hr
);
1526 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1527 ReleaseStgMedium(&med
);
1528 ok(DataObjectImpl_GetDataHere_calls
== 11, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1529 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1531 med
.pUnkForRelease
= NULL
;
1532 med
.tymed
= TYMED_ISTREAM
;
1533 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1534 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1535 ok(hr
== S_OK
, "got %08x\n", hr
);
1536 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1537 ReleaseStgMedium(&med
);
1538 ok(DataObjectImpl_GetDataHere_calls
== 12, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1539 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1541 med
.pUnkForRelease
= NULL
;
1542 med
.tymed
= TYMED_ISTORAGE
;
1543 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1544 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1545 ok(hr
== S_OK
, "got %08x\n", hr
);
1546 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1547 ReleaseStgMedium(&med
);
1548 ok(DataObjectImpl_GetDataHere_calls
== 13, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1549 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1552 IDataObject_Release(get
);
1553 IDataObject_Release(src
);
1559 static DWORD CALLBACK
test_data_obj(void *arg
)
1561 IDataObject
*data_obj
= arg
;
1563 IDataObject_Release(data_obj
);
1567 static void test_multithreaded_clipboard(void)
1569 IDataObject
*data_obj
;
1574 OleInitialize(NULL
);
1576 hr
= OleGetClipboard(&data_obj
);
1577 ok(hr
== S_OK
, "OleGetClipboard returned %x\n", hr
);
1579 thread
= CreateThread(NULL
, 0, test_data_obj
, data_obj
, 0, NULL
);
1580 ok(thread
!= NULL
, "CreateThread failed (%d)\n", GetLastError());
1581 ret
= WaitForSingleObject(thread
, 5000);
1582 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %x\n", ret
);
1584 hr
= OleGetClipboard(&data_obj
);
1585 ok(hr
== S_OK
, "OleGetClipboard returned %x\n", hr
);
1586 IDataObject_Release(data_obj
);
1591 static void test_get_clipboard_locked(void)
1596 OleInitialize(NULL
);
1598 pDObj
= (IDataObject
*)0xdeadbeef;
1599 /* lock clipboard */
1600 OpenClipboard(NULL
);
1601 hr
= OleGetClipboard(&pDObj
);
1602 todo_wine
ok(hr
== CLIPBRD_E_CANT_OPEN
, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr
, CLIPBRD_E_CANT_OPEN
);
1603 todo_wine
ok(pDObj
== NULL
, "OleGetClipboard() got 0x%p instead of NULL\n",pDObj
);
1604 if (pDObj
) IDataObject_Release(pDObj
);
1610 START_TEST(clipboard
)
1612 test_get_clipboard_unitialized();
1613 test_set_clipboard();
1614 test_consumer_refs();
1615 test_flushed_getdata();
1616 test_nonole_clipboard();
1618 test_multithreaded_clipboard();
1619 test_get_clipboard_locked();