ole32: Use window property to store registered drop target.
[wine] / dlls / ole32 / tests / dragdrop.c
1 /*
2  * Drag and Drop Tests
3  *
4  * Copyright 2007 Robert Shearman
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 _WIN32_DCOM
22 #define COBJMACROS
23 #define CONST_VTABLE
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31
32 #include "wine/test.h"
33
34 static int droptarget_addref_called;
35 static int droptarget_release_called;
36
37 /* helper macros to make tests a bit leaner */
38 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
39
40 static HRESULT WINAPI DropTarget_QueryInterface(IDropTarget* iface, REFIID riid,
41                                                 void** ppvObject)
42 {
43     trace("DropTarget_QueryInterface\n");
44     if (IsEqualIID(riid, &IID_IUnknown) ||
45         IsEqualIID(riid, &IID_IDropTarget))
46     {
47         IUnknown_AddRef(iface);
48         *ppvObject = iface;
49         return S_OK;
50     }
51     *ppvObject = NULL;
52     return E_NOINTERFACE;
53 }
54
55 static ULONG WINAPI DropTarget_AddRef(IDropTarget* iface)
56 {
57     droptarget_addref_called++;
58     return 2;
59 }
60
61 static ULONG WINAPI DropTarget_Release(IDropTarget* iface)
62 {
63     droptarget_release_called++;
64     return 1;
65 }
66
67 static HRESULT WINAPI DropTarget_DragEnter(IDropTarget* iface,
68                                            IDataObject* pDataObj,
69                                            DWORD grfKeyState, POINTL pt,
70                                            DWORD* pdwEffect)
71 {
72     return E_NOTIMPL;
73 }
74
75 static HRESULT WINAPI DropTarget_DragOver(IDropTarget* iface,
76                                           DWORD grfKeyState,
77                                           POINTL pt,
78                                           DWORD* pdwEffect)
79 {
80     return E_NOTIMPL;
81 }
82
83 static HRESULT WINAPI DropTarget_DragLeave(IDropTarget* iface)
84 {
85     return E_NOTIMPL;
86 }
87
88 static HRESULT WINAPI DropTarget_Drop(IDropTarget* iface,
89                                       IDataObject* pDataObj, DWORD grfKeyState,
90                                       POINTL pt, DWORD* pdwEffect)
91 {
92     return E_NOTIMPL;
93 }
94
95 static const IDropTargetVtbl DropTarget_VTbl =
96 {
97     DropTarget_QueryInterface,
98     DropTarget_AddRef,
99     DropTarget_Release,
100     DropTarget_DragEnter,
101     DropTarget_DragOver,
102     DropTarget_DragLeave,
103     DropTarget_Drop
104 };
105
106 static IDropTarget DropTarget = { &DropTarget_VTbl };
107
108 /** stub IDropSource **/
109 static HRESULT WINAPI DropSource_QueryInterface(IDropSource *iface, REFIID riid, void **ppObj)
110 {
111     if (IsEqualIID(riid, &IID_IUnknown) ||
112         IsEqualIID(riid, &IID_IDropSource))
113     {
114         *ppObj = iface;
115         IDropSource_AddRef(iface);
116         return S_OK;
117     }
118     return E_NOINTERFACE;
119 }
120
121 static ULONG WINAPI DropSource_AddRef(IDropSource *iface)
122 {
123     return 2;
124 }
125
126 static ULONG WINAPI DropSource_Release(IDropSource *iface)
127 {
128     return 1;
129 }
130
131 static HRESULT WINAPI DropSource_QueryContinueDrag(
132     IDropSource *iface,
133     BOOL fEscapePressed,
134     DWORD grfKeyState)
135 {
136     /* always drop */
137     return DRAGDROP_S_DROP;
138 }
139
140 static HRESULT WINAPI DropSource_GiveFeedback(
141     IDropSource *iface,
142     DWORD dwEffect)
143 {
144     return DRAGDROP_S_USEDEFAULTCURSORS;
145 }
146
147 static const IDropSourceVtbl dropsource_vtbl = {
148     DropSource_QueryInterface,
149     DropSource_AddRef,
150     DropSource_Release,
151     DropSource_QueryContinueDrag,
152     DropSource_GiveFeedback
153 };
154
155 static IDropSource DropSource = { &dropsource_vtbl };
156
157 /** IDataObject stub **/
158 static HRESULT WINAPI DataObject_QueryInterface(
159     IDataObject *iface,
160     REFIID riid,
161     void **pObj)
162 {
163     if (IsEqualIID(riid, &IID_IUnknown) ||
164         IsEqualIID(riid, &IID_IDataObject))
165     {
166         *pObj = iface;
167         IDataObject_AddRef(iface);
168         return S_OK;
169     }
170     return E_NOINTERFACE;
171 }
172
173 static ULONG WINAPI DataObject_AddRef(IDataObject *iface)
174 {
175     return 2;
176 }
177
178 static ULONG WINAPI DataObject_Release(IDataObject *iface)
179 {
180     return 1;
181 }
182
183 static HRESULT WINAPI DataObject_GetData(
184     IDataObject *iface,
185     FORMATETC *pformatetcIn,
186     STGMEDIUM *pmedium)
187 {
188     return E_NOTIMPL;
189 }
190
191 static HRESULT WINAPI DataObject_GetDataHere(
192     IDataObject *iface,
193     FORMATETC *pformatetc,
194     STGMEDIUM *pmedium)
195 {
196     return E_NOTIMPL;
197 }
198
199 static HRESULT WINAPI DataObject_QueryGetData(
200     IDataObject *iface,
201     FORMATETC *pformatetc)
202 {
203     return S_OK;
204 }
205
206 static HRESULT WINAPI DataObject_GetCanonicalFormatEtc(
207     IDataObject *iface,
208     FORMATETC *pformatectIn,
209     FORMATETC *pformatetcOut)
210 {
211     return E_NOTIMPL;
212 }
213
214 static HRESULT WINAPI DataObject_SetData(
215     IDataObject *iface,
216     FORMATETC *pformatetc,
217     STGMEDIUM *pmedium,
218     BOOL fRelease)
219 {
220     return E_NOTIMPL;
221 }
222
223 static HRESULT WINAPI DataObject_EnumFormatEtc(
224     IDataObject *iface,
225     DWORD dwDirection,
226     IEnumFORMATETC **ppenumFormatEtc)
227 {
228     return S_OK;
229 }
230
231 static HRESULT WINAPI DataObject_DAdvise(
232     IDataObject *iface,
233     FORMATETC *pformatetc,
234     DWORD advf,
235     IAdviseSink *pAdvSink,
236     DWORD *pdwConnection)
237 {
238     return E_NOTIMPL;
239 }
240
241 static HRESULT WINAPI DataObject_DUnadvise(
242     IDataObject *iface,
243     DWORD dwConnection)
244 {
245     return E_NOTIMPL;
246 }
247
248 static HRESULT WINAPI DataObject_EnumDAdvise(
249     IDataObject *iface,
250     IEnumSTATDATA **ppenumAdvise)
251 {
252     return E_NOTIMPL;
253 }
254
255 static const IDataObjectVtbl dataobject_vtbl = {
256     DataObject_QueryInterface,
257     DataObject_AddRef,
258     DataObject_Release,
259     DataObject_GetData,
260     DataObject_GetDataHere,
261     DataObject_QueryGetData,
262     DataObject_GetCanonicalFormatEtc,
263     DataObject_SetData,
264     DataObject_EnumFormatEtc,
265     DataObject_DAdvise,
266     DataObject_DUnadvise,
267     DataObject_EnumDAdvise
268 };
269
270 static IDataObject DataObject = { &dataobject_vtbl };
271
272 static ATOM register_dummy_class(void)
273 {
274     WNDCLASS wc =
275     {
276         0,
277         DefWindowProc,
278         0,
279         0,
280         GetModuleHandle(NULL),
281         NULL,
282         LoadCursor(NULL, IDC_ARROW),
283         (HBRUSH)(COLOR_BTNFACE+1),
284         NULL,
285         TEXT("WineOleTestClass"),
286     };
287
288     return RegisterClass(&wc);
289 }
290
291 static void test_Register_Revoke(void)
292 {
293     HANDLE prop;
294     HRESULT hr;
295     HWND hwnd;
296
297     hwnd = CreateWindowA("WineOleTestClass", "Test", 0,
298         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
299         NULL, NULL, NULL);
300
301     hr = RegisterDragDrop(hwnd, &DropTarget);
302     ok(hr == E_OUTOFMEMORY ||
303         broken(hr == CO_E_NOTINITIALIZED), /* NT4 */
304         "RegisterDragDrop without OLE initialized should have returned E_OUTOFMEMORY instead of 0x%08x\n", hr);
305
306     OleInitialize(NULL);
307
308     hr = RegisterDragDrop(hwnd, NULL);
309     ok(hr == E_INVALIDARG, "RegisterDragDrop with NULL IDropTarget * should return E_INVALIDARG instead of 0x%08x\n", hr);
310
311     hr = RegisterDragDrop(NULL, &DropTarget);
312     ok(hr == DRAGDROP_E_INVALIDHWND, "RegisterDragDrop with NULL hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
313
314     hr = RegisterDragDrop((HWND)0xdeadbeef, &DropTarget);
315     ok(hr == DRAGDROP_E_INVALIDHWND, "RegisterDragDrop with garbage hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
316
317     ok(droptarget_addref_called == 0, "DropTarget_AddRef shouldn't have been called\n");
318     hr = RegisterDragDrop(hwnd, &DropTarget);
319     ok_ole_success(hr, "RegisterDragDrop");
320     ok(droptarget_addref_called == 1, "DropTarget_AddRef should have been called once, not %d times\n", droptarget_addref_called);
321
322     prop = GetPropA(hwnd, "OleDropTargetInterface");
323     ok(prop == &DropTarget, "expected IDropTarget pointer %p, got %p\n", &DropTarget, prop);
324
325     hr = RegisterDragDrop(hwnd, &DropTarget);
326     ok(hr == DRAGDROP_E_ALREADYREGISTERED, "RegisterDragDrop with already registered hwnd should return DRAGDROP_E_ALREADYREGISTERED instead of 0x%08x\n", hr);
327
328     ok(droptarget_release_called == 0, "DropTarget_Release shouldn't have been called\n");
329     OleUninitialize();
330     ok(droptarget_release_called == 0, "DropTarget_Release shouldn't have been called\n");
331
332     hr = RevokeDragDrop(hwnd);
333     ok_ole_success(hr, "RevokeDragDrop");
334     ok(droptarget_release_called == 1 ||
335         broken(droptarget_release_called == 0), /* NT4 */
336         "DropTarget_Release should have been called once, not %d times\n", droptarget_release_called);
337
338     hr = RevokeDragDrop(NULL);
339     ok(hr == DRAGDROP_E_INVALIDHWND, "RevokeDragDrop with NULL hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
340
341     DestroyWindow(hwnd);
342
343     /* try to revoke with already destroyed window */
344     OleInitialize(NULL);
345
346     hwnd = CreateWindowA("WineOleTestClass", "Test", 0,
347         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
348         NULL, NULL, NULL);
349
350     hr = RegisterDragDrop(hwnd, &DropTarget);
351     ok(hr == S_OK, "got 0x%08x\n", hr);
352
353     DestroyWindow(hwnd);
354
355     hr = RevokeDragDrop(hwnd);
356     ok(hr == DRAGDROP_E_INVALIDHWND, "got 0x%08x\n", hr);
357
358     OleUninitialize();
359 }
360
361 static void test_DoDragDrop(void)
362 {
363     DWORD effect;
364     HRESULT hr;
365     HWND hwnd;
366
367     hwnd = CreateWindowA("WineOleTestClass", "Test", 0,
368         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
369         NULL, NULL, NULL);
370     ok(IsWindow(hwnd), "failed to create window\n");
371
372     hr = OleInitialize(NULL);
373     ok(hr == S_OK, "got 0x%08x\n", hr);
374
375     hr = RegisterDragDrop(hwnd, &DropTarget);
376     ok(hr == S_OK, "got 0x%08x\n", hr);
377
378     /* incomplete arguments set */
379     hr = DoDragDrop(NULL, NULL, 0, NULL);
380     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
381
382     hr = DoDragDrop(NULL, &DropSource, 0, NULL);
383     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
384
385     hr = DoDragDrop(&DataObject, NULL, 0, NULL);
386     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
387
388     hr = DoDragDrop(NULL, NULL, 0, &effect);
389     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
390
391     hr = DoDragDrop(&DataObject, &DropSource, 0, NULL);
392     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
393
394     hr = DoDragDrop(NULL, &DropSource, 0, &effect);
395     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
396
397     hr = DoDragDrop(&DataObject, NULL, 0, &effect);
398     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
399
400     OleUninitialize();
401
402     DestroyWindow(hwnd);
403 }
404
405 START_TEST(dragdrop)
406 {
407     register_dummy_class();
408
409     test_Register_Revoke();
410     test_DoDragDrop();
411 }