e14e757287bc2aef13f493b44cb5b193a31aa04f
[reactos.git] / modules / 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 #include "precomp.h"
22
23 #define METHOD_LIST \
24 METHOD(DO_EnumFormatEtc), \
25 METHOD(DO_QueryGetData), \
26 METHOD(EnumFMT_Next), \
27 METHOD(EnumFMT_Reset), \
28 METHOD(EnumFMT_Skip), \
29 METHOD(DS_QueryContinueDrag), \
30 METHOD(DS_GiveFeedback), \
31 METHOD(DT_DragEnter), \
32 METHOD(DT_Drop), \
33 METHOD(DT_DragLeave), \
34 METHOD(DT_DragOver), \
35 METHOD(DoDragDrop_effect_in), \
36 METHOD(DoDragDrop_ret), \
37 METHOD(DoDragDrop_effect_out), \
38 METHOD(end_seq)
39
40 #define METHOD(x) x
41 enum method
42 {
43 METHOD_LIST
44 };
45 #undef METHOD
46
47 #define METHOD(x) #x
48 static const char *method_names[] =
49 {
50 METHOD_LIST
51 };
52 #undef METHOD
53 #undef METHOD_LIST
54
55 struct method_call
56 {
57 enum method method;
58 DWORD expect_param;
59
60 HRESULT set_ret;
61 DWORD set_param;
62
63 int called_todo : 1;
64 };
65
66 const struct method_call *call_ptr;
67
68 static HRESULT check_expect_(enum method func, DWORD expect_param, DWORD *set_param, const char *file, int line )
69 {
70 HRESULT hr;
71
72 do
73 {
74 todo_wine_if(call_ptr->called_todo)
75 ok_( file, line )( func == call_ptr->method, "unexpected call %s instead of %s\n",
76 method_names[func], method_names[call_ptr->method] );
77 if (call_ptr->method == func) break;
78 } while ((++call_ptr)->method != end_seq);
79
80 ok_( file, line )( expect_param == call_ptr->expect_param, "%s: unexpected param %08x expected %08x\n",
81 method_names[func], expect_param, call_ptr->expect_param );
82 if (set_param) *set_param = call_ptr->set_param;
83 hr = call_ptr->set_ret;
84 if (call_ptr->method != end_seq) call_ptr++;
85 return hr;
86 }
87
88 #define check_expect(func, expect_param, set_param) \
89 check_expect_((func), (expect_param), (set_param), __FILE__, __LINE__)
90
91
92 struct method_call call_lists[][30] =
93 {
94 { /* First QueryContinueDrag rets DRAGDROP_S_DROP */
95 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY, 0 },
96 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
97 { EnumFMT_Next, 0, S_OK, 0, 1 },
98 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
99 { EnumFMT_Reset, 0, S_OK, 0, 1 },
100 { EnumFMT_Next, 0, S_OK, 0, 1 },
101 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
102 { DO_QueryGetData, 0, S_OK, 0, 1 },
103
104 { DS_QueryContinueDrag, 0, DRAGDROP_S_DROP, 0, 0 },
105 { DT_DragEnter, DROPEFFECT_COPY, S_OK, DROPEFFECT_COPY, 0 },
106 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
107 { DT_Drop, DROPEFFECT_COPY, 0xbeefbeef, DROPEFFECT_COPY, 0 },
108
109 { DoDragDrop_ret, 0xbeefbeef, 0, 0, 0, },
110 { DoDragDrop_effect_out, DROPEFFECT_COPY, 0, 0, 0 },
111 { end_seq, 0, 0, 0, 0 }
112 },
113 { /* As above, but initial effects == 0 */
114 { DoDragDrop_effect_in, 0, 0, 0, 0 },
115 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
116 { EnumFMT_Next, 0, S_OK, 0, 1 },
117 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
118 { EnumFMT_Reset, 0, S_OK, 0, 1 },
119 { EnumFMT_Next, 0, S_OK, 0, 1 },
120 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
121 { DO_QueryGetData, 0, S_OK, 0, 1 },
122
123 { DS_QueryContinueDrag, 0, DRAGDROP_S_DROP, 0, 0 },
124 { DT_DragEnter, 0, S_OK, DROPEFFECT_COPY, 0 },
125 { DS_GiveFeedback, 0, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
126 { DT_DragLeave, 0, 0, 0, 0 },
127
128 { DoDragDrop_ret, DRAGDROP_S_DROP, 0, 0, 0 },
129 { DoDragDrop_effect_out, 0, 0, 0, 0 },
130 { end_seq, 0, 0, 0, 0 }
131 },
132 { /* Multiple initial effects */
133 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0 },
134 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
135 { EnumFMT_Next, 0, S_OK, 0, 1 },
136 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
137 { EnumFMT_Reset, 0, S_OK, 0, 1 },
138 { EnumFMT_Next, 0, S_OK, 0, 1 },
139 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
140 { DO_QueryGetData, 0, S_OK, 0, 1 },
141
142 { DS_QueryContinueDrag, 0, DRAGDROP_S_DROP, 0, 0 },
143 { DT_DragEnter, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
144 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
145 { DT_Drop, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0, 0, 0 },
146
147 { DoDragDrop_ret, DRAGDROP_S_DROP, 0, 0, 0 },
148 { DoDragDrop_effect_out, 0, 0, 0, 0 },
149 { end_seq, 0, 0, 0, 0 }
150 },
151 { /* First couple of QueryContinueDrag return S_OK followed by a drop */
152 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0 },
153 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
154 { EnumFMT_Next, 0, S_OK, 0, 1 },
155 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
156 { EnumFMT_Reset, 0, S_OK, 0, 1 },
157 { EnumFMT_Next, 0, S_OK, 0, 1 },
158 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
159 { DO_QueryGetData, 0, S_OK, 0, 1 },
160
161 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
162 { DT_DragEnter, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
163 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
164 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
165 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
166
167 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
168 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
169 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
170
171 { DS_QueryContinueDrag, 0, DRAGDROP_S_DROP, 0, 0 },
172 { DT_Drop, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0, 0, 0 },
173
174 { DoDragDrop_ret, DRAGDROP_S_DROP, 0, 0, 0 },
175 { DoDragDrop_effect_out, 0, 0, 0, 0 },
176 { end_seq, 0, 0, 0, 0 }
177 },
178 { /* First QueryContinueDrag cancels */
179 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0 },
180 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
181 { EnumFMT_Next, 0, S_OK, 0, 1 },
182 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
183 { EnumFMT_Reset, 0, S_OK, 0, 1 },
184 { EnumFMT_Next, 0, S_OK, 0, 1 },
185 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
186 { DO_QueryGetData, 0, S_OK, 0, 1 },
187
188 { DS_QueryContinueDrag, 0, DRAGDROP_S_CANCEL, 0, 0 },
189
190 { DoDragDrop_ret, DRAGDROP_S_CANCEL, 0, 0, 0 },
191 { DoDragDrop_effect_out, 0, 0, 0, 0 },
192 { end_seq, 0, 0, 0, 0 }
193 },
194 { /* First couple of QueryContinueDrag return S_OK followed by a cancel */
195 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0 },
196 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
197 { EnumFMT_Next, 0, S_OK, 0, 1 },
198 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
199 { EnumFMT_Reset, 0, S_OK, 0, 1 },
200 { EnumFMT_Next, 0, S_OK, 0, 1 },
201 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
202 { DO_QueryGetData, 0, S_OK, 0, 1 },
203
204 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
205 { DT_DragEnter, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
206 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
207 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
208 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
209
210 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
211 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
212 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
213
214 { DS_QueryContinueDrag, 0, DRAGDROP_S_CANCEL, 0, 0 },
215 { DT_DragLeave, 0, 0, 0, 0 },
216
217 { DoDragDrop_ret, DRAGDROP_S_CANCEL, 0, 0, 0 },
218 { DoDragDrop_effect_out, 0, 0, 0, 0 },
219 { end_seq, 0, 0, 0, 0 }
220 },
221 { /* First couple of QueryContinueDrag return S_OK followed by a E_FAIL */
222 { DoDragDrop_effect_in, 0, 0, DROPEFFECT_COPY | DROPEFFECT_MOVE, 0 },
223 { DO_EnumFormatEtc, 0, S_OK, 0, 1 },
224 { EnumFMT_Next, 0, S_OK, 0, 1 },
225 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
226 { EnumFMT_Reset, 0, S_OK, 0, 1 },
227 { EnumFMT_Next, 0, S_OK, 0, 1 },
228 { EnumFMT_Next, 0, S_FALSE, 0, 1 },
229 { DO_QueryGetData, 0, S_OK, 0, 1 },
230
231 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
232 { DT_DragEnter, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
233 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
234 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
235 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
236
237 { DS_QueryContinueDrag, 0, S_OK, 0, 0 },
238 { DT_DragOver, DROPEFFECT_COPY | DROPEFFECT_MOVE, S_OK, DROPEFFECT_COPY, 0 },
239 { DS_GiveFeedback, DROPEFFECT_COPY, DRAGDROP_S_USEDEFAULTCURSORS, 0, 0 },
240
241 { DS_QueryContinueDrag, 0, E_FAIL, 0, 0 },
242 { DT_DragLeave, 0, 0, 0, 0 },
243
244 { DoDragDrop_ret, E_FAIL, 0, 0, 0 },
245 { DoDragDrop_effect_out, 0, 0, 0, 0 },
246 { end_seq, 0, 0, 0, 0 }
247 },
248 };
249
250 static int droptarget_refs;
251
252 /* helper macros to make tests a bit leaner */
253 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
254
255 static HRESULT WINAPI DropTarget_QueryInterface(IDropTarget* iface, REFIID riid,
256 void** ppvObject)
257 {
258 ok(0, "DropTarget_QueryInterface() shouldn't be called\n");
259 if (IsEqualIID(riid, &IID_IUnknown) ||
260 IsEqualIID(riid, &IID_IDropTarget))
261 {
262 IDropTarget_AddRef(iface);
263 *ppvObject = iface;
264 return S_OK;
265 }
266 *ppvObject = NULL;
267 return E_NOINTERFACE;
268 }
269
270 static ULONG WINAPI DropTarget_AddRef(IDropTarget* iface)
271 {
272 droptarget_refs++;
273 return droptarget_refs;
274 }
275
276 static ULONG WINAPI DropTarget_Release(IDropTarget* iface)
277 {
278 droptarget_refs--;
279 return droptarget_refs;
280 }
281
282 static HRESULT WINAPI DropTarget_DragEnter(IDropTarget* iface,
283 IDataObject* pDataObj,
284 DWORD grfKeyState, POINTL pt,
285 DWORD* pdwEffect)
286 {
287 return check_expect(DT_DragEnter, *pdwEffect, pdwEffect);
288 }
289
290 static HRESULT WINAPI DropTarget_DragOver(IDropTarget* iface,
291 DWORD grfKeyState,
292 POINTL pt,
293 DWORD* pdwEffect)
294 {
295 return check_expect(DT_DragOver, *pdwEffect, pdwEffect);
296 }
297
298 static HRESULT WINAPI DropTarget_DragLeave(IDropTarget* iface)
299 {
300 return check_expect(DT_DragLeave, 0, NULL);
301 }
302
303 static HRESULT WINAPI DropTarget_Drop(IDropTarget* iface,
304 IDataObject* pDataObj, DWORD grfKeyState,
305 POINTL pt, DWORD* pdwEffect)
306 {
307 return check_expect(DT_Drop, *pdwEffect, pdwEffect);
308 }
309
310 static const IDropTargetVtbl DropTarget_VTbl =
311 {
312 DropTarget_QueryInterface,
313 DropTarget_AddRef,
314 DropTarget_Release,
315 DropTarget_DragEnter,
316 DropTarget_DragOver,
317 DropTarget_DragLeave,
318 DropTarget_Drop
319 };
320
321 static IDropTarget DropTarget = { &DropTarget_VTbl };
322
323 static HRESULT WINAPI DropSource_QueryInterface(IDropSource *iface, REFIID riid, void **ppObj)
324 {
325 if (IsEqualIID(riid, &IID_IUnknown) ||
326 IsEqualIID(riid, &IID_IDropSource))
327 {
328 *ppObj = iface;
329 IDropSource_AddRef(iface);
330 return S_OK;
331 }
332 return E_NOINTERFACE;
333 }
334
335 static ULONG WINAPI DropSource_AddRef(IDropSource *iface)
336 {
337 return 2;
338 }
339
340 static ULONG WINAPI DropSource_Release(IDropSource *iface)
341 {
342 return 1;
343 }
344
345 static HRESULT WINAPI DropSource_QueryContinueDrag(
346 IDropSource *iface,
347 BOOL fEscapePressed,
348 DWORD grfKeyState)
349 {
350 return check_expect(DS_QueryContinueDrag, 0, NULL);
351 }
352
353 static HRESULT WINAPI DropSource_GiveFeedback(
354 IDropSource *iface,
355 DWORD dwEffect)
356 {
357 return check_expect(DS_GiveFeedback, dwEffect, NULL);
358 }
359
360 static const IDropSourceVtbl dropsource_vtbl = {
361 DropSource_QueryInterface,
362 DropSource_AddRef,
363 DropSource_Release,
364 DropSource_QueryContinueDrag,
365 DropSource_GiveFeedback
366 };
367
368 static IDropSource DropSource = { &dropsource_vtbl };
369
370 static HRESULT WINAPI EnumFORMATETC_QueryInterface(IEnumFORMATETC *iface,
371 REFIID riid, void **ppvObj)
372 {
373 ok(0, "unexpected call\n");
374 return E_NOTIMPL;
375 }
376
377 static ULONG WINAPI EnumFORMATETC_AddRef(IEnumFORMATETC *iface)
378 {
379 return 2;
380 }
381
382 static ULONG WINAPI EnumFORMATETC_Release(IEnumFORMATETC *iface)
383 {
384 return 1;
385 }
386
387 static HRESULT WINAPI EnumFORMATETC_Next(IEnumFORMATETC *iface,
388 ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched)
389 {
390 static FORMATETC format = { CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
391 HRESULT hr = check_expect(EnumFMT_Next, 0, NULL);
392
393 ok(celt == 1, "celt = %d\n", celt);
394 ok(rgelt != NULL, "rgelt == NULL\n");
395 ok(pceltFetched == NULL, "pceltFetched != NULL\n");
396
397 *rgelt = format;
398 return hr;
399 }
400
401 static HRESULT WINAPI EnumFORMATETC_Skip(IEnumFORMATETC *iface, ULONG celt)
402 {
403 return check_expect(EnumFMT_Skip, 0, NULL);
404 }
405
406 static HRESULT WINAPI EnumFORMATETC_Reset(IEnumFORMATETC *iface)
407 {
408 return check_expect(EnumFMT_Reset, 0, NULL);
409 }
410
411 static HRESULT WINAPI EnumFORMATETC_Clone(IEnumFORMATETC *iface,
412 IEnumFORMATETC **ppenum)
413 {
414 ok(0, "unexpected call\n");
415 return E_NOTIMPL;
416 }
417
418 static const IEnumFORMATETCVtbl enumformatetc_vtbl = {
419 EnumFORMATETC_QueryInterface,
420 EnumFORMATETC_AddRef,
421 EnumFORMATETC_Release,
422 EnumFORMATETC_Next,
423 EnumFORMATETC_Skip,
424 EnumFORMATETC_Reset,
425 EnumFORMATETC_Clone
426 };
427
428 static IEnumFORMATETC EnumFORMATETC = { &enumformatetc_vtbl };
429
430 static HRESULT WINAPI DataObject_QueryInterface(
431 IDataObject *iface,
432 REFIID riid,
433 void **pObj)
434 {
435 if (IsEqualIID(riid, &IID_IUnknown) ||
436 IsEqualIID(riid, &IID_IDataObject))
437 {
438 *pObj = iface;
439 IDataObject_AddRef(iface);
440 return S_OK;
441 }
442
443 trace("DataObject_QueryInterface: %s\n", wine_dbgstr_guid(riid));
444 return E_NOINTERFACE;
445 }
446
447 static ULONG WINAPI DataObject_AddRef(IDataObject *iface)
448 {
449 return 2;
450 }
451
452 static ULONG WINAPI DataObject_Release(IDataObject *iface)
453 {
454 return 1;
455 }
456
457 static HRESULT WINAPI DataObject_GetData(
458 IDataObject *iface,
459 FORMATETC *pformatetcIn,
460 STGMEDIUM *pmedium)
461 {
462 ok(0, "unexpected call\n");
463 return E_NOTIMPL;
464 }
465
466 static HRESULT WINAPI DataObject_GetDataHere(
467 IDataObject *iface,
468 FORMATETC *pformatetc,
469 STGMEDIUM *pmedium)
470 {
471 ok(0, "unexpected call\n");
472 return E_NOTIMPL;
473 }
474
475 static HRESULT WINAPI DataObject_QueryGetData(
476 IDataObject *iface,
477 FORMATETC *pformatetc)
478 {
479 return check_expect(DO_QueryGetData, 0, NULL);
480 }
481
482 static HRESULT WINAPI DataObject_GetCanonicalFormatEtc(
483 IDataObject *iface,
484 FORMATETC *pformatectIn,
485 FORMATETC *pformatetcOut)
486 {
487 ok(0, "unexpected call\n");
488 return E_NOTIMPL;
489 }
490
491 static HRESULT WINAPI DataObject_SetData(
492 IDataObject *iface,
493 FORMATETC *pformatetc,
494 STGMEDIUM *pmedium,
495 BOOL fRelease)
496 {
497 ok(0, "unexpected call\n");
498 return E_NOTIMPL;
499 }
500
501 static HRESULT WINAPI DataObject_EnumFormatEtc(
502 IDataObject *iface,
503 DWORD dwDirection,
504 IEnumFORMATETC **ppenumFormatEtc)
505 {
506 HRESULT hr = check_expect(DO_EnumFormatEtc, 0, NULL);
507 *ppenumFormatEtc = &EnumFORMATETC;
508 return hr;
509 }
510
511 static HRESULT WINAPI DataObject_DAdvise(
512 IDataObject *iface,
513 FORMATETC *pformatetc,
514 DWORD advf,
515 IAdviseSink *pAdvSink,
516 DWORD *pdwConnection)
517 {
518 ok(0, "unexpected call\n");
519 return E_NOTIMPL;
520 }
521
522 static HRESULT WINAPI DataObject_DUnadvise(
523 IDataObject *iface,
524 DWORD dwConnection)
525 {
526 ok(0, "unexpected call\n");
527 return E_NOTIMPL;
528 }
529
530 static HRESULT WINAPI DataObject_EnumDAdvise(
531 IDataObject *iface,
532 IEnumSTATDATA **ppenumAdvise)
533 {
534 ok(0, "unexpected call\n");
535 return E_NOTIMPL;
536 }
537
538 static const IDataObjectVtbl dataobject_vtbl = {
539 DataObject_QueryInterface,
540 DataObject_AddRef,
541 DataObject_Release,
542 DataObject_GetData,
543 DataObject_GetDataHere,
544 DataObject_QueryGetData,
545 DataObject_GetCanonicalFormatEtc,
546 DataObject_SetData,
547 DataObject_EnumFormatEtc,
548 DataObject_DAdvise,
549 DataObject_DUnadvise,
550 DataObject_EnumDAdvise
551 };
552
553 static IDataObject DataObject = { &dataobject_vtbl };
554
555 static ATOM register_dummy_class(void)
556 {
557 WNDCLASSA wc =
558 {
559 0,
560 DefWindowProcA,
561 0,
562 0,
563 GetModuleHandleA(NULL),
564 NULL,
565 LoadCursorA(NULL, (LPSTR)IDC_ARROW),
566 (HBRUSH)(COLOR_BTNFACE+1),
567 NULL,
568 "WineOleTestClass",
569 };
570
571 return RegisterClassA(&wc);
572 }
573
574 static void test_Register_Revoke(void)
575 {
576 HANDLE prop;
577 HRESULT hr;
578 HWND hwnd;
579
580 hwnd = CreateWindowA("WineOleTestClass", "Test", 0,
581 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
582 NULL, NULL, NULL);
583
584 hr = RegisterDragDrop(hwnd, &DropTarget);
585 ok(hr == E_OUTOFMEMORY ||
586 broken(hr == CO_E_NOTINITIALIZED), /* NT4 */
587 "RegisterDragDrop without OLE initialized should have returned E_OUTOFMEMORY instead of 0x%08x\n", hr);
588
589 OleInitialize(NULL);
590
591 hr = RegisterDragDrop(hwnd, NULL);
592 ok(hr == E_INVALIDARG, "RegisterDragDrop with NULL IDropTarget * should return E_INVALIDARG instead of 0x%08x\n", hr);
593
594 hr = RegisterDragDrop(NULL, &DropTarget);
595 ok(hr == DRAGDROP_E_INVALIDHWND, "RegisterDragDrop with NULL hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
596
597 hr = RegisterDragDrop((HWND)0xdeadbeef, &DropTarget);
598 ok(hr == DRAGDROP_E_INVALIDHWND, "RegisterDragDrop with garbage hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
599
600 ok(droptarget_refs == 0, "DropTarget refs should be zero not %d\n", droptarget_refs);
601 hr = RegisterDragDrop(hwnd, &DropTarget);
602 ok_ole_success(hr, "RegisterDragDrop");
603 ok(droptarget_refs >= 1, "DropTarget refs should be at least one\n");
604
605 prop = GetPropA(hwnd, "OleDropTargetInterface");
606 ok(prop == &DropTarget, "expected IDropTarget pointer %p, got %p\n", &DropTarget, prop);
607
608 hr = RegisterDragDrop(hwnd, &DropTarget);
609 ok(hr == DRAGDROP_E_ALREADYREGISTERED, "RegisterDragDrop with already registered hwnd should return DRAGDROP_E_ALREADYREGISTERED instead of 0x%08x\n", hr);
610
611 ok(droptarget_refs >= 1, "DropTarget refs should be at least one\n");
612 OleUninitialize();
613
614 /* Win 8 releases the ref in OleUninitialize() */
615 if (droptarget_refs >= 1)
616 {
617 hr = RevokeDragDrop(hwnd);
618 ok_ole_success(hr, "RevokeDragDrop");
619 ok(droptarget_refs == 0 ||
620 broken(droptarget_refs == 1), /* NT4 */
621 "DropTarget refs should be zero not %d\n", droptarget_refs);
622 }
623
624 hr = RevokeDragDrop(NULL);
625 ok(hr == DRAGDROP_E_INVALIDHWND, "RevokeDragDrop with NULL hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr);
626
627 DestroyWindow(hwnd);
628
629 /* try to revoke with already destroyed window */
630 OleInitialize(NULL);
631
632 hwnd = CreateWindowA("WineOleTestClass", "Test", 0,
633 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
634 NULL, NULL, NULL);
635
636 hr = RegisterDragDrop(hwnd, &DropTarget);
637 ok(hr == S_OK, "got 0x%08x\n", hr);
638
639 DestroyWindow(hwnd);
640
641 hr = RevokeDragDrop(hwnd);
642 ok(hr == DRAGDROP_E_INVALIDHWND, "got 0x%08x\n", hr);
643
644 OleUninitialize();
645 }
646
647 static void test_DoDragDrop(void)
648 {
649 DWORD effect;
650 HRESULT hr;
651 HWND hwnd;
652 RECT rect;
653 int seq;
654
655 hwnd = CreateWindowExA(WS_EX_TOPMOST, "WineOleTestClass", "Test", 0,
656 CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL,
657 NULL, NULL, NULL);
658 ok(IsWindow(hwnd), "failed to create window\n");
659
660 hr = OleInitialize(NULL);
661 ok(hr == S_OK, "got 0x%08x\n", hr);
662
663 hr = RegisterDragDrop(hwnd, &DropTarget);
664 ok(hr == S_OK, "got 0x%08x\n", hr);
665
666 /* incomplete arguments set */
667 hr = DoDragDrop(NULL, NULL, 0, NULL);
668 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
669
670 hr = DoDragDrop(NULL, &DropSource, 0, NULL);
671 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
672
673 hr = DoDragDrop(&DataObject, NULL, 0, NULL);
674 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
675
676 hr = DoDragDrop(NULL, NULL, 0, &effect);
677 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
678
679 hr = DoDragDrop(&DataObject, &DropSource, 0, NULL);
680 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
681
682 hr = DoDragDrop(NULL, &DropSource, 0, &effect);
683 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
684
685 hr = DoDragDrop(&DataObject, NULL, 0, &effect);
686 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
687
688 ShowWindow(hwnd, SW_SHOW);
689 GetWindowRect(hwnd, &rect);
690 ok(SetCursorPos(rect.left+50, rect.top+50), "SetCursorPos failed\n");
691
692 for (seq = 0; seq < sizeof(call_lists) / sizeof(call_lists[0]); seq++)
693 {
694 DWORD effect_in;
695 trace("%d\n", seq);
696 call_ptr = call_lists[seq];
697 effect_in = call_ptr->set_param;
698 call_ptr++;
699
700 hr = DoDragDrop(&DataObject, &DropSource, effect_in, &effect);
701 check_expect(DoDragDrop_ret, hr, NULL);
702 check_expect(DoDragDrop_effect_out, effect, NULL);
703 }
704
705 OleUninitialize();
706
707 DestroyWindow(hwnd);
708 }
709
710 START_TEST(dragdrop)
711 {
712 register_dummy_class();
713
714 test_Register_Revoke();
715 #ifdef __REACTOS__
716 if (!winetest_interactive &&
717 !strcmp(winetest_platform, "windows"))
718 {
719 skip("ROSTESTS-182: Skipping ole32_winetest:dragdrop test_DoDragDrop because it hangs on WHS-Testbot. Set winetest_interactive to run it anyway.\n");
720 return;
721 }
722 #endif
723 test_DoDragDrop();
724 }