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 } 725