4 * Copyright 2006 Kevin Koltzau
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NONAMELESSUNION
31 #include "wine/test.h"
33 #define InitFormatEtc(fe, cf, med) \
36 (fe).dwAspect=DVASPECT_CONTENT;\
42 static inline char *dump_fmtetc(FORMATETC
*fmt
)
46 snprintf(buf
, sizeof(buf
), "cf %04x ptd %p aspect %x lindex %d tymed %x",
47 fmt
->cfFormat
, fmt
->ptd
, fmt
->dwAspect
, fmt
->lindex
, fmt
->tymed
);
51 typedef struct DataObjectImpl
{
52 const IDataObjectVtbl
*lpVtbl
;
63 typedef struct EnumFormatImpl
{
64 const IEnumFORMATETCVtbl
*lpVtbl
;
73 static BOOL expect_DataObjectImpl_QueryGetData
= TRUE
;
74 static ULONG DataObjectImpl_GetData_calls
= 0;
75 static ULONG DataObjectImpl_GetDataHere_calls
= 0;
76 static ULONG DataObjectImpl_EnumFormatEtc_calls
= 0;
78 static UINT cf_stream
, cf_storage
, cf_global
, cf_another
, cf_onemore
;
80 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT size
, LPENUMFORMATETC
*lplpformatetc
);
82 static HRESULT WINAPI
EnumFormatImpl_QueryInterface(IEnumFORMATETC
*iface
, REFIID riid
, LPVOID
*ppvObj
)
84 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
86 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumFORMATETC
)) {
87 IEnumFORMATETC_AddRef(iface
);
95 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
97 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
98 LONG ref
= InterlockedIncrement(&This
->ref
);
102 static ULONG WINAPI
EnumFormatImpl_Release(IEnumFORMATETC
*iface
)
104 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
105 ULONG ref
= InterlockedDecrement(&This
->ref
);
108 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
109 HeapFree(GetProcessHeap(), 0, This
);
115 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
116 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
118 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
124 count
= min(celt
, This
->fmtetc_cnt
- This
->cur
);
125 for(i
= 0; i
< count
; i
++, This
->cur
++, rgelt
++)
127 *rgelt
= This
->fmtetc
[This
->cur
];
130 DWORD size
= This
->fmtetc
[This
->cur
].ptd
->tdSize
;
131 rgelt
->ptd
= CoTaskMemAlloc(size
);
132 memcpy(rgelt
->ptd
, This
->fmtetc
[This
->cur
].ptd
, size
);
136 *pceltFetched
= count
;
137 return count
== celt
? S_OK
: S_FALSE
;
140 static HRESULT WINAPI
EnumFormatImpl_Skip(IEnumFORMATETC
*iface
, ULONG celt
)
142 ok(0, "unexpected call\n");
146 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
148 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
154 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
156 ok(0, "unexpected call\n");
160 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
161 EnumFormatImpl_QueryInterface
,
162 EnumFormatImpl_AddRef
,
163 EnumFormatImpl_Release
,
166 EnumFormatImpl_Reset
,
170 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
174 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl
));
175 ret
->lpVtbl
= &VT_EnumFormatImpl
;
178 ret
->fmtetc_cnt
= fmtetc_cnt
;
179 ret
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt
*sizeof(FORMATETC
));
180 memcpy(ret
->fmtetc
, fmtetc
, fmtetc_cnt
*sizeof(FORMATETC
));
181 *lplpformatetc
= (LPENUMFORMATETC
)ret
;
185 static HRESULT WINAPI
DataObjectImpl_QueryInterface(IDataObject
*iface
, REFIID riid
, LPVOID
*ppvObj
)
187 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
189 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDataObject
)) {
190 IDataObject_AddRef(iface
);
195 return E_NOINTERFACE
;
198 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
200 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
201 ULONG ref
= InterlockedIncrement(&This
->ref
);
205 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
207 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
208 ULONG ref
= InterlockedDecrement(&This
->ref
);
213 if(This
->text
) GlobalFree(This
->text
);
214 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
215 HeapFree(GetProcessHeap(), 0, This
->fmtetc
[i
].ptd
);
216 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
217 if(This
->stm
) IStream_Release(This
->stm
);
218 if(This
->stg
) IStorage_Release(This
->stg
);
219 HeapFree(GetProcessHeap(), 0, This
);
225 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
227 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
229 BOOL foundFormat
= FALSE
;
231 trace("getdata: %s\n", dump_fmtetc(pformatetc
));
233 DataObjectImpl_GetData_calls
++;
235 if(pformatetc
->lindex
!= -1)
236 return DV_E_FORMATETC
;
238 for(i
= 0; i
< This
->fmtetc_cnt
; i
++)
240 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
)
243 if(This
->fmtetc
[i
].tymed
& pformatetc
->tymed
)
245 pmedium
->pUnkForRelease
= (LPUNKNOWN
)iface
;
246 IUnknown_AddRef(pmedium
->pUnkForRelease
);
248 if(pformatetc
->cfFormat
== CF_TEXT
|| pformatetc
->cfFormat
== cf_global
)
250 pmedium
->tymed
= TYMED_HGLOBAL
;
251 U(*pmedium
).hGlobal
= This
->text
;
253 else if(pformatetc
->cfFormat
== cf_stream
)
255 pmedium
->tymed
= TYMED_ISTREAM
;
256 IStream_AddRef(This
->stm
);
257 U(*pmedium
).pstm
= This
->stm
;
259 else if(pformatetc
->cfFormat
== cf_storage
|| pformatetc
->cfFormat
== cf_another
)
261 pmedium
->tymed
= TYMED_ISTORAGE
;
262 IStorage_AddRef(This
->stg
);
263 U(*pmedium
).pstg
= This
->stg
;
270 return foundFormat
? DV_E_TYMED
: DV_E_FORMATETC
;
273 static HRESULT WINAPI
DataObjectImpl_GetDataHere(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
275 trace("getdatahere: %s\n", dump_fmtetc(pformatetc
));
276 DataObjectImpl_GetDataHere_calls
++;
281 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
283 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
285 BOOL foundFormat
= FALSE
;
287 trace("querygetdata: %s\n", dump_fmtetc(pformatetc
));
288 if (!expect_DataObjectImpl_QueryGetData
)
289 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
291 if(pformatetc
->lindex
!= -1)
294 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
295 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
297 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
301 return foundFormat
?DV_E_FORMATETC
:DV_E_TYMED
;
304 static HRESULT WINAPI
DataObjectImpl_GetCanonicalFormatEtc(IDataObject
* iface
, FORMATETC
*pformatectIn
,
305 FORMATETC
*pformatetcOut
)
307 ok(0, "unexpected call\n");
311 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
312 STGMEDIUM
*pmedium
, BOOL fRelease
)
314 ok(0, "unexpected call\n");
318 static HRESULT WINAPI
DataObjectImpl_EnumFormatEtc(IDataObject
* iface
, DWORD dwDirection
,
319 IEnumFORMATETC
**ppenumFormatEtc
)
321 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
323 DataObjectImpl_EnumFormatEtc_calls
++;
325 if(dwDirection
!= DATADIR_GET
) {
326 ok(0, "unexpected direction %d\n", dwDirection
);
329 return EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenumFormatEtc
);
332 static HRESULT WINAPI
DataObjectImpl_DAdvise(IDataObject
* iface
, FORMATETC
*pformatetc
, DWORD advf
,
333 IAdviseSink
*pAdvSink
, DWORD
*pdwConnection
)
335 ok(0, "unexpected call\n");
339 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
341 ok(0, "unexpected call\n");
345 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
347 ok(0, "unexpected call\n");
351 static const IDataObjectVtbl VT_DataObjectImpl
=
353 DataObjectImpl_QueryInterface
,
354 DataObjectImpl_AddRef
,
355 DataObjectImpl_Release
,
356 DataObjectImpl_GetData
,
357 DataObjectImpl_GetDataHere
,
358 DataObjectImpl_QueryGetData
,
359 DataObjectImpl_GetCanonicalFormatEtc
,
360 DataObjectImpl_SetData
,
361 DataObjectImpl_EnumFormatEtc
,
362 DataObjectImpl_DAdvise
,
363 DataObjectImpl_DUnadvise
,
364 DataObjectImpl_EnumDAdvise
367 static HRESULT
DataObjectImpl_CreateText(LPCSTR text
, LPDATAOBJECT
*lplpdataobj
)
371 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
372 obj
->lpVtbl
= &VT_DataObjectImpl
;
374 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(text
) + 1);
375 strcpy(GlobalLock(obj
->text
), text
);
376 GlobalUnlock(obj
->text
);
381 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
382 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
384 *lplpdataobj
= (LPDATAOBJECT
)obj
;
388 const char *cmpl_stm_data
= "complex stream";
389 const char *cmpl_text_data
= "complex text";
390 const WCHAR devname
[] = {'m','y','d','e','v',0};
392 static HRESULT
DataObjectImpl_CreateComplex(LPDATAOBJECT
*lplpdataobj
)
398 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
399 obj
->lpVtbl
= &VT_DataObjectImpl
;
401 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(cmpl_text_data
) + 1);
402 strcpy(GlobalLock(obj
->text
), cmpl_text_data
);
403 GlobalUnlock(obj
->text
);
404 CreateStreamOnHGlobal(NULL
, TRUE
, &obj
->stm
);
405 IStream_Write(obj
->stm
, cmpl_stm_data
, strlen(cmpl_stm_data
), NULL
);
407 CreateILockBytesOnHGlobal(NULL
, TRUE
, &lbs
);
408 StgCreateDocfileOnILockBytes(lbs
, STGM_CREATE
|STGM_SHARE_EXCLUSIVE
|STGM_READWRITE
, 0, &obj
->stg
);
409 ILockBytes_Release(lbs
);
412 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
413 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
414 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
415 InitFormatEtc(obj
->fmtetc
[1], cf_stream
, TYMED_ISTREAM
);
416 InitFormatEtc(obj
->fmtetc
[2], cf_storage
, TYMED_ISTORAGE
);
417 InitFormatEtc(obj
->fmtetc
[3], cf_another
, TYMED_ISTORAGE
|TYMED_ISTREAM
|TYMED_HGLOBAL
);
418 memset(&dm
, 0, sizeof(dm
));
419 dm
.dmSize
= sizeof(dm
);
420 dm
.dmDriverExtra
= 0;
421 lstrcpyW(dm
.dmDeviceName
, devname
);
422 obj
->fmtetc
[3].ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(devname
) + dm
.dmSize
+ dm
.dmDriverExtra
);
423 obj
->fmtetc
[3].ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(devname
) + dm
.dmSize
+ dm
.dmDriverExtra
;
424 obj
->fmtetc
[3].ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
425 obj
->fmtetc
[3].ptd
->tdDeviceNameOffset
= 0;
426 obj
->fmtetc
[3].ptd
->tdPortNameOffset
= 0;
427 obj
->fmtetc
[3].ptd
->tdExtDevmodeOffset
= obj
->fmtetc
[3].ptd
->tdDriverNameOffset
+ sizeof(devname
);
428 lstrcpyW((WCHAR
*)obj
->fmtetc
[3].ptd
->tdData
, devname
);
429 memcpy(obj
->fmtetc
[3].ptd
->tdData
+ sizeof(devname
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
431 InitFormatEtc(obj
->fmtetc
[4], cf_global
, TYMED_HGLOBAL
);
432 InitFormatEtc(obj
->fmtetc
[5], cf_another
, TYMED_HGLOBAL
);
433 InitFormatEtc(obj
->fmtetc
[6], cf_another
, 0xfffff);
434 InitFormatEtc(obj
->fmtetc
[7], cf_another
, 0xfffff);
435 obj
->fmtetc
[7].dwAspect
= DVASPECT_ICON
;
437 *lplpdataobj
= (LPDATAOBJECT
)obj
;
441 static void test_get_clipboard(void)
444 IDataObject
*data_obj
;
448 hr
= OleGetClipboard(NULL
);
449 ok(hr
== E_INVALIDARG
, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr
);
451 hr
= OleGetClipboard(&data_obj
);
452 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
454 /* test IDataObject_QueryGetData */
456 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
457 expect_DataObjectImpl_QueryGetData
= FALSE
;
459 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
460 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
461 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
463 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
464 fmtetc
.dwAspect
= 0xdeadbeef;
465 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
466 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
468 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
469 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
470 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
471 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
473 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
475 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
476 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
),
477 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
479 ReleaseStgMedium(&stgmedium
);
481 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
482 fmtetc
.cfFormat
= CF_RIFF
;
483 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
484 ok(hr
== DV_E_CLIPFORMAT
, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr
);
486 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
487 fmtetc
.tymed
= TYMED_FILE
;
488 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
489 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
491 expect_DataObjectImpl_QueryGetData
= TRUE
;
493 /* test IDataObject_GetData */
495 DataObjectImpl_GetData_calls
= 0;
497 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
498 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
499 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
500 ReleaseStgMedium(&stgmedium
);
502 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
503 fmtetc
.dwAspect
= 0xdeadbeef;
504 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
505 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
506 ReleaseStgMedium(&stgmedium
);
508 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
509 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
510 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
511 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
512 ReleaseStgMedium(&stgmedium
);
514 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
516 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
517 ok(hr
== DV_E_FORMATETC
|| broken(hr
== S_OK
), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
520 /* undo the unexpected success */
521 DataObjectImpl_GetData_calls
--;
522 ReleaseStgMedium(&stgmedium
);
525 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
526 fmtetc
.cfFormat
= CF_RIFF
;
527 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
528 ok(hr
== DV_E_FORMATETC
, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
530 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
531 fmtetc
.tymed
= TYMED_FILE
;
532 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
533 ok(hr
== DV_E_TYMED
, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr
);
535 ok(DataObjectImpl_GetData_calls
== 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls
);
537 IDataObject_Release(data_obj
);
540 static void test_enum_fmtetc(IDataObject
*src
)
544 IEnumFORMATETC
*enum_fmt
, *src_enum
;
545 FORMATETC fmt
, src_fmt
;
548 hr
= OleGetClipboard(&data
);
549 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
551 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_SET
, &enum_fmt
);
552 ok(hr
== E_NOTIMPL
||
553 broken(hr
== E_INVALIDARG
), /* win98 (not win98SE) */
556 DataObjectImpl_EnumFormatEtc_calls
= 0;
557 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
558 ok(hr
== S_OK
, "got %08x\n", hr
);
559 ok(DataObjectImpl_EnumFormatEtc_calls
== 0, "EnumFormatEtc was called\n");
561 if(src
) IDataObject_EnumFormatEtc(src
, DATADIR_GET
, &src_enum
);
563 while((hr
= IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
)) == S_OK
)
565 ok(src
!= NULL
, "shouldn't be here\n");
566 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
567 ok(hr
== S_OK
, "%d: got %08x\n", count
, hr
);
568 trace("%d: cf %04x aspect %x tymed %x\n", count
, fmt
.cfFormat
, fmt
.dwAspect
, fmt
.tymed
);
569 ok(fmt
.cfFormat
== src_fmt
.cfFormat
, "%d: %04x %04x\n", count
, fmt
.cfFormat
, src_fmt
.cfFormat
);
570 ok(fmt
.dwAspect
== src_fmt
.dwAspect
, "%d: %08x %08x\n", count
, fmt
.dwAspect
, src_fmt
.dwAspect
);
571 ok(fmt
.lindex
== src_fmt
.lindex
, "%d: %08x %08x\n", count
, fmt
.lindex
, src_fmt
.lindex
);
572 ok(fmt
.tymed
== src_fmt
.tymed
, "%d: %08x %08x\n", count
, fmt
.tymed
, src_fmt
.tymed
);
575 ok(src_fmt
.ptd
!= NULL
, "%d: expected non-NULL\n", count
);
576 CoTaskMemFree(fmt
.ptd
);
577 CoTaskMemFree(src_fmt
.ptd
);
582 ok(hr
== S_FALSE
, "%d: got %08x\n", count
, hr
);
586 hr
= IEnumFORMATETC_Next(src_enum
, 1, &src_fmt
, NULL
);
587 ok(hr
== S_FALSE
, "%d: got %08x\n", count
, hr
);
588 IEnumFORMATETC_Release(src_enum
);
591 hr
= IEnumFORMATETC_Reset(enum_fmt
);
592 ok(hr
== S_OK
, "got %08x\n", hr
);
594 IEnumFORMATETC_Release(enum_fmt
);
595 IDataObject_Release(data
);
598 static void test_cf_dataobject(IDataObject
*data
)
601 UINT cf_dataobject
= RegisterClipboardFormatA("DataObject");
602 UINT cf_ole_priv_data
= RegisterClipboardFormatA("Ole Private Data");
603 BOOL found_dataobject
= FALSE
, found_priv_data
= FALSE
;
608 cf
= EnumClipboardFormats(cf
);
609 if(cf
== cf_dataobject
)
611 HGLOBAL h
= GetClipboardData(cf
);
612 HWND
*ptr
= GlobalLock(h
);
613 DWORD size
= GlobalSize(h
);
614 HWND clip_owner
= GetClipboardOwner();
616 found_dataobject
= TRUE
;
617 ok(size
>= sizeof(*ptr
), "size %d\n", size
);
619 ok(*ptr
== clip_owner
, "hwnd %p clip_owner %p\n", *ptr
, clip_owner
);
620 else /* ole clipboard flushed */
621 ok(*ptr
== NULL
, "hwnd %p\n", *ptr
);
624 else if(cf
== cf_ole_priv_data
)
626 found_priv_data
= TRUE
;
629 HGLOBAL h
= GetClipboardData(cf
);
630 DWORD
*ptr
= GlobalLock(h
);
631 DWORD size
= GlobalSize(h
);
634 win_skip("Ole Private Data in win9x format\n");
638 IEnumFORMATETC
*enum_fmt
;
644 BOOL first_use_of_cf
;
654 struct formatetcetc fmts
[1];
655 } *priv
= (struct priv_data
*)ptr
;
656 CLIPFORMAT cfs_seen
[10];
658 hr
= IDataObject_EnumFormatEtc(data
, DATADIR_GET
, &enum_fmt
);
659 ok(hr
== S_OK
, "got %08x\n", hr
);
660 fmt_ptr
= priv
->fmts
;
662 while(IEnumFORMATETC_Next(enum_fmt
, 1, &fmt
, NULL
) == S_OK
)
665 BOOL seen_cf
= FALSE
;
667 ok(fmt_ptr
->fmt
.cfFormat
== fmt
.cfFormat
,
668 "got %08x expected %08x\n", fmt_ptr
->fmt
.cfFormat
, fmt
.cfFormat
);
669 ok(fmt_ptr
->fmt
.dwAspect
== fmt
.dwAspect
, "got %08x expected %08x\n",
670 fmt_ptr
->fmt
.dwAspect
, fmt
.dwAspect
);
671 ok(fmt_ptr
->fmt
.lindex
== fmt
.lindex
, "got %08x expected %08x\n",
672 fmt_ptr
->fmt
.lindex
, fmt
.lindex
);
673 ok(fmt_ptr
->fmt
.tymed
== fmt
.tymed
, "got %08x expected %08x\n",
674 fmt_ptr
->fmt
.tymed
, fmt
.tymed
);
675 for(i
= 0; i
< count
; i
++)
676 if(fmt_ptr
->fmt
.cfFormat
== cfs_seen
[i
])
681 cfs_seen
[count
] = fmt
.cfFormat
;
682 ok(fmt_ptr
->first_use_of_cf
== seen_cf
? FALSE
: TRUE
, "got %08x expected %08x\n",
683 fmt_ptr
->first_use_of_cf
, !seen_cf
);
684 ok(fmt_ptr
->res
[0] == 0, "got %08x\n", fmt_ptr
->res
[1]);
685 ok(fmt_ptr
->res
[1] == 0, "got %08x\n", fmt_ptr
->res
[2]);
688 DVTARGETDEVICE
*target
;
690 ok(fmt_ptr
->fmt
.ptd
!= NULL
, "target device offset zero\n");
691 target
= (DVTARGETDEVICE
*)((char*)priv
+ (DWORD
)fmt_ptr
->fmt
.ptd
);
692 ok(!memcmp(target
, fmt
.ptd
, fmt
.ptd
->tdSize
), "target devices differ\n");
693 CoTaskMemFree(fmt
.ptd
);
698 ok(priv
->res1
== 0, "got %08x\n", priv
->res1
);
699 ok(priv
->res2
== 1, "got %08x\n", priv
->res2
);
700 ok(priv
->count
== count
, "got %08x expected %08x\n", priv
->count
, count
);
701 ok(priv
->res3
[0] == 0, "got %08x\n", priv
->res3
[0]);
702 ok(priv
->res3
[1] == 0, "got %08x\n", priv
->res3
[1]);
705 IEnumFORMATETC_Release(enum_fmt
);
709 else if(cf
== cf_stream
)
715 DataObjectImpl_GetDataHere_calls
= 0;
716 h
= GetClipboardData(cf
);
717 ok(DataObjectImpl_GetDataHere_calls
== 1, "got %d\n", DataObjectImpl_GetDataHere_calls
);
719 size
= GlobalSize(h
);
720 ok(size
== strlen(cmpl_stm_data
), "expected %d got %d\n", lstrlenA(cmpl_stm_data
), size
);
721 ok(!memcmp(ptr
, cmpl_stm_data
, size
), "mismatch\n");
724 else if(cf
== cf_global
)
730 DataObjectImpl_GetDataHere_calls
= 0;
731 h
= GetClipboardData(cf
);
732 ok(DataObjectImpl_GetDataHere_calls
== 0, "got %d\n", DataObjectImpl_GetDataHere_calls
);
734 size
= GlobalSize(h
);
735 ok(size
== strlen(cmpl_text_data
) + 1, "expected %d got %d\n", lstrlenA(cmpl_text_data
) + 1, size
);
736 ok(!memcmp(ptr
, cmpl_text_data
, size
), "mismatch\n");
741 ok(found_dataobject
, "didn't find cf_dataobject\n");
742 ok(found_priv_data
, "didn't find cf_ole_priv_data\n");
745 static void test_set_clipboard(void)
749 LPDATAOBJECT data1
, data2
, data_cmpl
;
752 cf_stream
= RegisterClipboardFormatA("stream format");
753 cf_storage
= RegisterClipboardFormatA("storage format");
754 cf_global
= RegisterClipboardFormatA("global format");
755 cf_another
= RegisterClipboardFormatA("another format");
756 cf_onemore
= RegisterClipboardFormatA("one more format");
758 hr
= DataObjectImpl_CreateText("data1", &data1
);
759 ok(SUCCEEDED(hr
), "Failed to create data1 object: 0x%08x\n", hr
);
762 hr
= DataObjectImpl_CreateText("data2", &data2
);
763 ok(SUCCEEDED(hr
), "Failed to create data2 object: 0x%08x\n", hr
);
766 hr
= DataObjectImpl_CreateComplex(&data_cmpl
);
767 ok(SUCCEEDED(hr
), "Failed to create complex data object: 0x%08x\n", hr
);
771 hr
= OleSetClipboard(data1
);
772 ok(hr
== CO_E_NOTINITIALIZED
, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr
);
775 hr
= OleSetClipboard(data1
);
776 ok(hr
== CO_E_NOTINITIALIZED
||
777 hr
== CLIPBRD_E_CANT_SET
, /* win9x */
778 "OleSetClipboard should have failed with "
779 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr
);
782 hr
= OleInitialize(NULL
);
783 ok(hr
== S_OK
, "OleInitialize failed with error 0x%08x\n", hr
);
785 hr
= OleSetClipboard(data1
);
786 ok(hr
== S_OK
, "failed to set clipboard to data1, hr = 0x%08x\n", hr
);
788 test_cf_dataobject(data1
);
790 hr
= OleIsCurrentClipboard(data1
);
791 ok(hr
== S_OK
, "expected current clipboard to be data1, hr = 0x%08x\n", hr
);
792 hr
= OleIsCurrentClipboard(data2
);
793 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
794 hr
= OleIsCurrentClipboard(NULL
);
795 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
797 test_get_clipboard();
799 hr
= OleSetClipboard(data2
);
800 ok(hr
== S_OK
, "failed to set clipboard to data2, hr = 0x%08x\n", hr
);
801 hr
= OleIsCurrentClipboard(data1
);
802 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
803 hr
= OleIsCurrentClipboard(data2
);
804 ok(hr
== S_OK
, "expected current clipboard to be data2, hr = 0x%08x\n", hr
);
805 hr
= OleIsCurrentClipboard(NULL
);
806 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
808 /* put a format directly onto the clipboard to show
809 OleFlushClipboard doesn't empty the clipboard */
810 hblob
= GlobalAlloc(GMEM_DDESHARE
|GMEM_MOVEABLE
|GMEM_ZEROINIT
, 10);
812 h
= SetClipboardData(cf_onemore
, hblob
);
813 ok(h
== hblob
, "got %p\n", h
);
814 h
= GetClipboardData(cf_onemore
);
816 broken(h
!= NULL
), /* win9x */
820 hr
= OleFlushClipboard();
821 ok(hr
== S_OK
, "failed to flush clipboard, hr = 0x%08x\n", hr
);
822 hr
= OleIsCurrentClipboard(data1
);
823 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
824 hr
= OleIsCurrentClipboard(data2
);
825 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
826 hr
= OleIsCurrentClipboard(NULL
);
827 ok(hr
== S_FALSE
, "expect S_FALSE, hr = 0x%08x\n", hr
);
829 /* format should survive the flush */
831 h
= GetClipboardData(cf_onemore
);
833 broken(h
!= NULL
), /* win9x */
837 test_cf_dataobject(NULL
);
839 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
842 h
= GetClipboardData(cf_onemore
);
843 ok(h
== NULL
, "got %p\n", h
);
846 trace("setting complex\n");
847 hr
= OleSetClipboard(data_cmpl
);
848 ok(hr
== S_OK
, "failed to set clipboard to complex data, hr = 0x%08x\n", hr
);
849 test_cf_dataobject(data_cmpl
);
850 test_enum_fmtetc(data_cmpl
);
852 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
854 test_enum_fmtetc(NULL
);
856 ref
= IDataObject_Release(data1
);
857 ok(ref
== 0, "expected data1 ref=0, got %d\n", ref
);
858 ref
= IDataObject_Release(data2
);
859 ok(ref
== 0, "expected data2 ref=0, got %d\n", ref
);
860 ref
= IDataObject_Release(data_cmpl
);
861 ok(ref
== 0, "expected data_cmpl ref=0, got %d\n", ref
);
866 static inline ULONG
count_refs(IDataObject
*d
)
868 IDataObject_AddRef(d
);
869 return IDataObject_Release(d
);
872 static void test_consumer_refs(void)
875 IDataObject
*src
, *src2
, *get1
, *get2
, *get3
;
876 ULONG refs
, old_refs
;
880 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
884 /* First show that each clipboard state results in
885 a different data object */
887 hr
= DataObjectImpl_CreateText("data1", &src
);
888 ok(hr
== S_OK
, "got %08x\n", hr
);
889 hr
= DataObjectImpl_CreateText("data2", &src2
);
890 ok(hr
== S_OK
, "got %08x\n", hr
);
892 hr
= OleSetClipboard(src
);
893 ok(hr
== S_OK
, "got %08x\n", hr
);
895 hr
= OleGetClipboard(&get1
);
896 ok(hr
== S_OK
, "got %08x\n", hr
);
898 hr
= OleGetClipboard(&get2
);
899 ok(hr
== S_OK
, "got %08x\n", hr
);
901 ok(get1
== get2
, "data objects differ\n");
902 refs
= IDataObject_Release(get2
);
903 ok(refs
== 1, "got %d\n", refs
);
907 DataObjectImpl_GetData_calls
= 0;
908 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
909 ok(hr
== S_OK
, "got %08x\n", hr
);
910 ok(DataObjectImpl_GetData_calls
== 0, "GetData called\n");
911 ReleaseStgMedium(&med
);
913 hr
= OleGetClipboard(&get2
);
914 ok(hr
== S_OK
, "got %08x\n", hr
);
916 ok(get1
!= get2
, "data objects match\n");
918 OleSetClipboard(NULL
);
920 hr
= OleGetClipboard(&get3
);
921 ok(hr
== S_OK
, "got %08x\n", hr
);
923 ok(get1
!= get3
, "data objects match\n");
924 ok(get2
!= get3
, "data objects match\n");
926 IDataObject_Release(get3
);
927 IDataObject_Release(get2
);
928 IDataObject_Release(get1
);
930 /* Now call GetData before the flush and show that this
931 takes a ref on our src data obj. */
933 hr
= OleSetClipboard(src
);
934 ok(hr
== S_OK
, "got %08x\n", hr
);
936 old_refs
= count_refs(src
);
938 hr
= OleGetClipboard(&get1
);
939 ok(hr
== S_OK
, "got %08x\n", hr
);
941 refs
= count_refs(src
);
942 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
944 DataObjectImpl_GetData_calls
= 0;
945 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
946 ok(hr
== S_OK
, "got %08x\n", hr
);
947 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
948 ReleaseStgMedium(&med
);
949 refs
= count_refs(src
);
950 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
954 DataObjectImpl_GetData_calls
= 0;
955 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
956 ok(hr
== S_OK
, "got %08x\n", hr
);
957 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
958 ReleaseStgMedium(&med
);
960 refs
= count_refs(src
);
961 ok(refs
== 2, "%d\n", refs
);
963 IDataObject_Release(get1
);
965 refs
= count_refs(src
);
966 ok(refs
== 1, "%d\n", refs
);
968 /* Now set a second src object before the call to GetData
969 and show that GetData calls that second src. */
971 hr
= OleSetClipboard(src
);
972 ok(hr
== S_OK
, "got %08x\n", hr
);
974 old_refs
= count_refs(src
);
976 hr
= OleGetClipboard(&get1
);
977 ok(hr
== S_OK
, "got %08x\n", hr
);
979 refs
= count_refs(src
);
980 ok(refs
== old_refs
, "%d %d\n", refs
, old_refs
);
982 hr
= OleSetClipboard(src2
);
983 ok(hr
== S_OK
, "got %08x\n", hr
);
985 old_refs
= count_refs(src2
);
987 DataObjectImpl_GetData_calls
= 0;
988 hr
= IDataObject_GetData(get1
, &fmt
, &med
);
989 ok(hr
== S_OK
, "got %08x\n", hr
);
990 ok(DataObjectImpl_GetData_calls
== 1, "GetData not called\n");
991 ReleaseStgMedium(&med
);
993 refs
= count_refs(src
);
994 ok(refs
== 1, "%d\n", refs
);
995 refs
= count_refs(src2
);
996 ok(refs
== old_refs
+ 1, "%d %d\n", refs
, old_refs
);
998 OleSetClipboard(NULL
);
1000 refs
= count_refs(src2
);
1001 ok(refs
== 2, "%d\n", refs
);
1003 IDataObject_Release(get1
);
1005 IDataObject_Release(src2
);
1006 IDataObject_Release(src
);
1011 static void test_flushed_getdata(void)
1014 IDataObject
*src
, *get
;
1020 OleInitialize(NULL
);
1022 hr
= DataObjectImpl_CreateComplex(&src
);
1023 ok(hr
== S_OK
, "got %08x\n", hr
);
1025 hr
= OleSetClipboard(src
);
1026 ok(hr
== S_OK
, "got %08x\n", hr
);
1028 hr
= OleFlushClipboard();
1029 ok(hr
== S_OK
, "got %08x\n", hr
);
1031 hr
= OleGetClipboard(&get
);
1032 ok(hr
== S_OK
, "got %08x\n", hr
);
1034 /* global format -> global & stream */
1036 InitFormatEtc(fmt
, CF_TEXT
, TYMED_HGLOBAL
);
1037 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1038 ok(hr
== S_OK
, "got %08x\n", hr
);
1039 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1040 ReleaseStgMedium(&med
);
1042 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTREAM
);
1043 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1044 ok(hr
== S_OK
, "got %08x\n", hr
);
1045 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1046 ReleaseStgMedium(&med
);
1048 InitFormatEtc(fmt
, CF_TEXT
, TYMED_ISTORAGE
);
1049 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1050 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1052 InitFormatEtc(fmt
, CF_TEXT
, 0xffff);
1053 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1054 ok(hr
== S_OK
, "got %08x\n", hr
);
1055 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1056 ReleaseStgMedium(&med
);
1058 /* stream format -> global & stream */
1060 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTREAM
);
1061 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1062 ok(hr
== S_OK
, "got %08x\n", hr
);
1063 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1064 ReleaseStgMedium(&med
);
1066 InitFormatEtc(fmt
, cf_stream
, TYMED_ISTORAGE
);
1067 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1068 ok(hr
== E_FAIL
, "got %08x\n", hr
);
1070 InitFormatEtc(fmt
, cf_stream
, TYMED_HGLOBAL
);
1071 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1072 ok(hr
== S_OK
, "got %08x\n", hr
);
1073 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1074 ReleaseStgMedium(&med
);
1076 InitFormatEtc(fmt
, cf_stream
, 0xffff);
1077 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1078 ok(hr
== S_OK
, "got %08x\n", hr
);
1079 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1080 ReleaseStgMedium(&med
);
1082 /* storage format -> global, stream & storage */
1084 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTORAGE
);
1085 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1086 ok(hr
== S_OK
, "got %08x\n", hr
);
1087 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1088 hr
= IStorage_Stat(med
.u
.pstg
, &stat
, STATFLAG_NONAME
);
1089 ok(hr
== S_OK
, "got %08x\n", hr
);
1090 ok(stat
.grfMode
== (STGM_SHARE_EXCLUSIVE
| STGM_READWRITE
), "got %08x\n", stat
.grfMode
);
1091 ReleaseStgMedium(&med
);
1093 InitFormatEtc(fmt
, cf_storage
, TYMED_ISTREAM
);
1094 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1095 ok(hr
== S_OK
, "got %08x\n", hr
);
1096 ok(med
.tymed
== TYMED_ISTREAM
, "got %x\n", med
.tymed
);
1097 ReleaseStgMedium(&med
);
1099 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
);
1100 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1101 ok(hr
== S_OK
, "got %08x\n", hr
);
1102 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1103 ReleaseStgMedium(&med
);
1105 InitFormatEtc(fmt
, cf_storage
, TYMED_HGLOBAL
| TYMED_ISTREAM
);
1106 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1107 ok(hr
== S_OK
, "got %08x\n", hr
);
1108 ok(med
.tymed
== TYMED_HGLOBAL
, "got %x\n", med
.tymed
);
1109 ReleaseStgMedium(&med
);
1111 InitFormatEtc(fmt
, cf_storage
, 0xffff);
1112 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1113 ok(hr
== S_OK
, "got %08x\n", hr
);
1114 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1115 ReleaseStgMedium(&med
);
1117 /* complex format with target device */
1119 InitFormatEtc(fmt
, cf_another
, 0xffff);
1120 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1121 todo_wine
ok(hr
== DV_E_FORMATETC
, "got %08x\n", hr
);
1123 InitFormatEtc(fmt
, cf_another
, 0xffff);
1124 memset(&dm
, 0, sizeof(dm
));
1125 dm
.dmSize
= sizeof(dm
);
1126 dm
.dmDriverExtra
= 0;
1127 lstrcpyW(dm
.dmDeviceName
, devname
);
1128 fmt
.ptd
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(devname
) + dm
.dmSize
+ dm
.dmDriverExtra
);
1129 fmt
.ptd
->tdSize
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
) + sizeof(devname
) + dm
.dmSize
+ dm
.dmDriverExtra
;
1130 fmt
.ptd
->tdDriverNameOffset
= FIELD_OFFSET(DVTARGETDEVICE
, tdData
);
1131 fmt
.ptd
->tdDeviceNameOffset
= 0;
1132 fmt
.ptd
->tdPortNameOffset
= 0;
1133 fmt
.ptd
->tdExtDevmodeOffset
= fmt
.ptd
->tdDriverNameOffset
+ sizeof(devname
);
1134 lstrcpyW((WCHAR
*)fmt
.ptd
->tdData
, devname
);
1135 memcpy(fmt
.ptd
->tdData
+ sizeof(devname
), &dm
, dm
.dmSize
+ dm
.dmDriverExtra
);
1137 hr
= IDataObject_GetData(get
, &fmt
, &med
);
1138 ok(hr
== S_OK
, "got %08x\n", hr
);
1139 ok(med
.tymed
== TYMED_ISTORAGE
, "got %x\n", med
.tymed
);
1140 ReleaseStgMedium(&med
);
1142 HeapFree(GetProcessHeap(), 0, fmt
.ptd
);
1145 IDataObject_Release(get
);
1146 IDataObject_Release(src
);
1150 START_TEST(clipboard
)
1152 test_set_clipboard();
1153 test_consumer_refs();
1154 test_flushed_getdata();