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