ole32: Fix return value for IDataObject_GetData.
[wine/wine64.git] / dlls / ole32 / tests / clipboard.c
blob8445f8b1c0fd96bf57ff1fa690df94ef1ccf6d89
1 /*
2 * Clipboard unit tests
4 * Copyright 2006 Kevin Koltzau
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
29 #include "wine/test.h"
31 #define InitFormatEtc(fe, cf, med) \
33 (fe).cfFormat=cf;\
34 (fe).dwAspect=DVASPECT_CONTENT;\
35 (fe).ptd=NULL;\
36 (fe).tymed=med;\
37 (fe).lindex=-1;\
40 typedef struct DataObjectImpl {
41 const IDataObjectVtbl *lpVtbl;
42 LONG ref;
44 FORMATETC *fmtetc;
45 UINT fmtetc_cnt;
47 HANDLE text;
48 } DataObjectImpl;
50 typedef struct EnumFormatImpl {
51 const IEnumFORMATETCVtbl *lpVtbl;
52 LONG ref;
54 FORMATETC *fmtetc;
55 UINT fmtetc_cnt;
57 UINT cur;
58 } EnumFormatImpl;
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;
72 return S_OK;
74 *ppvObj = NULL;
75 return E_NOINTERFACE;
78 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
80 EnumFormatImpl *This = (EnumFormatImpl*)iface;
81 LONG ref = InterlockedIncrement(&This->ref);
82 return ref;
85 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
87 EnumFormatImpl *This = (EnumFormatImpl*)iface;
88 ULONG ref = InterlockedDecrement(&This->ref);
90 if(!ref) {
91 HeapFree(GetProcessHeap(), 0, This->fmtetc);
92 HeapFree(GetProcessHeap(), 0, This);
95 return ref;
98 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
99 FORMATETC *rgelt, ULONG *pceltFetched)
101 EnumFormatImpl *This = (EnumFormatImpl*)iface;
102 ULONG count = 0;
104 if(!rgelt)
105 return E_INVALIDARG;
107 count = min(celt, This->fmtetc_cnt-This->cur);
108 if(count > 0) {
109 memcpy(rgelt, This->fmtetc+This->cur, count*sizeof(FORMATETC));
110 This->cur += count;
112 if(pceltFetched)
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");
120 return E_NOTIMPL;
123 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
125 EnumFormatImpl *This = (EnumFormatImpl*)iface;
127 This->cur = 0;
128 return S_OK;
131 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
133 ok(0, "unexpected call\n");
134 return E_NOTIMPL;
137 static const IEnumFORMATETCVtbl VT_EnumFormatImpl = {
138 EnumFormatImpl_QueryInterface,
139 EnumFormatImpl_AddRef,
140 EnumFormatImpl_Release,
141 EnumFormatImpl_Next,
142 EnumFormatImpl_Skip,
143 EnumFormatImpl_Reset,
144 EnumFormatImpl_Clone
147 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
149 EnumFormatImpl *ret;
151 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl));
152 ret->lpVtbl = &VT_EnumFormatImpl;
153 ret->ref = 1;
154 ret->cur = 0;
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;
159 return S_OK;
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;
169 return S_OK;
171 *ppvObj = NULL;
172 return E_NOINTERFACE;
175 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
177 DataObjectImpl *This = (DataObjectImpl*)iface;
178 ULONG ref = InterlockedIncrement(&This->ref);
179 return ref;
182 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
184 DataObjectImpl *This = (DataObjectImpl*)iface;
185 ULONG ref = InterlockedDecrement(&This->ref);
187 if(!ref) {
188 if(This->text) GlobalFree(This->text);
189 if(This->fmtetc) GlobalFree(This->fmtetc);
190 HeapFree(GetProcessHeap(), 0, This);
193 return ref;
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)
203 return DV_E_FORMATETC;
205 if(!(pformatetc->tymed & TYMED_HGLOBAL))
206 return DV_E_TYMED;
208 if(This->text && pformatetc->cfFormat == CF_TEXT)
209 U(*pmedium).hGlobal = This->text;
210 else
211 return DV_E_FORMATETC;
213 pmedium->tymed = TYMED_HGLOBAL;
214 pmedium->pUnkForRelease = (LPUNKNOWN)iface;
215 IUnknown_AddRef(pmedium->pUnkForRelease);
216 return S_OK;
219 static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
221 ok(0, "unexpected call\n");
222 return E_NOTIMPL;
225 static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc)
227 DataObjectImpl *This = (DataObjectImpl*)iface;
228 UINT i;
229 BOOL foundFormat = FALSE;
231 if (!expect_DataObjectImpl_QueryGetData)
232 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
234 if(pformatetc->lindex != -1)
235 return DV_E_LINDEX;
237 for(i=0; i<This->fmtetc_cnt; i++) {
238 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) {
239 foundFormat = TRUE;
240 if(This->fmtetc[i].tymed == pformatetc->tymed)
241 return S_OK;
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");
251 return E_NOTIMPL;
254 static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc,
255 STGMEDIUM *pmedium, BOOL fRelease)
257 ok(0, "unexpected call\n");
258 return E_NOTIMPL;
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);
268 return E_NOTIMPL;
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");
277 return E_NOTIMPL;
280 static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection)
282 ok(0, "unexpected call\n");
283 return E_NOTIMPL;
286 static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise)
288 ok(0, "unexpected call\n");
289 return E_NOTIMPL;
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)
310 DataObjectImpl *obj;
312 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
313 obj->lpVtbl = &VT_DataObjectImpl;
314 obj->ref = 1;
315 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1);
316 strcpy(GlobalLock(obj->text), text);
317 GlobalUnlock(obj->text);
319 obj->fmtetc_cnt = 1;
320 obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
321 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
323 *lplpdataobj = (LPDATAOBJECT)obj;
324 return S_OK;
327 static void test_get_clipboard(void)
329 HRESULT hr;
330 IDataObject *data_obj;
331 FORMATETC fmtetc;
332 STGMEDIUM stgmedium;
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);
360 fmtetc.lindex = 256;
361 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
362 ok(hr == DV_E_FORMATETC || broken(hr == S_OK),
363 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
364 if (hr == S_OK)
365 ReleaseStgMedium(&stgmedium);
367 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
368 fmtetc.cfFormat = CF_RIFF;
369 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
370 ok(hr == DV_E_CLIPFORMAT, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr);
372 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
373 fmtetc.tymed = TYMED_FILE;
374 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
375 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
377 expect_DataObjectImpl_QueryGetData = TRUE;
379 /* test IDataObject_GetData */
381 DataObjectImpl_GetData_calls = 0;
383 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
384 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
385 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
386 ReleaseStgMedium(&stgmedium);
388 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
389 fmtetc.dwAspect = 0xdeadbeef;
390 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
391 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
392 ReleaseStgMedium(&stgmedium);
394 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
395 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
396 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
397 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
398 ReleaseStgMedium(&stgmedium);
400 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
401 fmtetc.lindex = 256;
402 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
403 ok(hr == DV_E_FORMATETC || broken(hr == S_OK), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
404 if (hr == S_OK)
406 /* undo the unexpected success */
407 DataObjectImpl_GetData_calls--;
408 ReleaseStgMedium(&stgmedium);
411 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
412 fmtetc.cfFormat = CF_RIFF;
413 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
414 ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
416 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
417 fmtetc.tymed = TYMED_FILE;
418 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
419 ok(hr == DV_E_TYMED, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr);
421 ok(DataObjectImpl_GetData_calls == 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls);
423 IDataObject_Release(data_obj);
426 static void test_set_clipboard(void)
428 HRESULT hr;
429 ULONG ref;
430 LPDATAOBJECT data1, data2;
431 hr = DataObjectImpl_CreateText("data1", &data1);
432 ok(SUCCEEDED(hr), "Failed to create data1 object: 0x%08x\n", hr);
433 if(FAILED(hr))
434 return;
435 hr = DataObjectImpl_CreateText("data2", &data2);
436 ok(SUCCEEDED(hr), "Failed to create data2 object: 0x%08x\n", hr);
437 if(FAILED(hr))
438 return;
440 hr = OleSetClipboard(data1);
441 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
443 CoInitialize(NULL);
444 hr = OleSetClipboard(data1);
445 ok(hr == CO_E_NOTINITIALIZED ||
446 hr == CLIPBRD_E_CANT_SET, /* win9x */
447 "OleSetClipboard should have failed with "
448 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr);
449 CoUninitialize();
451 hr = OleInitialize(NULL);
452 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
454 hr = OleSetClipboard(data1);
455 ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr);
456 hr = OleIsCurrentClipboard(data1);
457 ok(hr == S_OK, "expected current clipboard to be data1, hr = 0x%08x\n", hr);
458 hr = OleIsCurrentClipboard(data2);
459 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
460 hr = OleIsCurrentClipboard(NULL);
461 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
463 test_get_clipboard();
465 hr = OleSetClipboard(data2);
466 ok(hr == S_OK, "failed to set clipboard to data2, hr = 0x%08x\n", hr);
467 hr = OleIsCurrentClipboard(data1);
468 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
469 hr = OleIsCurrentClipboard(data2);
470 ok(hr == S_OK, "expected current clipboard to be data2, hr = 0x%08x\n", hr);
471 hr = OleIsCurrentClipboard(NULL);
472 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
474 hr = OleFlushClipboard();
475 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
476 hr = OleIsCurrentClipboard(data1);
477 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
478 hr = OleIsCurrentClipboard(data2);
479 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
480 hr = OleIsCurrentClipboard(NULL);
481 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
483 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
485 ref = IDataObject_Release(data1);
486 ok(ref == 0, "expected data1 ref=0, got %d\n", ref);
487 ref = IDataObject_Release(data2);
488 ok(ref == 0, "expected data2 ref=0, got %d\n", ref);
490 OleUninitialize();
494 START_TEST(clipboard)
496 test_set_clipboard();