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