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
29 #include "wine/test.h"
31 #define InitFormatEtc(fe, cf, med) \
34 (fe).dwAspect=DVASPECT_CONTENT;\
40 typedef struct DataObjectImpl
{
41 const IDataObjectVtbl
*lpVtbl
;
50 typedef struct EnumFormatImpl
{
51 const IEnumFORMATETCVtbl
*lpVtbl
;
60 static BOOL expect_DataObjectImpl_QueryGetData
= TRUE
;
61 static ULONG DataObjectImpl_GetData_calls
= 0;
63 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT size
, LPENUMFORMATETC
*lplpformatetc
);
65 static HRESULT WINAPI
EnumFormatImpl_QueryInterface(IEnumFORMATETC
*iface
, REFIID riid
, LPVOID
*ppvObj
)
67 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
69 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumFORMATETC
)) {
70 IEnumFORMATETC_AddRef(iface
);
71 *ppvObj
= (LPVOID
)This
;
78 static ULONG WINAPI
EnumFormatImpl_AddRef(IEnumFORMATETC
*iface
)
80 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
81 LONG ref
= InterlockedIncrement(&This
->ref
);
85 static ULONG WINAPI
EnumFormatImpl_Release(IEnumFORMATETC
*iface
)
87 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
88 ULONG ref
= InterlockedDecrement(&This
->ref
);
91 HeapFree(GetProcessHeap(), 0, This
->fmtetc
);
92 HeapFree(GetProcessHeap(), 0, This
);
98 static HRESULT WINAPI
EnumFormatImpl_Next(IEnumFORMATETC
*iface
, ULONG celt
,
99 FORMATETC
*rgelt
, ULONG
*pceltFetched
)
101 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
107 count
= min(celt
, This
->fmtetc_cnt
-This
->cur
);
109 memcpy(rgelt
, This
->fmtetc
+This
->cur
, count
*sizeof(FORMATETC
));
113 *pceltFetched
= count
;
114 return count
== celt
? S_OK
: S_FALSE
;
117 static HRESULT WINAPI
EnumFormatImpl_Skip(IEnumFORMATETC
*iface
, ULONG celt
)
119 ok(0, "unexpected call\n");
123 static HRESULT WINAPI
EnumFormatImpl_Reset(IEnumFORMATETC
*iface
)
125 EnumFormatImpl
*This
= (EnumFormatImpl
*)iface
;
131 static HRESULT WINAPI
EnumFormatImpl_Clone(IEnumFORMATETC
*iface
, IEnumFORMATETC
**ppenum
)
133 ok(0, "unexpected call\n");
137 static const IEnumFORMATETCVtbl VT_EnumFormatImpl
= {
138 EnumFormatImpl_QueryInterface
,
139 EnumFormatImpl_AddRef
,
140 EnumFormatImpl_Release
,
143 EnumFormatImpl_Reset
,
147 static HRESULT
EnumFormatImpl_Create(FORMATETC
*fmtetc
, UINT fmtetc_cnt
, IEnumFORMATETC
**lplpformatetc
)
151 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl
));
152 ret
->lpVtbl
= &VT_EnumFormatImpl
;
155 ret
->fmtetc_cnt
= fmtetc_cnt
;
156 ret
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt
*sizeof(FORMATETC
));
157 memcpy(ret
->fmtetc
, fmtetc
, fmtetc_cnt
*sizeof(FORMATETC
));
158 *lplpformatetc
= (LPENUMFORMATETC
)ret
;
162 static HRESULT WINAPI
DataObjectImpl_QueryInterface(IDataObject
*iface
, REFIID riid
, LPVOID
*ppvObj
)
164 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
166 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDataObject
)) {
167 IDataObject_AddRef(iface
);
168 *ppvObj
= (LPVOID
)This
;
172 return E_NOINTERFACE
;
175 static ULONG WINAPI
DataObjectImpl_AddRef(IDataObject
* iface
)
177 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
178 ULONG ref
= InterlockedIncrement(&This
->ref
);
182 static ULONG WINAPI
DataObjectImpl_Release(IDataObject
* iface
)
184 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
185 ULONG ref
= InterlockedDecrement(&This
->ref
);
188 if(This
->text
) GlobalFree(This
->text
);
189 if(This
->fmtetc
) GlobalFree(This
->fmtetc
);
190 HeapFree(GetProcessHeap(), 0, This
);
196 static HRESULT WINAPI
DataObjectImpl_GetData(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
198 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
200 DataObjectImpl_GetData_calls
++;
202 if(pformatetc
->lindex
!= -1)
205 if(!(pformatetc
->tymed
& TYMED_HGLOBAL
))
208 if(This
->text
&& pformatetc
->cfFormat
== CF_TEXT
)
209 U(*pmedium
).hGlobal
= This
->text
;
211 return DV_E_FORMATETC
;
213 pmedium
->tymed
= TYMED_HGLOBAL
;
214 pmedium
->pUnkForRelease
= (LPUNKNOWN
)iface
;
215 IUnknown_AddRef(pmedium
->pUnkForRelease
);
219 static HRESULT WINAPI
DataObjectImpl_GetDataHere(IDataObject
* iface
, FORMATETC
*pformatetc
, STGMEDIUM
*pmedium
)
221 ok(0, "unexpected call\n");
225 static HRESULT WINAPI
DataObjectImpl_QueryGetData(IDataObject
* iface
, FORMATETC
*pformatetc
)
227 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
229 BOOL foundFormat
= FALSE
;
231 if (!expect_DataObjectImpl_QueryGetData
)
232 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
234 if(pformatetc
->lindex
!= -1)
237 for(i
=0; i
<This
->fmtetc_cnt
; i
++) {
238 if(This
->fmtetc
[i
].cfFormat
== pformatetc
->cfFormat
) {
240 if(This
->fmtetc
[i
].tymed
== pformatetc
->tymed
)
244 return foundFormat
?DV_E_FORMATETC
:DV_E_TYMED
;
247 static HRESULT WINAPI
DataObjectImpl_GetCanonicalFormatEtc(IDataObject
* iface
, FORMATETC
*pformatectIn
,
248 FORMATETC
*pformatetcOut
)
250 ok(0, "unexpected call\n");
254 static HRESULT WINAPI
DataObjectImpl_SetData(IDataObject
* iface
, FORMATETC
*pformatetc
,
255 STGMEDIUM
*pmedium
, BOOL fRelease
)
257 ok(0, "unexpected call\n");
261 static HRESULT WINAPI
DataObjectImpl_EnumFormatEtc(IDataObject
* iface
, DWORD dwDirection
,
262 IEnumFORMATETC
**ppenumFormatEtc
)
264 DataObjectImpl
*This
= (DataObjectImpl
*)iface
;
266 if(dwDirection
!= DATADIR_GET
) {
267 ok(0, "unexpected direction %d\n", dwDirection
);
270 return EnumFormatImpl_Create(This
->fmtetc
, This
->fmtetc_cnt
, ppenumFormatEtc
);
273 static HRESULT WINAPI
DataObjectImpl_DAdvise(IDataObject
* iface
, FORMATETC
*pformatetc
, DWORD advf
,
274 IAdviseSink
*pAdvSink
, DWORD
*pdwConnection
)
276 ok(0, "unexpected call\n");
280 static HRESULT WINAPI
DataObjectImpl_DUnadvise(IDataObject
* iface
, DWORD dwConnection
)
282 ok(0, "unexpected call\n");
286 static HRESULT WINAPI
DataObjectImpl_EnumDAdvise(IDataObject
* iface
, IEnumSTATDATA
**ppenumAdvise
)
288 ok(0, "unexpected call\n");
292 static const IDataObjectVtbl VT_DataObjectImpl
=
294 DataObjectImpl_QueryInterface
,
295 DataObjectImpl_AddRef
,
296 DataObjectImpl_Release
,
297 DataObjectImpl_GetData
,
298 DataObjectImpl_GetDataHere
,
299 DataObjectImpl_QueryGetData
,
300 DataObjectImpl_GetCanonicalFormatEtc
,
301 DataObjectImpl_SetData
,
302 DataObjectImpl_EnumFormatEtc
,
303 DataObjectImpl_DAdvise
,
304 DataObjectImpl_DUnadvise
,
305 DataObjectImpl_EnumDAdvise
308 static HRESULT
DataObjectImpl_CreateText(LPCSTR text
, LPDATAOBJECT
*lplpdataobj
)
312 obj
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl
));
313 obj
->lpVtbl
= &VT_DataObjectImpl
;
315 obj
->text
= GlobalAlloc(GMEM_MOVEABLE
, strlen(text
) + 1);
316 strcpy(GlobalLock(obj
->text
), text
);
317 GlobalUnlock(obj
->text
);
320 obj
->fmtetc
= HeapAlloc(GetProcessHeap(), 0, obj
->fmtetc_cnt
*sizeof(FORMATETC
));
321 InitFormatEtc(obj
->fmtetc
[0], CF_TEXT
, TYMED_HGLOBAL
);
323 *lplpdataobj
= (LPDATAOBJECT
)obj
;
327 static void test_get_clipboard(void)
330 IDataObject
*data_obj
;
334 hr
= OleGetClipboard(NULL
);
335 ok(hr
== E_INVALIDARG
, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr
);
337 hr
= OleGetClipboard(&data_obj
);
338 ok(hr
== S_OK
, "OleGetClipboard failed with error 0x%08x\n", hr
);
340 /* test IDataObject_QueryGetData */
342 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
343 expect_DataObjectImpl_QueryGetData
= FALSE
;
345 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
346 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
347 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
349 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
350 fmtetc
.dwAspect
= 0xdeadbeef;
351 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
352 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
354 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
355 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
356 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
357 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
359 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
361 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
362 ok(hr
== DV_E_FORMATETC
, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
364 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
365 fmtetc
.cfFormat
= CF_RIFF
;
366 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
367 ok(hr
== DV_E_CLIPFORMAT
, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr
);
369 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
370 fmtetc
.tymed
= TYMED_FILE
;
371 hr
= IDataObject_QueryGetData(data_obj
, &fmtetc
);
372 ok(hr
== S_OK
, "IDataObject_QueryGetData failed with error 0x%08x\n", hr
);
374 expect_DataObjectImpl_QueryGetData
= TRUE
;
376 /* test IDataObject_GetData */
378 DataObjectImpl_GetData_calls
= 0;
380 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
381 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
382 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
383 ReleaseStgMedium(&stgmedium
);
385 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
386 fmtetc
.dwAspect
= 0xdeadbeef;
387 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
388 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
389 ReleaseStgMedium(&stgmedium
);
391 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
392 fmtetc
.dwAspect
= DVASPECT_THUMBNAIL
;
393 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
394 ok(hr
== S_OK
, "IDataObject_GetData failed with error 0x%08x\n", hr
);
395 ReleaseStgMedium(&stgmedium
);
397 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
399 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
401 ok(hr
== DV_E_FORMATETC
, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
403 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
404 fmtetc
.cfFormat
= CF_RIFF
;
405 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
406 ok(hr
== DV_E_FORMATETC
, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr
);
408 InitFormatEtc(fmtetc
, CF_TEXT
, TYMED_HGLOBAL
);
409 fmtetc
.tymed
= TYMED_FILE
;
410 hr
= IDataObject_GetData(data_obj
, &fmtetc
, &stgmedium
);
411 ok(hr
== DV_E_TYMED
, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr
);
413 ok(DataObjectImpl_GetData_calls
== 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls
);
415 IDataObject_Release(data_obj
);
418 static void test_set_clipboard(void)
422 LPDATAOBJECT data1
, data2
;
423 hr
= DataObjectImpl_CreateText("data1", &data1
);
424 ok(SUCCEEDED(hr
), "Failed to create data1 object: 0x%08x\n", hr
);
427 hr
= DataObjectImpl_CreateText("data2", &data2
);
428 ok(SUCCEEDED(hr
), "Failed to create data2 object: 0x%08x\n", hr
);
432 hr
= OleSetClipboard(data1
);
434 ok(hr
== CO_E_NOTINITIALIZED
, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr
);
437 hr
= OleSetClipboard(data1
);
439 ok(hr
== CO_E_NOTINITIALIZED
||
440 hr
== CLIPBRD_E_CANT_SET
, /* win9x */
441 "OleSetClipboard should have failed with "
442 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr
);
445 hr
= OleInitialize(NULL
);
446 ok(hr
== S_OK
, "OleInitialize failed with error 0x%08x\n", hr
);
448 hr
= OleSetClipboard(data1
);
449 ok(hr
== S_OK
, "failed to set clipboard to data1, hr = 0x%08x\n", hr
);
450 hr
= OleIsCurrentClipboard(data1
);
451 ok(hr
== S_OK
, "expected current clipboard to be data1, hr = 0x%08x\n", hr
);
452 hr
= OleIsCurrentClipboard(data2
);
453 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
455 test_get_clipboard();
457 hr
= OleSetClipboard(data2
);
458 ok(hr
== S_OK
, "failed to set clipboard to data2, hr = 0x%08x\n", hr
);
459 hr
= OleIsCurrentClipboard(data1
);
460 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
461 hr
= OleIsCurrentClipboard(data2
);
462 ok(hr
== S_OK
, "expected current clipboard to be data2, hr = 0x%08x\n", hr
);
464 hr
= OleFlushClipboard();
465 ok(hr
== S_OK
, "failed to flush clipboard, hr = 0x%08x\n", hr
);
466 hr
= OleIsCurrentClipboard(data1
);
467 ok(hr
== S_FALSE
, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr
);
468 hr
= OleIsCurrentClipboard(data2
);
469 ok(hr
== S_FALSE
, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr
);
471 ok(OleSetClipboard(NULL
) == S_OK
, "failed to clear clipboard, hr = 0x%08x\n", hr
);
473 ref
= IDataObject_Release(data1
);
474 ok(ref
== 0, "expected data1 ref=0, got %d\n", ref
);
475 ref
= IDataObject_Release(data2
);
476 ok(ref
== 0, "expected data2 ref=0, got %d\n", ref
);
482 START_TEST(clipboard
)
484 test_set_clipboard();