ole32: Fix return value for DefaultHandler_GetMiscStatus.
[wine] / dlls / ole32 / tests / clipboard.c
1 /*
2  * Clipboard unit tests
3  *
4  * Copyright 2006 Kevin Koltzau
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #define COBJMACROS
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28
29 #include "wine/test.h"
30
31 #define InitFormatEtc(fe, cf, med) \
32         {\
33         (fe).cfFormat=cf;\
34         (fe).dwAspect=DVASPECT_CONTENT;\
35         (fe).ptd=NULL;\
36         (fe).tymed=med;\
37         (fe).lindex=-1;\
38         };
39
40 typedef struct DataObjectImpl {
41     const IDataObjectVtbl *lpVtbl;
42     LONG ref;
43
44     FORMATETC *fmtetc;
45     UINT fmtetc_cnt;
46
47     HANDLE text;
48 } DataObjectImpl;
49
50 typedef struct EnumFormatImpl {
51     const IEnumFORMATETCVtbl *lpVtbl;
52     LONG ref;
53
54     FORMATETC *fmtetc;
55     UINT fmtetc_cnt;
56
57     UINT cur;
58 } EnumFormatImpl;
59
60 static BOOL expect_DataObjectImpl_QueryGetData = TRUE;
61 static ULONG DataObjectImpl_GetData_calls = 0;
62
63 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
64
65 static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
66 {
67     EnumFormatImpl *This = (EnumFormatImpl*)iface;
68
69     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) {
70         IEnumFORMATETC_AddRef(iface);
71         *ppvObj = (LPVOID)This;
72         return S_OK;
73     }
74     *ppvObj = NULL;
75     return E_NOINTERFACE;
76 }
77
78 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
79 {
80     EnumFormatImpl *This = (EnumFormatImpl*)iface;
81     LONG ref = InterlockedIncrement(&This->ref);
82     return ref;
83 }
84
85 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
86 {
87     EnumFormatImpl *This = (EnumFormatImpl*)iface;
88     ULONG ref = InterlockedDecrement(&This->ref);
89
90     if(!ref) {
91         HeapFree(GetProcessHeap(), 0, This->fmtetc);
92         HeapFree(GetProcessHeap(), 0, This);
93     }
94
95     return ref;
96 }
97
98 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
99                                           FORMATETC *rgelt, ULONG *pceltFetched)
100 {
101     EnumFormatImpl *This = (EnumFormatImpl*)iface;
102     ULONG count = 0;
103
104     if(!rgelt)
105         return E_INVALIDARG;
106
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;
111     }
112     if(pceltFetched)
113         *pceltFetched = count;
114     return count == celt ? S_OK : S_FALSE;
115 }
116
117 static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt)
118 {
119     ok(0, "unexpected call\n");
120     return E_NOTIMPL;
121 }
122
123 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
124 {
125     EnumFormatImpl *This = (EnumFormatImpl*)iface;
126
127     This->cur = 0;
128     return S_OK;
129 }
130
131 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
132 {
133     ok(0, "unexpected call\n");
134     return E_NOTIMPL;
135 }
136
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
145 };
146
147 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
148 {
149     EnumFormatImpl *ret;
150
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;
160 }
161
162 static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj)
163 {
164     DataObjectImpl *This = (DataObjectImpl*)iface;
165
166     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) {
167         IDataObject_AddRef(iface);
168         *ppvObj = (LPVOID)This;
169         return S_OK;
170     }
171     *ppvObj = NULL;
172     return E_NOINTERFACE;
173 }
174
175 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
176 {
177     DataObjectImpl *This = (DataObjectImpl*)iface;
178     ULONG ref = InterlockedIncrement(&This->ref);
179     return ref;
180 }
181
182 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
183 {
184     DataObjectImpl *This = (DataObjectImpl*)iface;
185     ULONG ref = InterlockedDecrement(&This->ref);
186
187     if(!ref) {
188         if(This->text) GlobalFree(This->text);
189         if(This->fmtetc) GlobalFree(This->fmtetc);
190         HeapFree(GetProcessHeap(), 0, This);
191     }
192
193     return ref;
194 }
195
196 static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
197 {
198     DataObjectImpl *This = (DataObjectImpl*)iface;
199
200     DataObjectImpl_GetData_calls++;
201
202     if(pformatetc->lindex != -1)
203         return DV_E_FORMATETC;
204
205     if(!(pformatetc->tymed & TYMED_HGLOBAL))
206         return DV_E_TYMED;
207
208     if(This->text && pformatetc->cfFormat == CF_TEXT)
209         U(*pmedium).hGlobal = This->text;
210     else
211         return DV_E_FORMATETC;
212
213     pmedium->tymed = TYMED_HGLOBAL;
214     pmedium->pUnkForRelease = (LPUNKNOWN)iface;
215     IUnknown_AddRef(pmedium->pUnkForRelease);
216     return S_OK;
217 }
218
219 static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
220 {
221     ok(0, "unexpected call\n");
222     return E_NOTIMPL;
223 }
224
225 static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc)
226 {
227     DataObjectImpl *This = (DataObjectImpl*)iface;
228     UINT i;
229     BOOL foundFormat = FALSE;
230
231     if (!expect_DataObjectImpl_QueryGetData)
232         ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
233
234     if(pformatetc->lindex != -1)
235         return DV_E_LINDEX;
236
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;
242         }
243     }
244     return foundFormat?DV_E_FORMATETC:DV_E_TYMED;
245 }
246
247 static HRESULT WINAPI DataObjectImpl_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC *pformatectIn,
248                                                            FORMATETC *pformatetcOut)
249 {
250     ok(0, "unexpected call\n");
251     return E_NOTIMPL;
252 }
253
254 static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc,
255                                              STGMEDIUM *pmedium, BOOL fRelease)
256 {
257     ok(0, "unexpected call\n");
258     return E_NOTIMPL;
259 }
260
261 static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwDirection,
262                                                    IEnumFORMATETC **ppenumFormatEtc)
263 {
264     DataObjectImpl *This = (DataObjectImpl*)iface;
265
266     if(dwDirection != DATADIR_GET) {
267         ok(0, "unexpected direction %d\n", dwDirection);
268         return E_NOTIMPL;
269     }
270     return EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenumFormatEtc);
271 }
272
273 static HRESULT WINAPI DataObjectImpl_DAdvise(IDataObject* iface, FORMATETC *pformatetc, DWORD advf,
274                                              IAdviseSink *pAdvSink, DWORD *pdwConnection)
275 {
276     ok(0, "unexpected call\n");
277     return E_NOTIMPL;
278 }
279
280 static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection)
281 {
282     ok(0, "unexpected call\n");
283     return E_NOTIMPL;
284 }
285
286 static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise)
287 {
288     ok(0, "unexpected call\n");
289     return E_NOTIMPL;
290 }
291
292 static const IDataObjectVtbl VT_DataObjectImpl =
293 {
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
306 };
307
308 static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
309 {
310     DataObjectImpl *obj;
311
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);
318
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);
322
323     *lplpdataobj = (LPDATAOBJECT)obj;
324     return S_OK;
325 }
326
327 static void test_get_clipboard(void)
328 {
329     HRESULT hr;
330     IDataObject *data_obj;
331     FORMATETC fmtetc;
332     STGMEDIUM stgmedium;
333
334     hr = OleGetClipboard(NULL);
335     ok(hr == E_INVALIDARG, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr);
336
337     hr = OleGetClipboard(&data_obj);
338     ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
339
340     /* test IDataObject_QueryGetData */
341
342     /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
343     expect_DataObjectImpl_QueryGetData = FALSE;
344
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);
348
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);
353
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);
358
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);
366
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);
371
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);
376
377     expect_DataObjectImpl_QueryGetData = TRUE;
378
379     /* test IDataObject_GetData */
380
381     DataObjectImpl_GetData_calls = 0;
382
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);
387
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);
393
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);
399
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)
405     {
406         /* undo the unexpected success */
407         DataObjectImpl_GetData_calls--;
408         ReleaseStgMedium(&stgmedium);
409     }
410
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);
415
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);
420
421     ok(DataObjectImpl_GetData_calls == 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls);
422
423     IDataObject_Release(data_obj);
424 }
425
426 static void test_set_clipboard(void)
427 {
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;
439
440     hr = OleSetClipboard(data1);
441     ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
442
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();
450
451     hr = OleInitialize(NULL);
452     ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
453
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);
462
463     test_get_clipboard();
464
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);
473
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);
482
483     ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
484
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);
489
490     OleUninitialize();
491 }
492
493
494 START_TEST(clipboard)
495 {
496     test_set_clipboard();
497 }