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
);
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 trace("next: count %d cur %d\n", celt
, This
->cur
);
137 count
= min(celt
, This
->fmtetc_cnt
- This
->cur
);
138 for(i
= 0; i
< count
; i
++, This
->cur
++, rgelt
++)
140 *rgelt
= This
->fmtetc
[This
->cur
];
143 DWORD size
= This
->fmtetc
[This
->cur
].ptd
->tdSize
;
144 rgelt
->ptd
= CoTaskMemAlloc(size
);
145 memcpy(rgelt
->ptd
, This
->fmtetc
[This
->cur
].ptd
, size
);
149 *pceltFetched
= count
;
150 return count
== celt
? S_OK
: S_FALSE
;
153 static HRESULT WINAPI
EnumFormatImpl_Skip(IEnumFORMATETC
*iface
, ULONG celt
)
155 ok(0, "unexpected call\n");
159 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
161 EnumFormatImpl
*This
= impl_from_IEnumFORMATETC(iface
);
167 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
169 ok(0, "unexpected call\n");
173 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
174 EnumFormatImpl_QueryInterface
,
175 EnumFormatImpl_AddRef
,
176 EnumFormatImpl_Release
,
179 EnumFormatImpl_Reset
,
183 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
187 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl
));
188 ret
->IEnumFORMATETC_iface
.lpVtbl
= &VT_EnumFormatImpl
;
191 ret
->fmtetc_cnt
= fmtetc_cnt
;
192 ret
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt
*sizeof(FORMATETC
));
193 memcpy(ret
->fmtetc
, fmtetc
, fmtetc_cnt
*sizeof(FORMATETC
));
194 *lplpformatetc
= (LPENUMFORMATETC
)ret
;
198 static HRESULT WINAPI
DataObjectImpl_QueryInterface(IDataObject
*iface
, REFIID riid
, LPVOID
*ppvObj
)
200 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
202 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDataObject
)) {
203 IDataObject_AddRef(iface
);
208 return E_NOINTERFACE
;
211 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
213 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
214 ULONG ref
= InterlockedIncrement(&This
->ref
);
218 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
220 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
221 ULONG ref
= InterlockedDecrement(&This
->ref
);
226 if(This
->text
) GlobalFree(This
->text
);
227 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
228 HeapFree(GetProcessHeap(), 0, This
->fmtetc
[i
].ptd
);
229 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
230 if(This
->stm
) IStream_Release(This
->stm
);
231 if(This
->stg
) IStorage_Release(This
->stg
);
232 HeapFree(GetProcessHeap(), 0, This
);
238 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
240 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
242 BOOL foundFormat
= FALSE
;
244 trace("getdata: %s\n", dump_fmtetc(pformatetc
));
246 DataObjectImpl_GetData_calls
++;
248 if(pformatetc
->lindex
!= -1)
249 return DV_E_FORMATETC
;
251 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
253 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
)
256 if(This
->fmtetc
[i
].tymed
& pformatetc
->tymed
)
258 pmedium
->pUnkForRelease
= (LPUNKNOWN
)iface
;
259 IUnknown_AddRef(pmedium
->pUnkForRelease
);
261 if(pformatetc
->cfFormat
== CF_TEXT
|| pformatetc
->cfFormat
== cf_global
)
263 pmedium
->tymed
= TYMED_HGLOBAL
;
264 U(*pmedium
).hGlobal
= This
->text
;
266 else if(pformatetc
->cfFormat
== cf_stream
)
268 pmedium
->tymed
= TYMED_ISTREAM
;
269 IStream_AddRef(This
->stm
);
270 U(*pmedium
).pstm
= This
->stm
;
272 else if(pformatetc
->cfFormat
== cf_storage
|| pformatetc
->cfFormat
== cf_another
)
274 pmedium
->tymed
= TYMED_ISTORAGE
;
275 IStorage_AddRef(This
->stg
);
276 U(*pmedium
).pstg
= This
->stg
;
283 return foundFormat
? DV_E_TYMED
: DV_E_FORMATETC
;
286 static HRESULT WINAPI
DataObjectImpl_GetDataHere(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
288 trace("getdatahere: %s\n", dump_fmtetc(pformatetc
));
289 DataObjectImpl_GetDataHere_calls
++;
294 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
296 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
298 BOOL foundFormat
= FALSE
;
300 trace("querygetdata: %s\n", dump_fmtetc(pformatetc
));
301 if (!expect_DataObjectImpl_QueryGetData
)
302 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
304 if(pformatetc
->lindex
!= -1)
307 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
308 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
310 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
314 return foundFormat
?DV_E_FORMATETC
:DV_E_TYMED
;
317 static HRESULT WINAPI
DataObjectImpl_GetCanonicalFormatEtc(IDataObject
* iface
, FORMATETC
*pformatectIn
,
318 FORMATETC
*pformatetcOut
)
320 ok(0, "unexpected call\n");
324 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
325 STGMEDIUM
*pmedium
, BOOL fRelease
)
327 ok(0, "unexpected call\n");
331 static HRESULT WINAPI
DataObjectImpl_EnumFormatEtc(IDataObject
* iface
, DWORD dwDirection
,
332 IEnumFORMATETC
**ppenumFormatEtc
)
334 DataObjectImpl
*This
= impl_from_IDataObject(iface
);
336 DataObjectImpl_EnumFormatEtc_calls
++;
338 if(dwDirection
!= DATADIR_GET
) {
339 ok(0, "unexpected direction %d\n", dwDirection
);
342 return EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenumFormatEtc
);
345 static HRESULT WINAPI
DataObjectImpl_DAdvise(IDataObject
* iface
, FORMATETC
*pformatetc
, DWORD advf
,
346 IAdviseSink
*pAdvSink
, DWORD
*pdwConnection
)
348 ok(0, "unexpected call\n");
352 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
354 ok(0, "unexpected call\n");
358 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
360 ok(0, "unexpected call\n");
364 static const IDataObjectVtbl VT_DataObjectImpl
=
366 DataObjectImpl_QueryInterface
,
367 DataObjectImpl_AddRef
,
368 DataObjectImpl_Release
,
369 DataObjectImpl_GetData
,
370 DataObjectImpl_GetDataHere
,
371 DataObjectImpl_QueryGetData
,
372 DataObjectImpl_GetCanonicalFormatEtc
,
373 DataObjectImpl_SetData
,
374 DataObjectImpl_EnumFormatEtc
,
375 DataObjectImpl_DAdvise
,
376 DataObjectImpl_DUnadvise
,
377 DataObjectImpl_EnumDAdvise
380 static HRESULT
DataObjectImpl_CreateText(LPCSTR text
, LPDATAOBJECT
*lplpdataobj
)
384 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
385 obj
->IDataObject_iface
.lpVtbl
= &VT_DataObjectImpl
;
387 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(text
) + 1);
388 strcpy(GlobalLock(obj
->text
), text
);
389 GlobalUnlock(obj
->text
);
394 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
395 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
397 *lplpdataobj
= (LPDATAOBJECT
)obj
;
401 static const char *cmpl_stm_data
= "complex stream";
402 static const char *cmpl_text_data
= "complex text";
403 static const WCHAR device_name
[] = {'m','y','d','e','v',0};
405 static HRESULT
DataObjectImpl_CreateComplex(LPDATAOBJECT
*lplpdataobj
)
411 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
412 obj
->IDataObject_iface
.lpVtbl
= &VT_DataObjectImpl
;
414 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(cmpl_text_data
) + 1);
415 strcpy(GlobalLock(obj
->text
), cmpl_text_data
);
416 GlobalUnlock(obj
->text
);
417 CreateStreamOnHGlobal(NULL
, TRUE
, &obj
->stm
);
418 IStream_Write(obj
->stm
, cmpl_stm_data
, strlen(cmpl_stm_data
), NULL
);
420 CreateILockBytesOnHGlobal(NULL
, TRUE
, &lbs
);
421 StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &obj
->stg
);
422 ILockBytes_Release(lbs
);
425 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
426 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
427 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
428 InitFormatEtc(obj
->fmtetc
[1], cf_stream
, TYMED_ISTREAM
);
429 InitFormatEtc(obj
->fmtetc
[2], cf_storage
, TYMED_ISTORAGE
);
430 InitFormatEtc(obj
->fmtetc
[3], cf_another
, TYMED_ISTORAGE
|TYMED_ISTREAM
|TYMED_HGLOBAL
);
431 if (0) /* Causes crashes on both Wine and Windows */
433 memset(&dm
, 0, sizeof(dm
));
434 dm
.dmSize
= sizeof(dm
);
435 dm
.dmDriverExtra
= 0;
436 lstrcpyW(dm
.dmDeviceName
, device_name
);
437 obj
->fmtetc
[3].ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
);
438 obj
->fmtetc
[3].ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
;
439 obj
->fmtetc
[3].ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
440 obj
->fmtetc
[3].ptd
->tdDeviceNameOffset
= 0;
441 obj
->fmtetc
[3].ptd
->tdPortNameOffset
= 0;
442 obj
->fmtetc
[3].ptd
->tdExtDevmodeOffset
= obj
->fmtetc
[3].ptd
->tdDriverNameOffset
+ sizeof(device_name
);
443 lstrcpyW((WCHAR
*)obj
->fmtetc
[3].ptd
->tdData
, device_name
);
444 memcpy(obj
->fmtetc
[3].ptd
->tdData
+ sizeof(device_name
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
447 InitFormatEtc(obj
->fmtetc
[4], cf_global
, TYMED_HGLOBAL
);
448 InitFormatEtc(obj
->fmtetc
[5], cf_another
, TYMED_HGLOBAL
);
449 InitFormatEtc(obj
->fmtetc
[6], cf_another
, 0xfffff);
450 InitFormatEtc(obj
->fmtetc
[7], cf_another
, 0xfffff);
451 obj
->fmtetc
[7].dwAspect
= DVASPECT_ICON
;
453 *lplpdataobj
= (LPDATAOBJECT
)obj
;
457 static void test_get_clipboard(void)
460 IDataObject
*data_obj
;
464 hr
= OleGetClipboard(NULL
);
465 ok(hr
== E_INVALIDARG
, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr
);
467 hr
= OleGetClipboard(&data_obj
);
468 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
470 /* test IDataObject_QueryGetData */
472 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
473 expect_DataObjectImpl_QueryGetData
= FALSE
;
475 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
476 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
477 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
479 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
480 fmtetc
.dwAspect
= 0xdeadbeef;
481 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
482 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
484 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
485 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
486 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
487 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
489 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
491 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
492 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
),
493 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
495 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
496 fmtetc
.cfFormat
= CF_RIFF
;
497 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
498 ok(hr
== DV_E_CLIPFORMAT
, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr
);
500 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
501 fmtetc
.tymed
= TYMED_FILE
;
502 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
503 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
505 expect_DataObjectImpl_QueryGetData
= TRUE
;
507 /* test IDataObject_GetData */
509 DataObjectImpl_GetData_calls
= 0;
511 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
512 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
513 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
514 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
516 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
517 fmtetc
.dwAspect
= 0xdeadbeef;
518 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
519 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
520 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
522 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
523 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
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
);
530 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
531 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
534 /* undo the unexpected success */
535 DataObjectImpl_GetData_calls
--;
536 ReleaseStgMedium(&stgmedium
);
539 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
540 fmtetc
.cfFormat
= CF_RIFF
;
541 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
542 ok(hr
== DV_E_FORMATETC
, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
543 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
545 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
546 fmtetc
.tymed
= TYMED_FILE
;
547 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
548 ok(hr
== DV_E_TYMED
, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr
);
549 if(SUCCEEDED(hr
)) ReleaseStgMedium(&stgmedium
);
551 ok(DataObjectImpl_GetData_calls
== 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls
);
553 IDataObject_Release(data_obj
);
556 static void test_enum_fmtetc(IDataObject
*src
)
560 IEnumFORMATETC
*enum_fmt
, *src_enum
;
561 FORMATETC fmt
, src_fmt
;
564 hr
= OleGetClipboard(&data
);
565 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
567 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_SET
, &enum_fmt
);
568 ok(hr
== E_NOTIMPL
||
569 broken(hr
== E_INVALIDARG
), /* win98 (not win98SE) */
572 DataObjectImpl_EnumFormatEtc_calls
= 0;
573 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
574 ok(hr
== S_OK
, "got %08x\n", hr
);
575 ok(DataObjectImpl_EnumFormatEtc_calls
== 0, "EnumFormatEtc was called\n");
577 if(src
) IDataObject_EnumFormatEtc(src
, DATADIR_GET
, &src_enum
);
579 while((hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
)) == S_OK
)
581 ok(src
!= NULL
, "shouldn't be here\n");
582 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
583 ok(hr
== S_OK
, "%d: got %08x\n", count
, hr
);
584 trace("%d: %s\n", count
, dump_fmtetc(&fmt
));
585 ok(fmt
.cfFormat
== src_fmt
.cfFormat
, "%d: %04x %04x\n", count
, fmt
.cfFormat
, src_fmt
.cfFormat
);
586 ok(fmt
.dwAspect
== src_fmt
.dwAspect
, "%d: %08x %08x\n", count
, fmt
.dwAspect
, src_fmt
.dwAspect
);
587 ok(fmt
.lindex
== src_fmt
.lindex
, "%d: %08x %08x\n", count
, fmt
.lindex
, src_fmt
.lindex
);
588 ok(fmt
.tymed
== src_fmt
.tymed
, "%d: %08x %08x\n", count
, fmt
.tymed
, src_fmt
.tymed
);
591 ok(src_fmt
.ptd
!= NULL
, "%d: expected non-NULL\n", count
);
592 CoTaskMemFree(fmt
.ptd
);
593 CoTaskMemFree(src_fmt
.ptd
);
598 ok(hr
== S_FALSE
, "%d: got %08x\n", count
, hr
);
602 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
604 broken(hr
== S_OK
&& count
== 5), /* win9x and winme don't enumerate duplicated cf's */
605 "%d: got %08x\n", count
, hr
);
606 IEnumFORMATETC_Release(src_enum
);
609 hr
= IEnumFORMATETC_Reset(enum_fmt
);
610 ok(hr
== S_OK
, "got %08x\n", hr
);
612 if(src
) /* Exercise the enumerator a bit */
614 IEnumFORMATETC
*clone
;
617 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
618 ok(hr
== S_OK
, "got %08x\n", hr
);
619 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
620 ok(hr
== S_OK
, "got %08x\n", hr
);
621 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &third_fmt
, NULL
);
622 ok(hr
== S_OK
, "got %08x\n", hr
);
624 hr
= IEnumFORMATETC_Reset(enum_fmt
);
625 ok(hr
== S_OK
, "got %08x\n", hr
);
626 hr
= IEnumFORMATETC_Skip(enum_fmt
, 2);
627 ok(hr
== S_OK
, "got %08x\n", hr
);
629 hr
= IEnumFORMATETC_Clone(enum_fmt
, &clone
);
630 ok(hr
== S_OK
, "got %08x\n", hr
);
631 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
632 ok(hr
== S_OK
, "got %08x\n", hr
);
633 ok(fmt
.cfFormat
== third_fmt
.cfFormat
, "formats don't match\n");
634 hr
= IEnumFORMATETC_Next(clone
, 1, &fmt
, NULL
);
635 ok(hr
== S_OK
, "got %08x\n", hr
);
636 ok(fmt
.cfFormat
== third_fmt
.cfFormat
, "formats don't match\n");
637 IEnumFORMATETC_Release(clone
);
640 IEnumFORMATETC_Release(enum_fmt
);
641 IDataObject_Release(data
);
644 static void test_no_cf_dataobject(void)
646 UINT cf_dataobject
= RegisterClipboardFormatA("DataObject");
647 UINT cf_ole_priv_data
= RegisterClipboardFormatA("Ole Private Data");
651 h
= GetClipboardData(cf_dataobject
);
652 ok(!h
, "got %p\n", h
);
653 h
= GetClipboardData(cf_ole_priv_data
);
654 ok(!h
, "got %p\n", h
);
659 static void test_cf_dataobject(IDataObject
*data
)
662 UINT cf_dataobject
= RegisterClipboardFormatA("DataObject");
663 UINT cf_ole_priv_data
= RegisterClipboardFormatA("Ole Private Data");
664 BOOL found_dataobject
= FALSE
, found_priv_data
= FALSE
;
669 cf
= EnumClipboardFormats(cf
);
670 if(cf
== cf_dataobject
)
672 HGLOBAL h
= GetClipboardData(cf
);
673 HWND
*ptr
= GlobalLock(h
);
674 DWORD size
= GlobalSize(h
);
675 HWND clip_owner
= GetClipboardOwner();
677 found_dataobject
= TRUE
;
678 ok(size
>= sizeof(*ptr
), "size %d\n", size
);
680 ok(*ptr
== clip_owner
, "hwnd %p clip_owner %p\n", *ptr
, clip_owner
);
681 else /* ole clipboard flushed */
682 ok(*ptr
== NULL
, "hwnd %p\n", *ptr
);
685 else if(cf
== cf_ole_priv_data
)
687 found_priv_data
= TRUE
;
690 HGLOBAL h
= GetClipboardData(cf
);
691 DWORD
*ptr
= GlobalLock(h
);
692 DWORD size
= GlobalSize(h
);
695 win_skip("Ole Private Data in win9x format\n");
699 IEnumFORMATETC
*enum_fmt
;
705 BOOL first_use_of_cf
;
715 struct formatetcetc fmts
[1];
716 } *priv
= (struct priv_data
*)ptr
;
717 CLIPFORMAT cfs_seen
[10];
719 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
720 ok(hr
== S_OK
, "got %08x\n", hr
);
721 fmt_ptr
= priv
->fmts
;
723 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
726 BOOL seen_cf
= FALSE
;
728 ok(fmt_ptr
->fmt
.cfFormat
== fmt
.cfFormat
,
729 "got %08x expected %08x\n", fmt_ptr
->fmt
.cfFormat
, fmt
.cfFormat
);
730 ok(fmt_ptr
->fmt
.dwAspect
== fmt
.dwAspect
, "got %08x expected %08x\n",
731 fmt_ptr
->fmt
.dwAspect
, fmt
.dwAspect
);
732 ok(fmt_ptr
->fmt
.lindex
== fmt
.lindex
, "got %08x expected %08x\n",
733 fmt_ptr
->fmt
.lindex
, fmt
.lindex
);
734 ok(fmt_ptr
->fmt
.tymed
== fmt
.tymed
, "got %08x expected %08x\n",
735 fmt_ptr
->fmt
.tymed
, fmt
.tymed
);
736 for(i
= 0; i
< count
; i
++)
737 if(fmt_ptr
->fmt
.cfFormat
== cfs_seen
[i
])
742 cfs_seen
[count
] = fmt
.cfFormat
;
743 ok(fmt_ptr
->first_use_of_cf
== seen_cf
? FALSE
: TRUE
, "got %08x expected %08x\n",
744 fmt_ptr
->first_use_of_cf
, !seen_cf
);
745 ok(fmt_ptr
->res
[0] == 0, "got %08x\n", fmt_ptr
->res
[1]);
746 ok(fmt_ptr
->res
[1] == 0, "got %08x\n", fmt_ptr
->res
[2]);
749 DVTARGETDEVICE
*target
;
751 ok(fmt_ptr
->fmt
.ptd
!= NULL
, "target device offset zero\n");
752 target
= (DVTARGETDEVICE
*)((char*)priv
+ (DWORD_PTR
)fmt_ptr
->fmt
.ptd
);
753 ok(!memcmp(target
, fmt
.ptd
, fmt
.ptd
->tdSize
), "target devices differ\n");
754 CoTaskMemFree(fmt
.ptd
);
759 ok(priv
->res1
== 0, "got %08x\n", priv
->res1
);
760 ok(priv
->res2
== 1, "got %08x\n", priv
->res2
);
761 ok(priv
->count
== count
, "got %08x expected %08x\n", priv
->count
, count
);
762 ok(priv
->res3
[0] == 0, "got %08x\n", priv
->res3
[0]);
764 /* win64 sets the lsb */
765 if(sizeof(fmt_ptr
->fmt
.ptd
) == 8)
766 todo_wine
ok(priv
->res3
[1] == 1, "got %08x\n", priv
->res3
[1]);
768 ok(priv
->res3
[1] == 0, "got %08x\n", priv
->res3
[1]);
771 IEnumFORMATETC_Release(enum_fmt
);
775 else if(cf
== cf_stream
)
781 DataObjectImpl_GetDataHere_calls
= 0;
782 h
= GetClipboardData(cf
);
783 ok(DataObjectImpl_GetDataHere_calls
== 1, "got %d\n", DataObjectImpl_GetDataHere_calls
);
785 size
= GlobalSize(h
);
786 ok(size
== strlen(cmpl_stm_data
) ||
787 broken(size
> strlen(cmpl_stm_data
)), /* win9x, winme */
788 "expected %d got %d\n", lstrlenA(cmpl_stm_data
), size
);
789 ok(!memcmp(ptr
, cmpl_stm_data
, strlen(cmpl_stm_data
)), "mismatch\n");
792 else if(cf
== cf_global
)
798 DataObjectImpl_GetDataHere_calls
= 0;
799 h
= GetClipboardData(cf
);
800 ok(DataObjectImpl_GetDataHere_calls
== 0, "got %d\n", DataObjectImpl_GetDataHere_calls
);
802 size
= GlobalSize(h
);
803 ok(size
== strlen(cmpl_text_data
) + 1 ||
804 broken(size
> strlen(cmpl_text_data
) + 1), /* win9x, winme */
805 "expected %d got %d\n", lstrlenA(cmpl_text_data
) + 1, size
);
806 ok(!memcmp(ptr
, cmpl_text_data
, strlen(cmpl_text_data
) + 1), "mismatch\n");
811 ok(found_dataobject
, "didn't find cf_dataobject\n");
812 ok(found_priv_data
, "didn't find cf_ole_priv_data\n");
815 static void test_set_clipboard(void)
819 LPDATAOBJECT data1
, data2
, data_cmpl
;
822 cf_stream
= RegisterClipboardFormatA("stream format");
823 cf_storage
= RegisterClipboardFormatA("storage format");
824 cf_global
= RegisterClipboardFormatA("global format");
825 cf_another
= RegisterClipboardFormatA("another format");
826 cf_onemore
= RegisterClipboardFormatA("one more format");
828 hr
= DataObjectImpl_CreateText("data1", &data1
);
829 ok(hr
== S_OK
, "Failed to create data1 object: 0x%08x\n", hr
);
832 hr
= DataObjectImpl_CreateText("data2", &data2
);
833 ok(hr
== S_OK
, "Failed to create data2 object: 0x%08x\n", hr
);
836 hr
= DataObjectImpl_CreateComplex(&data_cmpl
);
837 ok(hr
== S_OK
, "Failed to create complex data object: 0x%08x\n", hr
);
841 hr
= OleSetClipboard(data1
);
842 ok(hr
== CO_E_NOTINITIALIZED
, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr
);
845 hr
= OleSetClipboard(data1
);
846 ok(hr
== CO_E_NOTINITIALIZED
||
847 hr
== CLIPBRD_E_CANT_SET
, /* win9x */
848 "OleSetClipboard should have failed with "
849 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr
);
852 hr
= OleInitialize(NULL
);
853 ok(hr
== S_OK
, "OleInitialize failed with error 0x%08x\n", hr
);
855 hr
= OleSetClipboard(data1
);
856 ok(hr
== S_OK
, "failed to set clipboard to data1, hr = 0x%08x\n", hr
);
858 test_cf_dataobject(data1
);
860 hr
= OleIsCurrentClipboard(data1
);
861 ok(hr
== S_OK
, "expected current clipboard to be data1, hr = 0x%08x\n", hr
);
862 hr
= OleIsCurrentClipboard(data2
);
863 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
864 hr
= OleIsCurrentClipboard(NULL
);
865 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
867 test_get_clipboard();
869 hr
= OleSetClipboard(data2
);
870 ok(hr
== S_OK
, "failed to set clipboard to data2, hr = 0x%08x\n", hr
);
871 hr
= OleIsCurrentClipboard(data1
);
872 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
873 hr
= OleIsCurrentClipboard(data2
);
874 ok(hr
== S_OK
, "expected current clipboard to be data2, hr = 0x%08x\n", hr
);
875 hr
= OleIsCurrentClipboard(NULL
);
876 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
878 /* put a format directly onto the clipboard to show
879 OleFlushClipboard doesn't empty the clipboard */
880 hblob
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
|GMEM_ZEROINIT
, 10);
882 h
= SetClipboardData(cf_onemore
, hblob
);
883 ok(h
== hblob
, "got %p\n", h
);
884 h
= GetClipboardData(cf_onemore
);
886 broken(h
!= NULL
), /* win9x */
890 hr
= OleFlushClipboard();
891 ok(hr
== S_OK
, "failed to flush clipboard, hr = 0x%08x\n", hr
);
892 hr
= OleIsCurrentClipboard(data1
);
893 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
894 hr
= OleIsCurrentClipboard(data2
);
895 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
896 hr
= OleIsCurrentClipboard(NULL
);
897 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
899 /* format should survive the flush */
901 h
= GetClipboardData(cf_onemore
);
903 broken(h
!= NULL
), /* win9x */
907 test_cf_dataobject(NULL
);
909 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
912 h
= GetClipboardData(cf_onemore
);
913 ok(h
== NULL
, "got %p\n", h
);
916 trace("setting complex\n");
917 hr
= OleSetClipboard(data_cmpl
);
918 ok(hr
== S_OK
, "failed to set clipboard to complex data, hr = 0x%08x\n", hr
);
919 test_cf_dataobject(data_cmpl
);
920 test_enum_fmtetc(data_cmpl
);
922 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
924 test_no_cf_dataobject();
925 test_enum_fmtetc(NULL
);
927 ref
= IDataObject_Release(data1
);
928 ok(ref
== 0, "expected data1 ref=0, got %d\n", ref
);
929 ref
= IDataObject_Release(data2
);
930 ok(ref
== 0, "expected data2 ref=0, got %d\n", ref
);
931 ref
= IDataObject_Release(data_cmpl
);
932 ok(ref
== 0, "expected data_cmpl ref=0, got %d\n", ref
);
937 static inline ULONG
count_refs(IDataObject
*d
)
939 IDataObject_AddRef(d
);
940 return IDataObject_Release(d
);
943 static void test_consumer_refs(void)
946 IDataObject
*src
, *src2
, *get1
, *get2
, *get3
;
947 ULONG refs
, old_refs
;
951 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
955 /* First show that each clipboard state results in
956 a different data object */
958 hr
= DataObjectImpl_CreateText("data1", &src
);
959 ok(hr
== S_OK
, "got %08x\n", hr
);
960 hr
= DataObjectImpl_CreateText("data2", &src2
);
961 ok(hr
== S_OK
, "got %08x\n", hr
);
963 hr
= OleSetClipboard(src
);
964 ok(hr
== S_OK
, "got %08x\n", hr
);
966 hr
= OleGetClipboard(&get1
);
967 ok(hr
== S_OK
, "got %08x\n", hr
);
969 hr
= OleGetClipboard(&get2
);
970 ok(hr
== S_OK
, "got %08x\n", hr
);
973 broken(get1
!= get2
), /* win9x, winme & nt4 */
974 "data objects differ\n");
975 refs
= IDataObject_Release(get2
);
976 ok(refs
== (get1
== get2
? 1 : 0), "got %d\n", refs
);
980 DataObjectImpl_GetData_calls
= 0;
981 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
982 ok(hr
== S_OK
, "got %08x\n", hr
);
983 ok(DataObjectImpl_GetData_calls
== 0, "GetData called\n");
984 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
986 hr
= OleGetClipboard(&get2
);
987 ok(hr
== S_OK
, "got %08x\n", hr
);
989 ok(get1
!= get2
, "data objects match\n");
991 OleSetClipboard(NULL
);
993 hr
= OleGetClipboard(&get3
);
994 ok(hr
== S_OK
, "got %08x\n", hr
);
996 ok(get1
!= get3
, "data objects match\n");
997 ok(get2
!= get3
, "data objects match\n");
999 IDataObject_Release(get3
);
1000 IDataObject_Release(get2
);
1001 IDataObject_Release(get1
);
1003 /* Now call GetData before the flush and show that this
1004 takes a ref on our src data obj. */
1006 hr
= OleSetClipboard(src
);
1007 ok(hr
== S_OK
, "got %08x\n", hr
);
1009 old_refs
= count_refs(src
);
1011 hr
= OleGetClipboard(&get1
);
1012 ok(hr
== S_OK
, "got %08x\n", hr
);
1014 refs
= count_refs(src
);
1015 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
1017 DataObjectImpl_GetData_calls
= 0;
1018 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1019 ok(hr
== S_OK
, "got %08x\n", hr
);
1020 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1021 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1022 refs
= count_refs(src
);
1023 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
1025 OleFlushClipboard();
1027 DataObjectImpl_GetData_calls
= 0;
1028 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1029 ok(hr
== S_OK
, "got %08x\n", hr
);
1030 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1031 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1033 refs
= count_refs(src
);
1034 ok(refs
== 2, "%d\n", refs
);
1036 IDataObject_Release(get1
);
1038 refs
= count_refs(src
);
1039 ok(refs
== 1, "%d\n", refs
);
1041 /* Now set a second src object before the call to GetData
1042 and show that GetData calls that second src. */
1044 hr
= OleSetClipboard(src
);
1045 ok(hr
== S_OK
, "got %08x\n", hr
);
1047 old_refs
= count_refs(src
);
1049 hr
= OleGetClipboard(&get1
);
1050 ok(hr
== S_OK
, "got %08x\n", hr
);
1052 refs
= count_refs(src
);
1053 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
1055 hr
= OleSetClipboard(src2
);
1056 ok(hr
== S_OK
, "got %08x\n", hr
);
1058 old_refs
= count_refs(src2
);
1060 DataObjectImpl_GetData_calls
= 0;
1061 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
1062 ok(hr
== S_OK
, "got %08x\n", hr
);
1063 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
1064 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1066 refs
= count_refs(src
);
1067 ok(refs
== 1, "%d\n", refs
);
1068 refs
= count_refs(src2
);
1069 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
1071 OleSetClipboard(NULL
);
1073 refs
= count_refs(src2
);
1074 ok(refs
== 2, "%d\n", refs
);
1076 IDataObject_Release(get1
);
1078 IDataObject_Release(src2
);
1079 IDataObject_Release(src
);
1084 static void test_flushed_getdata(void)
1087 IDataObject
*src
, *get
;
1093 OleInitialize(NULL
);
1095 hr
= DataObjectImpl_CreateComplex(&src
);
1096 ok(hr
== S_OK
, "got %08x\n", hr
);
1098 hr
= OleSetClipboard(src
);
1099 ok(hr
== S_OK
, "got %08x\n", hr
);
1101 hr
= OleFlushClipboard();
1102 ok(hr
== S_OK
, "got %08x\n", hr
);
1104 hr
= OleGetClipboard(&get
);
1105 ok(hr
== S_OK
, "got %08x\n", hr
);
1107 /* global format -> global & stream */
1109 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1110 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1111 ok(hr
== S_OK
, "got %08x\n", hr
);
1112 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1113 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1115 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTREAM
);
1116 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1117 ok(hr
== S_OK
, "got %08x\n", hr
);
1118 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1119 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1121 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTORAGE
);
1122 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1123 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1124 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1126 InitFormatEtc(fmt
, CF_TEXT
, 0xffff);
1127 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1128 ok(hr
== S_OK
, "got %08x\n", hr
);
1129 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1130 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1132 /* stream format -> global & stream */
1134 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTREAM
);
1135 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1136 ok(hr
== S_OK
, "got %08x\n", hr
);
1137 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1138 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1140 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTORAGE
);
1141 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1142 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1143 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1145 InitFormatEtc(fmt
, cf_stream
, TYMED_HGLOBAL
);
1146 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1147 ok(hr
== S_OK
, "got %08x\n", hr
);
1148 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1149 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1151 InitFormatEtc(fmt
, cf_stream
, 0xffff);
1152 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1153 ok(hr
== S_OK
, "got %08x\n", hr
);
1154 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1155 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1157 /* storage format -> global, stream & storage */
1159 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTORAGE
);
1160 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1161 ok(hr
== S_OK
, "got %08x\n", hr
);
1162 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1164 hr
= IStorage_Stat(med
.u
.pstg
, &stat
, STATFLAG_NONAME
);
1165 ok(hr
== S_OK
, "got %08x\n", hr
);
1166 ok(stat
.grfMode
== (STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
), "got %08x\n", stat
.grfMode
);
1167 ReleaseStgMedium(&med
);
1170 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTREAM
);
1171 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1172 ok(hr
== S_OK
, "got %08x\n", hr
);
1173 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1174 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1176 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
);
1177 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1178 ok(hr
== S_OK
, "got %08x\n", hr
);
1179 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1180 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1182 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
| TYMED_ISTREAM
);
1183 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1184 ok(hr
== S_OK
, "got %08x\n", hr
);
1185 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1186 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1188 InitFormatEtc(fmt
, cf_storage
, 0xffff);
1189 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1190 ok(hr
== S_OK
, "got %08x\n", hr
);
1191 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1192 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1194 /* complex format with target device */
1196 InitFormatEtc(fmt
, cf_another
, 0xffff);
1197 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1198 ok(hr
== S_OK
, "got %08x\n", hr
);
1199 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1201 if (0) /* Causes crashes on both Wine and Windows */
1203 InitFormatEtc(fmt
, cf_another
, 0xffff);
1204 memset(&dm
, 0, sizeof(dm
));
1205 dm
.dmSize
= sizeof(dm
);
1206 dm
.dmDriverExtra
= 0;
1207 lstrcpyW(dm
.dmDeviceName
, device_name
);
1208 fmt
.ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
);
1209 fmt
.ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(device_name
) + dm
.dmSize
+ dm
.dmDriverExtra
;
1210 fmt
.ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
1211 fmt
.ptd
->tdDeviceNameOffset
= 0;
1212 fmt
.ptd
->tdPortNameOffset
= 0;
1213 fmt
.ptd
->tdExtDevmodeOffset
= fmt
.ptd
->tdDriverNameOffset
+ sizeof(device_name
);
1214 lstrcpyW((WCHAR
*)fmt
.ptd
->tdData
, device_name
);
1215 memcpy(fmt
.ptd
->tdData
+ sizeof(device_name
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
1217 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1218 ok(hr
== S_OK
, "got %08x\n", hr
);
1219 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1220 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1222 HeapFree(GetProcessHeap(), 0, fmt
.ptd
);
1226 IDataObject_Release(get
);
1227 IDataObject_Release(src
);
1231 static HGLOBAL
create_text(void)
1233 HGLOBAL h
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
, 5);
1234 char *p
= GlobalLock(h
);
1240 static HENHMETAFILE
create_emf(void)
1242 const RECT rect
= {0, 0, 100, 100};
1243 HDC hdc
= CreateEnhMetaFileA(NULL
, NULL
, &rect
, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1244 ExtTextOutA(hdc
, 0, 0, ETO_OPAQUE
, &rect
, "Test String", strlen("Test String"), NULL
);
1245 return CloseEnhMetaFile(hdc
);
1248 static void test_nonole_clipboard(void)
1253 IEnumFORMATETC
*enum_fmt
;
1255 HGLOBAL h
, hblob
, htext
;
1260 r
= OpenClipboard(NULL
);
1261 ok(r
, "gle %d\n", GetLastError());
1262 r
= EmptyClipboard();
1263 ok(r
, "gle %d\n", GetLastError());
1264 r
= CloseClipboard();
1265 ok(r
, "gle %d\n", GetLastError());
1267 OleInitialize(NULL
);
1269 /* empty clipboard */
1270 hr
= OleGetClipboard(&get
);
1271 ok(hr
== S_OK
, "got %08x\n", hr
);
1272 hr
= IDataObject_EnumFormatEtc(get
, DATADIR_GET
, &enum_fmt
);
1273 ok(hr
== S_OK
, "got %08x\n", hr
);
1275 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1276 ok(hr
== S_FALSE
, "got %08x\n", hr
);
1277 IEnumFORMATETC_Release(enum_fmt
);
1279 IDataObject_Release(get
);
1281 /* set a user defined clipboard type */
1283 htext
= create_text();
1284 hblob
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
|GMEM_ZEROINIT
, 10);
1287 r
= OpenClipboard(NULL
);
1288 ok(r
, "gle %d\n", GetLastError());
1289 h
= SetClipboardData(CF_TEXT
, htext
);
1290 ok(h
== htext
, "got %p\n", h
);
1291 h
= SetClipboardData(cf_onemore
, hblob
);
1292 ok(h
== hblob
, "got %p\n", h
);
1293 h
= SetClipboardData(CF_ENHMETAFILE
, emf
);
1294 ok(h
== emf
, "got %p\n", h
);
1295 r
= CloseClipboard();
1296 ok(r
, "gle %d\n", GetLastError());
1298 hr
= OleGetClipboard(&get
);
1299 ok(hr
== S_OK
, "got %08x\n", hr
);
1300 hr
= IDataObject_EnumFormatEtc(get
, DATADIR_GET
, &enum_fmt
);
1301 ok(hr
== S_OK
, "got %08x\n", hr
);
1303 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1304 ok(hr
== S_OK
, "got %08x\n", hr
);
1305 ok(fmt
.cfFormat
== CF_TEXT
, "cf %04x\n", fmt
.cfFormat
);
1306 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1307 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1308 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1309 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1311 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1312 ok(hr
== S_OK
, "got %08x\n", hr
);
1313 ok(fmt
.cfFormat
== cf_onemore
, "cf %04x\n", fmt
.cfFormat
);
1314 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1315 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1316 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1317 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1319 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1320 ok(hr
== S_OK
, "got %08x\n", hr
);
1321 ok(fmt
.cfFormat
== CF_ENHMETAFILE
, "cf %04x\n", fmt
.cfFormat
);
1322 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1323 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1324 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1325 ok(fmt
.tymed
== TYMED_ENHMF
, "tymed %x\n", fmt
.tymed
);
1327 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1328 ok(hr
== S_OK
, "got %08x\n", hr
); /* User32 adds some synthesised formats */
1330 todo_wine
ok(fmt
.cfFormat
== CF_LOCALE
, "cf %04x\n", fmt
.cfFormat
);
1331 if(fmt
.cfFormat
== CF_LOCALE
)
1333 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1334 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1335 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1336 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1338 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1339 ok(hr
== S_OK
, "got %08x\n", hr
);
1342 ok(fmt
.cfFormat
== CF_OEMTEXT
, "cf %04x\n", fmt
.cfFormat
);
1343 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1344 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1345 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1346 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1348 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1349 ok(hr
== S_OK
, "got %08x\n", hr
);
1350 ok(fmt
.cfFormat
== CF_UNICODETEXT
||
1351 broken(fmt
.cfFormat
== CF_METAFILEPICT
), /* win9x and winme don't have CF_UNICODETEXT */
1352 "cf %04x\n", fmt
.cfFormat
);
1353 if(fmt
.cfFormat
== CF_UNICODETEXT
)
1355 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1356 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1357 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1358 ok(fmt
.tymed
== (TYMED_ISTREAM
| TYMED_HGLOBAL
), "tymed %x\n", fmt
.tymed
);
1360 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1361 ok(hr
== S_OK
, "got %08x\n", hr
);
1363 ok(fmt
.cfFormat
== CF_METAFILEPICT
, "cf %04x\n", fmt
.cfFormat
);
1364 ok(fmt
.ptd
== NULL
, "ptd %p\n", fmt
.ptd
);
1365 ok(fmt
.dwAspect
== DVASPECT_CONTENT
, "aspect %x\n", fmt
.dwAspect
);
1366 ok(fmt
.lindex
== -1, "lindex %d\n", fmt
.lindex
);
1367 ok(fmt
.tymed
== TYMED_MFPICT
, "tymed %x\n", fmt
.tymed
);
1369 hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
);
1370 ok(hr
== S_FALSE
, "got %08x\n", hr
);
1371 IEnumFORMATETC_Release(enum_fmt
);
1373 InitFormatEtc(fmt
, CF_ENHMETAFILE
, TYMED_ENHMF
);
1374 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1375 ok(hr
== S_OK
, "got %08x\n", hr
);
1376 obj_type
= GetObjectType(U(med
).hEnhMetaFile
);
1377 ok(obj_type
== OBJ_ENHMETAFILE
, "got %d\n", obj_type
);
1378 if(SUCCEEDED(hr
)) ReleaseStgMedium(&med
);
1380 IDataObject_Release(get
);
1382 r
= OpenClipboard(NULL
);
1383 ok(r
, "gle %d\n", GetLastError());
1384 r
= EmptyClipboard();
1385 ok(r
, "gle %d\n", GetLastError());
1386 r
= CloseClipboard();
1387 ok(r
, "gle %d\n", GetLastError());
1392 static void test_getdatahere(void)
1395 IDataObject
*src
, *get
;
1399 OleInitialize(NULL
);
1401 hr
= DataObjectImpl_CreateComplex(&src
);
1402 ok(hr
== S_OK
, "got %08x\n", hr
);
1404 hr
= OleSetClipboard(src
);
1405 ok(hr
== S_OK
, "got %08x\n", hr
);
1407 hr
= OleGetClipboard(&get
);
1408 ok(hr
== S_OK
, "got %08x\n", hr
);
1410 /* global format -> global & stream */
1412 DataObjectImpl_GetData_calls
= 0;
1413 DataObjectImpl_GetDataHere_calls
= 0;
1415 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1417 med
.pUnkForRelease
= NULL
;
1418 med
.tymed
= TYMED_HGLOBAL
;
1419 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1420 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1421 ok(hr
== S_OK
, "got %08x\n", hr
);
1422 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1423 ReleaseStgMedium(&med
);
1424 ok(DataObjectImpl_GetDataHere_calls
== 1, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1425 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1427 InitFormatEtc(fmt
, CF_TEXT
, 0);
1429 med
.pUnkForRelease
= NULL
;
1430 med
.tymed
= TYMED_HGLOBAL
;
1431 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1432 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1433 ok(hr
== S_OK
, "got %08x\n", hr
);
1434 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1435 ReleaseStgMedium(&med
);
1436 ok(DataObjectImpl_GetDataHere_calls
== 2, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1437 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1439 med
.pUnkForRelease
= NULL
;
1440 med
.tymed
= TYMED_HGLOBAL
;
1441 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 1);
1442 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1443 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1444 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1445 ReleaseStgMedium(&med
);
1446 ok(DataObjectImpl_GetDataHere_calls
== 3, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1447 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1449 med
.pUnkForRelease
= NULL
;
1450 med
.tymed
= TYMED_ISTREAM
;
1451 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1452 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1453 ok(hr
== S_OK
, "got %08x\n", hr
);
1454 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1455 ReleaseStgMedium(&med
);
1456 ok(DataObjectImpl_GetDataHere_calls
== 4, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1457 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1459 med
.pUnkForRelease
= NULL
;
1460 med
.tymed
= TYMED_ISTORAGE
;
1461 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1462 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1463 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1464 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1465 ReleaseStgMedium(&med
);
1466 ok(DataObjectImpl_GetDataHere_calls
== 5, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1467 ok(DataObjectImpl_GetData_calls
== 1, "called %d\n", DataObjectImpl_GetData_calls
);
1469 InitFormatEtc(fmt
, cf_stream
, 0);
1471 med
.pUnkForRelease
= NULL
;
1472 med
.tymed
= TYMED_HGLOBAL
;
1473 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 100);
1474 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1475 ok(hr
== S_OK
, "got %08x\n", hr
);
1476 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1477 ReleaseStgMedium(&med
);
1478 ok(DataObjectImpl_GetDataHere_calls
== 7, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1479 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1481 med
.pUnkForRelease
= NULL
;
1482 med
.tymed
= TYMED_ISTREAM
;
1483 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1484 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1485 ok(hr
== S_OK
, "got %08x\n", hr
);
1486 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1487 ReleaseStgMedium(&med
);
1488 ok(DataObjectImpl_GetDataHere_calls
== 8, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1489 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1491 med
.pUnkForRelease
= NULL
;
1492 med
.tymed
= TYMED_ISTORAGE
;
1493 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1494 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1495 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1496 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1497 ReleaseStgMedium(&med
);
1498 ok(DataObjectImpl_GetDataHere_calls
== 9, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1499 ok(DataObjectImpl_GetData_calls
== 2, "called %d\n", DataObjectImpl_GetData_calls
);
1501 InitFormatEtc(fmt
, cf_storage
, 0);
1503 med
.pUnkForRelease
= NULL
;
1504 med
.tymed
= TYMED_HGLOBAL
;
1505 U(med
).hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, 3000);
1506 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1507 ok(hr
== S_OK
, "got %08x\n", hr
);
1508 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1509 ReleaseStgMedium(&med
);
1510 ok(DataObjectImpl_GetDataHere_calls
== 11, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1511 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1513 med
.pUnkForRelease
= NULL
;
1514 med
.tymed
= TYMED_ISTREAM
;
1515 CreateStreamOnHGlobal(NULL
, TRUE
, &U(med
).pstm
);
1516 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1517 ok(hr
== S_OK
, "got %08x\n", hr
);
1518 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1519 ReleaseStgMedium(&med
);
1520 ok(DataObjectImpl_GetDataHere_calls
== 12, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1521 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1523 med
.pUnkForRelease
= NULL
;
1524 med
.tymed
= TYMED_ISTORAGE
;
1525 StgCreateDocfile(NULL
, STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_DELETEONRELEASE
, 0, &U(med
).pstg
);
1526 hr
= IDataObject_GetDataHere(get
, &fmt
, &med
);
1527 ok(hr
== S_OK
, "got %08x\n", hr
);
1528 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1529 ReleaseStgMedium(&med
);
1530 ok(DataObjectImpl_GetDataHere_calls
== 13, "called %d\n", DataObjectImpl_GetDataHere_calls
);
1531 ok(DataObjectImpl_GetData_calls
== 3, "called %d\n", DataObjectImpl_GetData_calls
);
1534 IDataObject_Release(get
);
1535 IDataObject_Release(src
);
1541 START_TEST(clipboard
)
1543 test_set_clipboard();
1544 test_consumer_refs();
1545 test_flushed_getdata();
1546 test_nonole_clipboard();