ole32: Avoid calling QueryContinueDrag recursively.
[wine.git] / dlls / ole32 / tests / dragdrop.c
blob62ac15d8fc707ee6614c50215cfe4d7edca8a738
1 /*
2 * Drag and Drop Tests
4 * Copyright 2007 Robert Shearman
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.
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.
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
21 #define _WIN32_DCOM
22 #define COBJMACROS
23 #define CONST_VTABLE
25 #include <stdarg.h>
26 #include <stdio.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
32 #include "wine/test.h"
35 #define METHOD_LIST \
36 METHOD(DO_EnumFormatEtc), \
37 METHOD(DO_QueryGetData), \
38 METHOD(EnumFMT_Next), \
39 METHOD(EnumFMT_Reset), \
40 METHOD(EnumFMT_Skip), \
41 METHOD(DS_QueryContinueDrag), \
42 METHOD(DS_GiveFeedback), \
43 METHOD(DT_DragEnter), \
44 METHOD(DT_Drop), \
45 METHOD(DT_DragLeave), \
46 METHOD(DT_DragOver), \
47 METHOD(DoDragDrop_effect_in), \
48 METHOD(DoDragDrop_ret), \
49 METHOD(DoDragDrop_effect_out), \
50 METHOD(end_seq)
52 #define METHOD(x) x
53 enum method
55 METHOD_LIST
57 #undef METHOD
59 #define METHOD(x) #x
60 static const char *method_names[] =
62 METHOD_LIST
64 #undef METHOD
65 #undef METHOD_LIST
67 struct method_call
69 enum method method;
70 DWORD expect_param;
72 HRESULT set_ret;
73 DWORD set_param;
75 int called_todo : 1;
78 const struct method_call *call_ptr;
80 static HRESULT check_expect_(enum method func, DWORD expect_param, DWORD *set_param, const char *file, int line )
82 HRESULT hr;
86 todo_wine_if(call_ptr->called_todo)
87 ok_( file, line )( func == call_ptr->method, "unexpected call %s instead of %s\n",
88 method_names[func], method_names[call_ptr->method] );
89 if (call_ptr->method == func) break;
90 } while ((++call_ptr)->method != end_seq);
92 ok_( file, line )( expect_param == call_ptr->expect_param, "%s: unexpected param %08x expected %08x\n",
93 method_names[func], expect_param, call_ptr->expect_param );
94 if (set_param) *set_param = call_ptr->set_param;
95 hr = call_ptr->set_ret;
96 if (call_ptr->method != end_seq) call_ptr++;
97 return hr;
100 #define check_expect(func, expect_param, set_param) \
101 check_expect_((func), (expect_param), (set_param), __FILE__, __LINE__)
104 struct method_call call_lists[][30] =
106 { /* First QueryContinueDrag rets DRAGDROP_S_DROP */
107 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY, 0 },
108 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
109 { EnumFMT_Next, 0, S_OK, 0, 1 },
110 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
111 { EnumFMT_Reset, 0, S_OK, 0, 1 },
112 { EnumFMT_Next, 0, S_OK, 0, 1 },
113 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
114 { DO_QueryGetData, 0, S_OK, 0, 1 },
116 { DS_QueryContinueDrag, 0, DRAGDROP_S_DROP, 0, 0 },
117 { DT_DragEnter, DROPEFFECT_COPY, S_OK, DROPEFFECT_COPY, 0 },
118 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
119 { DT_Drop, DROPEFFECT_COPY, 0xbeefbeef, DROPEFFECT_COPY, 0 },
121 { DoDragDrop_ret, 0xbeefbeef, 0, 0, 0, },
122 { DoDragDrop_effect_out, DROPEFFECT_COPY, 0, 0, 0 },
123 { end_seq, 0, 0, 0, 0 }
125 { /* As above, but initial effects == 0 */
126 { DoDragDrop_effect_in, 0, 0, 0, 0 },
127 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
128 { EnumFMT_Next, 0, S_OK, 0, 1 },
129 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
130 { EnumFMT_Reset, 0, S_OK, 0, 1 },
131 { EnumFMT_Next, 0, S_OK, 0, 1 },
132 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
133 { DO_QueryGetData, 0, S_OK, 0, 1 },
135 { DS_QueryContinueDrag, 0, DRAGDROP_S_DROP, 0, 0 },
136 { DT_DragEnter, 0, S_OK, DROPEFFECT_COPY, 0 },
137 { DS_GiveFeedback, 0, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
138 { DT_DragLeave, 0, 0, 0, 0 },
140 { DoDragDrop_ret, DRAGDROP_S_DROP, 0, 0, 0 },
141 { DoDragDrop_effect_out, 0, 0, 0, 0 },
142 { end_seq, 0, 0, 0, 0 }
144 { /* Multiple initial effects */
145 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0 },
146 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
147 { EnumFMT_Next, 0, S_OK, 0, 1 },
148 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
149 { EnumFMT_Reset, 0, S_OK, 0, 1 },
150 { EnumFMT_Next, 0, S_OK, 0, 1 },
151 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
152 { DO_QueryGetData, 0, S_OK, 0, 1 },
154 { DS_QueryContinueDrag, 0, DRAGDROP_S_DROP, 0, 0 },
155 { DT_DragEnter, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
156 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
157 { DT_Drop, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0, 0, 0 },
159 { DoDragDrop_ret, DRAGDROP_S_DROP, 0, 0, 0 },
160 { DoDragDrop_effect_out, 0, 0, 0, 0 },
161 { end_seq, 0, 0, 0, 0 }
163 { /* First couple of QueryContinueDrag return S_OK followed by a drop */
164 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0 },
165 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
166 { EnumFMT_Next, 0, S_OK, 0, 1 },
167 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
168 { EnumFMT_Reset, 0, S_OK, 0, 1 },
169 { EnumFMT_Next, 0, S_OK, 0, 1 },
170 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
171 { DO_QueryGetData, 0, S_OK, 0, 1 },
173 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
174 { DT_DragEnter, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
175 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
176 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
177 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
179 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
180 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
181 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
183 { DS_QueryContinueDrag, 0, DRAGDROP_S_DROP, 0, 0 },
184 { DT_Drop, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0, 0, 0 },
186 { DoDragDrop_ret, DRAGDROP_S_DROP, 0, 0, 0 },
187 { DoDragDrop_effect_out, 0, 0, 0, 0 },
188 { end_seq, 0, 0, 0, 0 }
190 { /* First QueryContinueDrag cancels */
191 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0 },
192 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
193 { EnumFMT_Next, 0, S_OK, 0, 1 },
194 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
195 { EnumFMT_Reset, 0, S_OK, 0, 1 },
196 { EnumFMT_Next, 0, S_OK, 0, 1 },
197 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
198 { DO_QueryGetData, 0, S_OK, 0, 1 },
200 { DS_QueryContinueDrag, 0, DRAGDROP_S_CANCEL, 0, 0 },
202 { DoDragDrop_ret, DRAGDROP_S_CANCEL, 0, 0, 0 },
203 { DoDragDrop_effect_out, 0, 0, 0, 0 },
204 { end_seq, 0, 0, 0, 0 }
206 { /* First couple of QueryContinueDrag return S_OK followed by a cancel */
207 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0 },
208 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
209 { EnumFMT_Next, 0, S_OK, 0, 1 },
210 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
211 { EnumFMT_Reset, 0, S_OK, 0, 1 },
212 { EnumFMT_Next, 0, S_OK, 0, 1 },
213 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
214 { DO_QueryGetData, 0, S_OK, 0, 1 },
216 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
217 { DT_DragEnter, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
218 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
219 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
220 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
222 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
223 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
224 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
226 { DS_QueryContinueDrag, 0, DRAGDROP_S_CANCEL, 0, 0 },
227 { DT_DragLeave, 0, 0, 0, 0 },
229 { DoDragDrop_ret, DRAGDROP_S_CANCEL, 0, 0, 0 },
230 { DoDragDrop_effect_out, 0, 0, 0, 0 },
231 { end_seq, 0, 0, 0, 0 }
233 { /* First couple of QueryContinueDrag return S_OK followed by a E_FAIL */
234 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0 },
235 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
236 { EnumFMT_Next, 0, S_OK, 0, 1 },
237 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
238 { EnumFMT_Reset, 0, S_OK, 0, 1 },
239 { EnumFMT_Next, 0, S_OK, 0, 1 },
240 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
241 { DO_QueryGetData, 0, S_OK, 0, 1 },
243 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
244 { DT_DragEnter, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
245 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
246 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
247 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
249 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
250 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
251 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
253 { DS_QueryContinueDrag, 0, E_FAIL, 0, 0 },
254 { DT_DragLeave, 0, 0, 0, 0 },
256 { DoDragDrop_ret, E_FAIL, 0, 0, 0 },
257 { DoDragDrop_effect_out, 0, 0, 0, 0 },
258 { end_seq, 0, 0, 0, 0 }
262 static int droptarget_refs;
263 static int test_reentrance;
265 /* helper macros to make tests a bit leaner */
266 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
268 static HRESULT WINAPI DropTarget_QueryInterface(IDropTarget* iface, REFIID riid,
269 void** ppvObject)
271 ok(0, "DropTarget_QueryInterface() shouldn't be called\n");
272 if (IsEqualIID(riid, &IID_IUnknown) ||
273 IsEqualIID(riid, &IID_IDropTarget))
275 IDropTarget_AddRef(iface);
276 *ppvObject = iface;
277 return S_OK;
279 *ppvObject = NULL;
280 return E_NOINTERFACE;
283 static ULONG WINAPI DropTarget_AddRef(IDropTarget* iface)
285 droptarget_refs++;
286 return droptarget_refs;
289 static ULONG WINAPI DropTarget_Release(IDropTarget* iface)
291 droptarget_refs--;
292 return droptarget_refs;
295 static HRESULT WINAPI DropTarget_DragEnter(IDropTarget* iface,
296 IDataObject* pDataObj,
297 DWORD grfKeyState, POINTL pt,
298 DWORD* pdwEffect)
300 return check_expect(DT_DragEnter, *pdwEffect, pdwEffect);
303 static HRESULT WINAPI DropTarget_DragOver(IDropTarget* iface,
304 DWORD grfKeyState,
305 POINTL pt,
306 DWORD* pdwEffect)
308 return check_expect(DT_DragOver, *pdwEffect, pdwEffect);
311 static HRESULT WINAPI DropTarget_DragLeave(IDropTarget* iface)
313 return check_expect(DT_DragLeave, 0, NULL);
316 static HRESULT WINAPI DropTarget_Drop(IDropTarget* iface,
317 IDataObject* pDataObj, DWORD grfKeyState,
318 POINTL pt, DWORD* pdwEffect)
320 return check_expect(DT_Drop, *pdwEffect, pdwEffect);
323 static const IDropTargetVtbl DropTarget_VTbl =
325 DropTarget_QueryInterface,
326 DropTarget_AddRef,
327 DropTarget_Release,
328 DropTarget_DragEnter,
329 DropTarget_DragOver,
330 DropTarget_DragLeave,
331 DropTarget_Drop
334 static IDropTarget DropTarget = { &DropTarget_VTbl };
336 static HRESULT WINAPI DropSource_QueryInterface(IDropSource *iface, REFIID riid, void **ppObj)
338 if (IsEqualIID(riid, &IID_IUnknown) ||
339 IsEqualIID(riid, &IID_IDropSource))
341 *ppObj = iface;
342 IDropSource_AddRef(iface);
343 return S_OK;
345 return E_NOINTERFACE;
348 static ULONG WINAPI DropSource_AddRef(IDropSource *iface)
350 return 2;
353 static ULONG WINAPI DropSource_Release(IDropSource *iface)
355 return 1;
358 static HRESULT WINAPI DropSource_QueryContinueDrag(
359 IDropSource *iface,
360 BOOL fEscapePressed,
361 DWORD grfKeyState)
363 HRESULT hr = check_expect(DS_QueryContinueDrag, 0, NULL);
364 if (test_reentrance)
366 MSG msg;
367 BOOL r;
368 int num = 0;
370 HWND hwnd = GetCapture();
371 ok(hwnd != 0, "Expected capture window\n");
373 /* send some fake events that should be ignored */
374 r = PostMessageA(hwnd, WM_MOUSEMOVE, 0, 0);
375 r &= PostMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
376 r &= PostMessageA(hwnd, WM_LBUTTONUP, 0, 0);
377 r &= PostMessageA(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
378 ok(r, "Unable to post messages\n");
380 /* run the message loop for this thread */
381 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
383 TranslateMessage(&msg);
384 DispatchMessageA(&msg);
385 num++;
388 ok(num >= 4, "Expected at least 4 messages but %d were processed\n", num);
390 return hr;
393 static HRESULT WINAPI DropSource_GiveFeedback(
394 IDropSource *iface,
395 DWORD dwEffect)
397 return check_expect(DS_GiveFeedback, dwEffect, NULL);
400 static const IDropSourceVtbl dropsource_vtbl = {
401 DropSource_QueryInterface,
402 DropSource_AddRef,
403 DropSource_Release,
404 DropSource_QueryContinueDrag,
405 DropSource_GiveFeedback
408 static IDropSource DropSource = { &dropsource_vtbl };
410 static HRESULT WINAPI EnumFORMATETC_QueryInterface(IEnumFORMATETC *iface,
411 REFIID riid, void **ppvObj)
413 ok(0, "unexpected call\n");
414 return E_NOTIMPL;
417 static ULONG WINAPI EnumFORMATETC_AddRef(IEnumFORMATETC *iface)
419 return 2;
422 static ULONG WINAPI EnumFORMATETC_Release(IEnumFORMATETC *iface)
424 return 1;
427 static HRESULT WINAPI EnumFORMATETC_Next(IEnumFORMATETC *iface,
428 ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched)
430 static FORMATETC format = { CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
431 HRESULT hr = check_expect(EnumFMT_Next, 0, NULL);
433 ok(celt == 1, "celt = %d\n", celt);
434 ok(rgelt != NULL, "rgelt == NULL\n");
435 ok(pceltFetched == NULL, "pceltFetched != NULL\n");
437 *rgelt = format;
438 return hr;
441 static HRESULT WINAPI EnumFORMATETC_Skip(IEnumFORMATETC *iface, ULONG celt)
443 return check_expect(EnumFMT_Skip, 0, NULL);
446 static HRESULT WINAPI EnumFORMATETC_Reset(IEnumFORMATETC *iface)
448 return check_expect(EnumFMT_Reset, 0, NULL);
451 static HRESULT WINAPI EnumFORMATETC_Clone(IEnumFORMATETC *iface,
452 IEnumFORMATETC **ppenum)
454 ok(0, "unexpected call\n");
455 return E_NOTIMPL;
458 static const IEnumFORMATETCVtbl enumformatetc_vtbl = {
459 EnumFORMATETC_QueryInterface,
460 EnumFORMATETC_AddRef,
461 EnumFORMATETC_Release,
462 EnumFORMATETC_Next,
463 EnumFORMATETC_Skip,
464 EnumFORMATETC_Reset,
465 EnumFORMATETC_Clone
468 static IEnumFORMATETC EnumFORMATETC = { &enumformatetc_vtbl };
470 static HRESULT WINAPI DataObject_QueryInterface(
471 IDataObject *iface,
472 REFIID riid,
473 void **pObj)
475 if (IsEqualIID(riid, &IID_IUnknown) ||
476 IsEqualIID(riid, &IID_IDataObject))
478 *pObj = iface;
479 IDataObject_AddRef(iface);
480 return S_OK;
483 trace("DataObject_QueryInterface: %s\n", wine_dbgstr_guid(riid));
484 return E_NOINTERFACE;
487 static ULONG WINAPI DataObject_AddRef(IDataObject *iface)
489 return 2;
492 static ULONG WINAPI DataObject_Release(IDataObject *iface)
494 return 1;
497 static HRESULT WINAPI DataObject_GetData(
498 IDataObject *iface,
499 FORMATETC *pformatetcIn,
500 STGMEDIUM *pmedium)
502 ok(0, "unexpected call\n");
503 return E_NOTIMPL;
506 static HRESULT WINAPI DataObject_GetDataHere(
507 IDataObject *iface,
508 FORMATETC *pformatetc,
509 STGMEDIUM *pmedium)
511 ok(0, "unexpected call\n");
512 return E_NOTIMPL;
515 static HRESULT WINAPI DataObject_QueryGetData(
516 IDataObject *iface,
517 FORMATETC *pformatetc)
519 return check_expect(DO_QueryGetData, 0, NULL);
522 static HRESULT WINAPI DataObject_GetCanonicalFormatEtc(
523 IDataObject *iface,
524 FORMATETC *pformatectIn,
525 FORMATETC *pformatetcOut)
527 ok(0, "unexpected call\n");
528 return E_NOTIMPL;
531 static HRESULT WINAPI DataObject_SetData(
532 IDataObject *iface,
533 FORMATETC *pformatetc,
534 STGMEDIUM *pmedium,
535 BOOL fRelease)
537 ok(0, "unexpected call\n");
538 return E_NOTIMPL;
541 static HRESULT WINAPI DataObject_EnumFormatEtc(
542 IDataObject *iface,
543 DWORD dwDirection,
544 IEnumFORMATETC **ppenumFormatEtc)
546 HRESULT hr = check_expect(DO_EnumFormatEtc, 0, NULL);
547 *ppenumFormatEtc = &EnumFORMATETC;
548 return hr;
551 static HRESULT WINAPI DataObject_DAdvise(
552 IDataObject *iface,
553 FORMATETC *pformatetc,
554 DWORD advf,
555 IAdviseSink *pAdvSink,
556 DWORD *pdwConnection)
558 ok(0, "unexpected call\n");
559 return E_NOTIMPL;
562 static HRESULT WINAPI DataObject_DUnadvise(
563 IDataObject *iface,
564 DWORD dwConnection)
566 ok(0, "unexpected call\n");
567 return E_NOTIMPL;
570 static HRESULT WINAPI DataObject_EnumDAdvise(
571 IDataObject *iface,
572 IEnumSTATDATA **ppenumAdvise)
574 ok(0, "unexpected call\n");
575 return E_NOTIMPL;
578 static const IDataObjectVtbl dataobject_vtbl = {
579 DataObject_QueryInterface,
580 DataObject_AddRef,
581 DataObject_Release,
582 DataObject_GetData,
583 DataObject_GetDataHere,
584 DataObject_QueryGetData,
585 DataObject_GetCanonicalFormatEtc,
586 DataObject_SetData,
587 DataObject_EnumFormatEtc,
588 DataObject_DAdvise,
589 DataObject_DUnadvise,
590 DataObject_EnumDAdvise
593 static IDataObject DataObject = { &dataobject_vtbl };
595 static ATOM register_dummy_class(void)
597 WNDCLASSA wc =
600 DefWindowProcA,
603 GetModuleHandleA(NULL),
604 NULL,
605 LoadCursorA(NULL, (LPSTR)IDC_ARROW),
606 (HBRUSH)(COLOR_BTNFACE+1),
607 NULL,
608 "WineOleTestClass",
611 return RegisterClassA(&wc);
614 static void test_Register_Revoke(void)
616 HANDLE prop;
617 HRESULT hr;
618 HWND hwnd;
620 hwnd = CreateWindowA("WineOleTestClass", "Test", 0,
621 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
622 NULL, NULL, NULL);
624 hr = RegisterDragDrop(hwnd, &DropTarget);
625 ok(hr == E_OUTOFMEMORY ||
626 broken(hr == CO_E_NOTINITIALIZED), /* NT4 */
627 "RegisterDragDrop without OLE initialized should have returned E_OUTOFMEMORY instead of 0x%08x\n", hr);
629 OleInitialize(NULL);
631 hr = RegisterDragDrop(hwnd, NULL);
632 ok(hr == E_INVALIDARG, "RegisterDragDrop with NULL IDropTarget * should return E_INVALIDARG instead of 0x%08x\n", hr);
634 hr = RegisterDragDrop(NULL, &DropTarget);
635 ok(hr == DRAGDROP_E_INVALIDHWND, "RegisterDragDrop with NULL hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
637 hr = RegisterDragDrop((HWND)0xdeadbeef, &DropTarget);
638 ok(hr == DRAGDROP_E_INVALIDHWND, "RegisterDragDrop with garbage hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
640 ok(droptarget_refs == 0, "DropTarget refs should be zero not %d\n", droptarget_refs);
641 hr = RegisterDragDrop(hwnd, &DropTarget);
642 ok_ole_success(hr, "RegisterDragDrop");
643 ok(droptarget_refs >= 1, "DropTarget refs should be at least one\n");
645 prop = GetPropA(hwnd, "OleDropTargetInterface");
646 ok(prop == &DropTarget, "expected IDropTarget pointer %p, got %p\n", &DropTarget, prop);
648 hr = RegisterDragDrop(hwnd, &DropTarget);
649 ok(hr == DRAGDROP_E_ALREADYREGISTERED, "RegisterDragDrop with already registered hwnd should return DRAGDROP_E_ALREADYREGISTERED instead of 0x%08x\n", hr);
651 ok(droptarget_refs >= 1, "DropTarget refs should be at least one\n");
652 OleUninitialize();
654 /* Win 8 releases the ref in OleUninitialize() */
655 if (droptarget_refs >= 1)
657 hr = RevokeDragDrop(hwnd);
658 ok_ole_success(hr, "RevokeDragDrop");
659 ok(droptarget_refs == 0 ||
660 broken(droptarget_refs == 1), /* NT4 */
661 "DropTarget refs should be zero not %d\n", droptarget_refs);
664 hr = RevokeDragDrop(NULL);
665 ok(hr == DRAGDROP_E_INVALIDHWND, "RevokeDragDrop with NULL hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
667 DestroyWindow(hwnd);
669 /* try to revoke with already destroyed window */
670 OleInitialize(NULL);
672 hwnd = CreateWindowA("WineOleTestClass", "Test", 0,
673 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
674 NULL, NULL, NULL);
676 hr = RegisterDragDrop(hwnd, &DropTarget);
677 ok(hr == S_OK, "got 0x%08x\n", hr);
679 DestroyWindow(hwnd);
681 hr = RevokeDragDrop(hwnd);
682 ok(hr == DRAGDROP_E_INVALIDHWND, "got 0x%08x\n", hr);
684 OleUninitialize();
687 static void test_DoDragDrop(void)
689 DWORD effect;
690 HRESULT hr;
691 HWND hwnd;
692 RECT rect;
693 int seq;
695 hwnd = CreateWindowExA(WS_EX_TOPMOST, "WineOleTestClass", "Test", 0,
696 CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL,
697 NULL, NULL, NULL);
698 ok(IsWindow(hwnd), "failed to create window\n");
700 hr = OleInitialize(NULL);
701 ok(hr == S_OK, "got 0x%08x\n", hr);
703 hr = RegisterDragDrop(hwnd, &DropTarget);
704 ok(hr == S_OK, "got 0x%08x\n", hr);
706 /* incomplete arguments set */
707 hr = DoDragDrop(NULL, NULL, 0, NULL);
708 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
710 hr = DoDragDrop(NULL, &DropSource, 0, NULL);
711 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
713 hr = DoDragDrop(&DataObject, NULL, 0, NULL);
714 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
716 hr = DoDragDrop(NULL, NULL, 0, &effect);
717 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
719 hr = DoDragDrop(&DataObject, &DropSource, 0, NULL);
720 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
722 hr = DoDragDrop(NULL, &DropSource, 0, &effect);
723 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
725 hr = DoDragDrop(&DataObject, NULL, 0, &effect);
726 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
728 ShowWindow(hwnd, SW_SHOW);
729 GetWindowRect(hwnd, &rect);
730 ok(SetCursorPos(rect.left+50, rect.top+50), "SetCursorPos failed\n");
732 for (test_reentrance = 0; test_reentrance < 2; test_reentrance++)
734 for (seq = 0; seq < ARRAY_SIZE(call_lists); seq++)
736 DWORD effect_in;
737 trace("%d\n", seq);
738 call_ptr = call_lists[seq];
739 effect_in = call_ptr->set_param;
740 call_ptr++;
742 hr = DoDragDrop(&DataObject, &DropSource, effect_in, &effect);
743 check_expect(DoDragDrop_ret, hr, NULL);
744 check_expect(DoDragDrop_effect_out, effect, NULL);
748 OleUninitialize();
750 DestroyWindow(hwnd);
753 START_TEST(dragdrop)
755 register_dummy_class();
757 test_Register_Revoke();
758 test_DoDragDrop();