ole32/tests: Don't use the NONAMELESS* macros in the tests.
[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 HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
61
62 static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
63 {
64     EnumFormatImpl *This = (EnumFormatImpl*)iface;
65
66     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) {
67         IEnumFORMATETC_AddRef(iface);
68         *ppvObj = (LPVOID)This;
69         return S_OK;
70     }
71     *ppvObj = NULL;
72     return E_NOINTERFACE;
73 }
74
75 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
76 {
77     EnumFormatImpl *This = (EnumFormatImpl*)iface;
78     LONG ref = InterlockedIncrement(&This->ref);
79     return ref;
80 }
81
82 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
83 {
84     EnumFormatImpl *This = (EnumFormatImpl*)iface;
85     ULONG ref = InterlockedDecrement(&This->ref);
86
87     if(!ref) {
88         HeapFree(GetProcessHeap(), 0, This->fmtetc);
89         HeapFree(GetProcessHeap(), 0, This);
90     }
91
92     return ref;
93 }
94
95 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
96                                           FORMATETC *rgelt, ULONG *pceltFetched)
97 {
98     EnumFormatImpl *This = (EnumFormatImpl*)iface;
99     ULONG count = 0;
100
101     if(!rgelt)
102         return E_INVALIDARG;
103
104     count = min(celt, This->fmtetc_cnt-This->cur);
105     if(count > 0) {
106         memcpy(rgelt, This->fmtetc+This->cur, count*sizeof(FORMATETC));
107         This->cur += count;
108     }
109     if(pceltFetched)
110         *pceltFetched = count;
111     return count == celt ? S_OK : S_FALSE;
112 }
113
114 static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt)
115 {
116     ok(0, "unexpected call\n");
117     return E_NOTIMPL;
118 }
119
120 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
121 {
122     ok(0, "unexpected call\n");
123     return E_NOTIMPL;
124 }
125
126 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
127 {
128     ok(0, "unexpected call\n");
129     return E_NOTIMPL;
130 }
131
132 static const IEnumFORMATETCVtbl VT_EnumFormatImpl = {
133     EnumFormatImpl_QueryInterface,
134     EnumFormatImpl_AddRef,
135     EnumFormatImpl_Release,
136     EnumFormatImpl_Next,
137     EnumFormatImpl_Skip,
138     EnumFormatImpl_Reset,
139     EnumFormatImpl_Clone
140 };
141
142 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
143 {
144     EnumFormatImpl *ret;
145
146     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl));
147     ret->lpVtbl = &VT_EnumFormatImpl;
148     ret->ref = 1;
149     ret->cur = 0;
150     ret->fmtetc_cnt = fmtetc_cnt;
151     ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC));
152     memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
153     *lplpformatetc = (LPENUMFORMATETC)ret;
154     return S_OK;
155 }
156
157 static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj)
158 {
159     DataObjectImpl *This = (DataObjectImpl*)iface;
160
161     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) {
162         IDataObject_AddRef(iface);
163         *ppvObj = (LPVOID)This;
164         return S_OK;
165     }
166     *ppvObj = NULL;
167     return E_NOINTERFACE;
168 }
169
170 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
171 {
172     DataObjectImpl *This = (DataObjectImpl*)iface;
173     ULONG ref = InterlockedIncrement(&This->ref);
174     return ref;
175 }
176
177 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
178 {
179     DataObjectImpl *This = (DataObjectImpl*)iface;
180     ULONG ref = InterlockedDecrement(&This->ref);
181
182     if(!ref) {
183         if(This->text) GlobalFree(This->text);
184         if(This->fmtetc) GlobalFree(This->fmtetc);
185         HeapFree(GetProcessHeap(), 0, This);
186     }
187
188     return ref;
189 }
190
191 static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
192 {
193     DataObjectImpl *This = (DataObjectImpl*)iface;
194
195     if(pformatetc->lindex != -1)
196         return DV_E_LINDEX;
197
198     if(!(pformatetc->tymed & TYMED_HGLOBAL))
199         return DV_E_TYMED;
200
201     if(This->text && pformatetc->cfFormat == CF_TEXT)
202         U(*pmedium).hGlobal = This->text;
203     else
204         return DV_E_FORMATETC;
205
206     pmedium->tymed = TYMED_HGLOBAL;
207     pmedium->pUnkForRelease = (LPUNKNOWN)iface;
208     IUnknown_AddRef(pmedium->pUnkForRelease);
209     return S_OK;
210 }
211
212 static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
213 {
214     ok(0, "unexpected call\n");
215     return E_NOTIMPL;
216 }
217
218 static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc)
219 {
220     DataObjectImpl *This = (DataObjectImpl*)iface;
221     UINT i;
222     BOOL foundFormat = FALSE;
223
224     if(pformatetc->lindex != -1)
225         return DV_E_LINDEX;
226
227     for(i=0; i<This->fmtetc_cnt; i++) {
228         if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) {
229             foundFormat = TRUE;
230             if(This->fmtetc[i].tymed == pformatetc->tymed)
231                 return S_OK;
232         }
233     }
234     return foundFormat?DV_E_FORMATETC:DV_E_TYMED;
235 }
236
237 static HRESULT WINAPI DataObjectImpl_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC *pformatectIn,
238                                                            FORMATETC *pformatetcOut)
239 {
240     ok(0, "unexpected call\n");
241     return E_NOTIMPL;
242 }
243
244 static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc,
245                                              STGMEDIUM *pmedium, BOOL fRelease)
246 {
247     ok(0, "unexpected call\n");
248     return E_NOTIMPL;
249 }
250
251 static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwDirection,
252                                                    IEnumFORMATETC **ppenumFormatEtc)
253 {
254     DataObjectImpl *This = (DataObjectImpl*)iface;
255
256     if(dwDirection != DATADIR_GET) {
257         ok(0, "unexpected direction %d\n", dwDirection);
258         return E_NOTIMPL;
259     }
260     return EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenumFormatEtc);
261 }
262
263 static HRESULT WINAPI DataObjectImpl_DAdvise(IDataObject* iface, FORMATETC *pformatetc, DWORD advf,
264                                              IAdviseSink *pAdvSink, DWORD *pdwConnection)
265 {
266     ok(0, "unexpected call\n");
267     return E_NOTIMPL;
268 }
269
270 static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection)
271 {
272     ok(0, "unexpected call\n");
273     return E_NOTIMPL;
274 }
275
276 static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise)
277 {
278     ok(0, "unexpected call\n");
279     return E_NOTIMPL;
280 }
281
282 static const IDataObjectVtbl VT_DataObjectImpl =
283 {
284     DataObjectImpl_QueryInterface,
285     DataObjectImpl_AddRef,
286     DataObjectImpl_Release,
287     DataObjectImpl_GetData,
288     DataObjectImpl_GetDataHere,
289     DataObjectImpl_QueryGetData,
290     DataObjectImpl_GetCanonicalFormatEtc,
291     DataObjectImpl_SetData,
292     DataObjectImpl_EnumFormatEtc,
293     DataObjectImpl_DAdvise,
294     DataObjectImpl_DUnadvise,
295     DataObjectImpl_EnumDAdvise
296 };
297
298 static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
299 {
300     DataObjectImpl *obj;
301
302     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
303     obj->lpVtbl = &VT_DataObjectImpl;
304     obj->ref = 1;
305     obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1);
306     strcpy(GlobalLock(obj->text), text);
307     GlobalUnlock(obj->text);
308
309     obj->fmtetc_cnt = 1;
310     obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
311     InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
312
313     *lplpdataobj = (LPDATAOBJECT)obj;
314     return S_OK;
315 }
316
317 static void test_set_clipboard(void)
318 {
319     HRESULT hr;
320     ULONG ref;
321     LPDATAOBJECT data1, data2;
322     hr = DataObjectImpl_CreateText("data1", &data1);
323     ok(SUCCEEDED(hr), "Failed to create data1 object: %d\n", hr);
324     if(FAILED(hr))
325         return;
326     hr = DataObjectImpl_CreateText("data2", &data2);
327     ok(SUCCEEDED(hr), "Failed to create data2 object: %d\n", hr);
328     if(FAILED(hr))
329         return;
330
331     ok(OleSetClipboard(data1) == S_OK, "failed to set clipboard to data1\n");
332     ok(OleIsCurrentClipboard(data1) == S_OK, "expected current clipboard to be data1\n");
333     ok(OleIsCurrentClipboard(data2) == S_FALSE, "did not expect current clipboard to be data2\n");
334
335     ok(OleSetClipboard(data2) == S_OK, "failed to set clipboard to data2\n");
336     ok(OleIsCurrentClipboard(data1) == S_FALSE, "did not expect current clipboard to be data1\n");
337     ok(OleIsCurrentClipboard(data2) == S_OK, "expected current clipboard to be data2\n");
338
339     ok(OleFlushClipboard() == S_OK, "failed to flush clipboard\n");
340     ok(OleIsCurrentClipboard(data1) == S_FALSE, "did not expect current clipboard to be data1\n");
341     ok(OleIsCurrentClipboard(data2) == S_FALSE, "did not expect current clipboard to be data2\n");
342
343     ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard\n");
344
345     ref = IDataObject_Release(data1);
346     ok(ref == 0, "expected data1 ref=0, got %d\n", ref);
347     ref = IDataObject_Release(data2);
348     ok(ref == 0, "expected data2 ref=0, got %d\n", ref);
349 }
350
351
352 START_TEST(clipboard)
353 {
354     test_set_clipboard();
355 }