[OLE32_WINETEST]
[reactos.git] / rostests / winetests / ole32 / 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_NO_STATUS
22 #define _INC_WINDOWS
23 #define COM_NO_WINDOWS_H
24
25 #define _WIN32_DCOM
26 #define COBJMACROS
27 #define CONST_VTABLE
28
29 #include <stdarg.h>
30 //#include <stdio.h>
31
32 #include <windef.h>
33 #include <winbase.h>
34 #include <ole2.h>
35 //#include "objbase.h"
36
37 #include <wine/test.h>
38
39 #define DEFINE_EXPECT(func) \
40 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
41
42 #define SET_EXPECT(func) \
43 expect_ ## func = TRUE
44
45 #define CHECK_EXPECT2(func) \
46 do { \
47 ok(expect_ ##func, "unexpected call " #func "\n"); \
48 called_ ## func = TRUE; \
49 }while(0)
50
51 #define CHECK_EXPECT(func) \
52 do { \
53 CHECK_EXPECT2(func); \
54 expect_ ## func = FALSE; \
55 }while(0)
56
57 #define CHECK_CALLED(func) \
58 do { \
59 ok(called_ ## func, "expected " #func "\n"); \
60 expect_ ## func = called_ ## func = FALSE; \
61 }while(0)
62
63 DEFINE_EXPECT(DataObject_EnumFormatEtc);
64 DEFINE_EXPECT(EnumFORMATETC_Next);
65 DEFINE_EXPECT(EnumFORMATETC_Reset);
66 DEFINE_EXPECT(DataObject_QueryGetData);
67 DEFINE_EXPECT(DropSource_QueryContinueDrag);
68 DEFINE_EXPECT(DropTarget_DragEnter);
69 DEFINE_EXPECT(DropSource_GiveFeedback);
70 DEFINE_EXPECT(DropTarget_Drop);
71 DEFINE_EXPECT(DropTarget_DragLeave);
72
73 static int droptarget_refs;
74
75 /* helper macros to make tests a bit leaner */
76 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
77
78 static HRESULT WINAPI DropTarget_QueryInterface(IDropTarget* iface, REFIID riid,
79 void** ppvObject)
80 {
81 ok(0, "DropTarget_QueryInterface() shouldn't be called\n");
82 if (IsEqualIID(riid, &IID_IUnknown) ||
83 IsEqualIID(riid, &IID_IDropTarget))
84 {
85 IDropTarget_AddRef(iface);
86 *ppvObject = iface;
87 return S_OK;
88 }
89 *ppvObject = NULL;
90 return E_NOINTERFACE;
91 }
92
93 static ULONG WINAPI DropTarget_AddRef(IDropTarget* iface)
94 {
95 droptarget_refs++;
96 return droptarget_refs;
97 }
98
99 static ULONG WINAPI DropTarget_Release(IDropTarget* iface)
100 {
101 droptarget_refs--;
102 return droptarget_refs;
103 }
104
105 static HRESULT WINAPI DropTarget_DragEnter(IDropTarget* iface,
106 IDataObject* pDataObj,
107 DWORD grfKeyState, POINTL pt,
108 DWORD* pdwEffect)
109 {
110 CHECK_EXPECT(DropTarget_DragEnter);
111 *pdwEffect = DROPEFFECT_COPY;
112 return S_OK;
113 }
114
115 static HRESULT WINAPI DropTarget_DragOver(IDropTarget* iface,
116 DWORD grfKeyState,
117 POINTL pt,
118 DWORD* pdwEffect)
119 {
120 ok(0, "unexpected call\n");
121 *pdwEffect = DROPEFFECT_COPY;
122 return S_OK;
123 }
124
125 static HRESULT WINAPI DropTarget_DragLeave(IDropTarget* iface)
126 {
127 CHECK_EXPECT(DropTarget_DragLeave);
128 return E_NOTIMPL;
129 }
130
131 static HRESULT WINAPI DropTarget_Drop(IDropTarget* iface,
132 IDataObject* pDataObj, DWORD grfKeyState,
133 POINTL pt, DWORD* pdwEffect)
134 {
135 CHECK_EXPECT(DropTarget_Drop);
136 return 0xbeefbeef;
137 }
138
139 static const IDropTargetVtbl DropTarget_VTbl =
140 {
141 DropTarget_QueryInterface,
142 DropTarget_AddRef,
143 DropTarget_Release,
144 DropTarget_DragEnter,
145 DropTarget_DragOver,
146 DropTarget_DragLeave,
147 DropTarget_Drop
148 };
149
150 static IDropTarget DropTarget = { &DropTarget_VTbl };
151
152 static HRESULT WINAPI DropSource_QueryInterface(IDropSource *iface, REFIID riid, void **ppObj)
153 {
154 if (IsEqualIID(riid, &IID_IUnknown) ||
155 IsEqualIID(riid, &IID_IDropSource))
156 {
157 *ppObj = iface;
158 IDropSource_AddRef(iface);
159 return S_OK;
160 }
161 return E_NOINTERFACE;
162 }
163
164 static ULONG WINAPI DropSource_AddRef(IDropSource *iface)
165 {
166 return 2;
167 }
168
169 static ULONG WINAPI DropSource_Release(IDropSource *iface)
170 {
171 return 1;
172 }
173
174 static HRESULT WINAPI DropSource_QueryContinueDrag(
175 IDropSource *iface,
176 BOOL fEscapePressed,
177 DWORD grfKeyState)
178 {
179 CHECK_EXPECT(DropSource_QueryContinueDrag);
180 return DRAGDROP_S_DROP;
181 }
182
183 static HRESULT WINAPI DropSource_GiveFeedback(
184 IDropSource *iface,
185 DWORD dwEffect)
186 {
187 CHECK_EXPECT(DropSource_GiveFeedback);
188 return DRAGDROP_S_USEDEFAULTCURSORS;
189 }
190
191 static const IDropSourceVtbl dropsource_vtbl = {
192 DropSource_QueryInterface,
193 DropSource_AddRef,
194 DropSource_Release,
195 DropSource_QueryContinueDrag,
196 DropSource_GiveFeedback
197 };
198
199 static IDropSource DropSource = { &dropsource_vtbl };
200
201 static HRESULT WINAPI EnumFORMATETC_QueryInterface(IEnumFORMATETC *iface,
202 REFIID riid, void **ppvObj)
203 {
204 ok(0, "unexpected call\n");
205 return E_NOTIMPL;
206 }
207
208 static ULONG WINAPI EnumFORMATETC_AddRef(IEnumFORMATETC *iface)
209 {
210 return 2;
211 }
212
213 static ULONG WINAPI EnumFORMATETC_Release(IEnumFORMATETC *iface)
214 {
215 return 1;
216 }
217
218 static BOOL formats_enumerated;
219 static HRESULT WINAPI EnumFORMATETC_Next(IEnumFORMATETC *iface,
220 ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched)
221 {
222 static FORMATETC format = { CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
223
224 CHECK_EXPECT2(EnumFORMATETC_Next);
225
226 ok(celt == 1, "celt = %d\n", celt);
227 ok(rgelt != NULL, "rgelt == NULL\n");
228 ok(pceltFetched == NULL, "pceltFetched != NULL\n");
229
230 if(formats_enumerated)
231 return S_FALSE;
232
233 *rgelt = format;
234 formats_enumerated = TRUE;
235 return S_OK;
236 }
237
238 static HRESULT WINAPI EnumFORMATETC_Skip(IEnumFORMATETC *iface, ULONG celt)
239 {
240 ok(0, "unexpected call\n");
241 return E_NOTIMPL;
242 }
243
244 static HRESULT WINAPI EnumFORMATETC_Reset(IEnumFORMATETC *iface)
245 {
246 CHECK_EXPECT(EnumFORMATETC_Reset);
247 formats_enumerated = FALSE;
248 return S_OK;
249 }
250
251 static HRESULT WINAPI EnumFORMATETC_Clone(IEnumFORMATETC *iface,
252 IEnumFORMATETC **ppenum)
253 {
254 ok(0, "unexpected call\n");
255 return E_NOTIMPL;
256 }
257
258 static const IEnumFORMATETCVtbl enumformatetc_vtbl = {
259 EnumFORMATETC_QueryInterface,
260 EnumFORMATETC_AddRef,
261 EnumFORMATETC_Release,
262 EnumFORMATETC_Next,
263 EnumFORMATETC_Skip,
264 EnumFORMATETC_Reset,
265 EnumFORMATETC_Clone
266 };
267
268 static IEnumFORMATETC EnumFORMATETC = { &enumformatetc_vtbl };
269
270 static HRESULT WINAPI DataObject_QueryInterface(
271 IDataObject *iface,
272 REFIID riid,
273 void **pObj)
274 {
275 if (IsEqualIID(riid, &IID_IUnknown) ||
276 IsEqualIID(riid, &IID_IDataObject))
277 {
278 *pObj = iface;
279 IDataObject_AddRef(iface);
280 return S_OK;
281 }
282
283 trace("DataObject_QueryInterface: %s\n", wine_dbgstr_guid(riid));
284 return E_NOINTERFACE;
285 }
286
287 static ULONG WINAPI DataObject_AddRef(IDataObject *iface)
288 {
289 return 2;
290 }
291
292 static ULONG WINAPI DataObject_Release(IDataObject *iface)
293 {
294 return 1;
295 }
296
297 static HRESULT WINAPI DataObject_GetData(
298 IDataObject *iface,
299 FORMATETC *pformatetcIn,
300 STGMEDIUM *pmedium)
301 {
302 ok(0, "unexpected call\n");
303 return E_NOTIMPL;
304 }
305
306 static HRESULT WINAPI DataObject_GetDataHere(
307 IDataObject *iface,
308 FORMATETC *pformatetc,
309 STGMEDIUM *pmedium)
310 {
311 ok(0, "unexpected call\n");
312 return E_NOTIMPL;
313 }
314
315 static HRESULT WINAPI DataObject_QueryGetData(
316 IDataObject *iface,
317 FORMATETC *pformatetc)
318 {
319 CHECK_EXPECT(DataObject_QueryGetData);
320 return S_OK;
321 }
322
323 static HRESULT WINAPI DataObject_GetCanonicalFormatEtc(
324 IDataObject *iface,
325 FORMATETC *pformatectIn,
326 FORMATETC *pformatetcOut)
327 {
328 ok(0, "unexpected call\n");
329 return E_NOTIMPL;
330 }
331
332 static HRESULT WINAPI DataObject_SetData(
333 IDataObject *iface,
334 FORMATETC *pformatetc,
335 STGMEDIUM *pmedium,
336 BOOL fRelease)
337 {
338 ok(0, "unexpected call\n");
339 return E_NOTIMPL;
340 }
341
342 static HRESULT WINAPI DataObject_EnumFormatEtc(
343 IDataObject *iface,
344 DWORD dwDirection,
345 IEnumFORMATETC **ppenumFormatEtc)
346 {
347 CHECK_EXPECT(DataObject_EnumFormatEtc);
348 *ppenumFormatEtc = &EnumFORMATETC;
349 formats_enumerated = FALSE;
350 return S_OK;
351 }
352
353 static HRESULT WINAPI DataObject_DAdvise(
354 IDataObject *iface,
355 FORMATETC *pformatetc,
356 DWORD advf,
357 IAdviseSink *pAdvSink,
358 DWORD *pdwConnection)
359 {
360 ok(0, "unexpected call\n");
361 return E_NOTIMPL;
362 }
363
364 static HRESULT WINAPI DataObject_DUnadvise(
365 IDataObject *iface,
366 DWORD dwConnection)
367 {
368 ok(0, "unexpected call\n");
369 return E_NOTIMPL;
370 }
371
372 static HRESULT WINAPI DataObject_EnumDAdvise(
373 IDataObject *iface,
374 IEnumSTATDATA **ppenumAdvise)
375 {
376 ok(0, "unexpected call\n");
377 return E_NOTIMPL;
378 }
379
380 static const IDataObjectVtbl dataobject_vtbl = {
381 DataObject_QueryInterface,
382 DataObject_AddRef,
383 DataObject_Release,
384 DataObject_GetData,
385 DataObject_GetDataHere,
386 DataObject_QueryGetData,
387 DataObject_GetCanonicalFormatEtc,
388 DataObject_SetData,
389 DataObject_EnumFormatEtc,
390 DataObject_DAdvise,
391 DataObject_DUnadvise,
392 DataObject_EnumDAdvise
393 };
394
395 static IDataObject DataObject = { &dataobject_vtbl };
396
397 static ATOM register_dummy_class(void)
398 {
399 WNDCLASSA wc =
400 {
401 0,
402 DefWindowProcA,
403 0,
404 0,
405 GetModuleHandleA(NULL),
406 NULL,
407 LoadCursorA(NULL, (LPSTR)IDC_ARROW),
408 (HBRUSH)(COLOR_BTNFACE+1),
409 NULL,
410 "WineOleTestClass",
411 };
412
413 return RegisterClassA(&wc);
414 }
415
416 static void test_Register_Revoke(void)
417 {
418 HANDLE prop;
419 HRESULT hr;
420 HWND hwnd;
421
422 hwnd = CreateWindowA("WineOleTestClass", "Test", 0,
423 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
424 NULL, NULL, NULL);
425
426 hr = RegisterDragDrop(hwnd, &DropTarget);
427 ok(hr == E_OUTOFMEMORY ||
428 broken(hr == CO_E_NOTINITIALIZED), /* NT4 */
429 "RegisterDragDrop without OLE initialized should have returned E_OUTOFMEMORY instead of 0x%08x\n", hr);
430
431 OleInitialize(NULL);
432
433 hr = RegisterDragDrop(hwnd, NULL);
434 ok(hr == E_INVALIDARG, "RegisterDragDrop with NULL IDropTarget * should return E_INVALIDARG instead of 0x%08x\n", hr);
435
436 hr = RegisterDragDrop(NULL, &DropTarget);
437 ok(hr == DRAGDROP_E_INVALIDHWND, "RegisterDragDrop with NULL hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
438
439 hr = RegisterDragDrop((HWND)0xdeadbeef, &DropTarget);
440 ok(hr == DRAGDROP_E_INVALIDHWND, "RegisterDragDrop with garbage hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
441
442 ok(droptarget_refs == 0, "DropTarget refs should be zero not %d\n", droptarget_refs);
443 hr = RegisterDragDrop(hwnd, &DropTarget);
444 ok_ole_success(hr, "RegisterDragDrop");
445 ok(droptarget_refs >= 1, "DropTarget refs should be at least one\n");
446
447 prop = GetPropA(hwnd, "OleDropTargetInterface");
448 ok(prop == &DropTarget, "expected IDropTarget pointer %p, got %p\n", &DropTarget, prop);
449
450 hr = RegisterDragDrop(hwnd, &DropTarget);
451 ok(hr == DRAGDROP_E_ALREADYREGISTERED, "RegisterDragDrop with already registered hwnd should return DRAGDROP_E_ALREADYREGISTERED instead of 0x%08x\n", hr);
452
453 ok(droptarget_refs >= 1, "DropTarget refs should be at least one\n");
454 OleUninitialize();
455 ok(droptarget_refs >= 1, "DropTarget refs should be at least one\n");
456
457 hr = RevokeDragDrop(hwnd);
458 ok_ole_success(hr, "RevokeDragDrop");
459 ok(droptarget_refs == 0 ||
460 broken(droptarget_refs == 1), /* NT4 */
461 "DropTarget refs should be zero not %d\n", droptarget_refs);
462
463 hr = RevokeDragDrop(NULL);
464 ok(hr == DRAGDROP_E_INVALIDHWND, "RevokeDragDrop with NULL hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
465
466 DestroyWindow(hwnd);
467
468 /* try to revoke with already destroyed window */
469 OleInitialize(NULL);
470
471 hwnd = CreateWindowA("WineOleTestClass", "Test", 0,
472 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
473 NULL, NULL, NULL);
474
475 hr = RegisterDragDrop(hwnd, &DropTarget);
476 ok(hr == S_OK, "got 0x%08x\n", hr);
477
478 DestroyWindow(hwnd);
479
480 hr = RevokeDragDrop(hwnd);
481 ok(hr == DRAGDROP_E_INVALIDHWND, "got 0x%08x\n", hr);
482
483 OleUninitialize();
484 }
485
486 static void test_DoDragDrop(void)
487 {
488 DWORD effect;
489 HRESULT hr;
490 HWND hwnd;
491 RECT rect;
492
493 hwnd = CreateWindowExA(WS_EX_TOPMOST, "WineOleTestClass", "Test", 0,
494 CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL,
495 NULL, NULL, NULL);
496 ok(IsWindow(hwnd), "failed to create window\n");
497
498 hr = OleInitialize(NULL);
499 ok(hr == S_OK, "got 0x%08x\n", hr);
500
501 hr = RegisterDragDrop(hwnd, &DropTarget);
502 ok(hr == S_OK, "got 0x%08x\n", hr);
503
504 /* incomplete arguments set */
505 hr = DoDragDrop(NULL, NULL, 0, NULL);
506 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
507
508 hr = DoDragDrop(NULL, &DropSource, 0, NULL);
509 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
510
511 hr = DoDragDrop(&DataObject, NULL, 0, NULL);
512 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
513
514 hr = DoDragDrop(NULL, NULL, 0, &effect);
515 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
516
517 hr = DoDragDrop(&DataObject, &DropSource, 0, NULL);
518 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
519
520 hr = DoDragDrop(NULL, &DropSource, 0, &effect);
521 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
522
523 hr = DoDragDrop(&DataObject, NULL, 0, &effect);
524 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
525
526 ShowWindow(hwnd, SW_SHOW);
527 GetWindowRect(hwnd, &rect);
528 ok(SetCursorPos(rect.left+50, rect.top+50), "SetCursorPos failed\n");
529 SET_EXPECT(DataObject_EnumFormatEtc);
530 SET_EXPECT(EnumFORMATETC_Next);
531 SET_EXPECT(EnumFORMATETC_Reset);
532 SET_EXPECT(DataObject_QueryGetData);
533 SET_EXPECT(DropSource_QueryContinueDrag);
534 SET_EXPECT(DropTarget_DragEnter);
535 SET_EXPECT(DropSource_GiveFeedback);
536 SET_EXPECT(DropTarget_Drop);
537 hr = DoDragDrop(&DataObject, &DropSource, DROPEFFECT_COPY, &effect);
538 ok(hr == 0xbeefbeef, "got 0x%08x\n", hr);
539 todo_wine CHECK_CALLED(DataObject_EnumFormatEtc);
540 todo_wine CHECK_CALLED(EnumFORMATETC_Next);
541 todo_wine CHECK_CALLED(EnumFORMATETC_Reset);
542 todo_wine CHECK_CALLED(DataObject_QueryGetData);
543 CHECK_CALLED(DropSource_QueryContinueDrag);
544 CHECK_CALLED(DropTarget_DragEnter);
545 CHECK_CALLED(DropSource_GiveFeedback);
546 CHECK_CALLED(DropTarget_Drop);
547
548 SET_EXPECT(DataObject_EnumFormatEtc);
549 SET_EXPECT(EnumFORMATETC_Next);
550 SET_EXPECT(EnumFORMATETC_Reset);
551 SET_EXPECT(DataObject_QueryGetData);
552 SET_EXPECT(DropSource_QueryContinueDrag);
553 SET_EXPECT(DropTarget_DragEnter);
554 SET_EXPECT(DropSource_GiveFeedback);
555 SET_EXPECT(DropTarget_DragLeave);
556 hr = DoDragDrop(&DataObject, &DropSource, 0, &effect);
557 ok(hr == DRAGDROP_S_DROP, "got 0x%08x\n", hr);
558 todo_wine CHECK_CALLED(DataObject_EnumFormatEtc);
559 todo_wine CHECK_CALLED(EnumFORMATETC_Next);
560 todo_wine CHECK_CALLED(EnumFORMATETC_Reset);
561 todo_wine CHECK_CALLED(DataObject_QueryGetData);
562 CHECK_CALLED(DropSource_QueryContinueDrag);
563 CHECK_CALLED(DropTarget_DragEnter);
564 CHECK_CALLED(DropSource_GiveFeedback);
565 CHECK_CALLED(DropTarget_DragLeave);
566
567 OleUninitialize();
568
569 DestroyWindow(hwnd);
570 }
571
572 START_TEST(dragdrop)
573 {
574 register_dummy_class();
575
576 test_Register_Revoke();
577 #ifdef __REACTOS__
578 if (!winetest_interactive &&
579 !strcmp(winetest_platform, "windows"))
580 {
581 skip("ROSTESTS-182: Skipping ole32_winetest:dragdrop test_DoDragDrop because it hangs on WHS-Testbot. Set winetest_interactive to run it anyway.\n");
582 return;
583 }
584 #endif
585 test_DoDragDrop();
586 }