1 /* 2 * Unit tests for IShellDispatch 3 * 4 * Copyright 2010 Alexander Morozov for Etersoft 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 COBJMACROS 22 #define NONAMELESSUNION 23 #define NONAMELESSSTRUCT 24 25 #include "shldisp.h" 26 #include "shlobj.h" 27 #include "shlwapi.h" 28 #include "winsvc.h" 29 30 #include "wine/heap.h" 31 #include "wine/test.h" 32 33 #include "initguid.h" 34 35 #define EXPECT_HR(hr,hr_exp) \ 36 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp) 37 38 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown *)obj, ref, __LINE__) 39 static void _expect_ref(IUnknown *obj, ULONG ref, int line) 40 { 41 ULONG rc; 42 IUnknown_AddRef(obj); 43 rc = IUnknown_Release(obj); 44 ok_(__FILE__,line)(rc == ref, "Unexpected refcount %d, expected %d\n", rc, ref); 45 } 46 47 static const WCHAR winetestW[] = {'w','i','n','e','t','e','s','t',0}; 48 49 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*); 50 51 /* Updated Windows 7 has a new IShellDispatch6 in its typelib */ 52 DEFINE_GUID(IID_IWin7ShellDispatch6, 0x34936ba1, 0x67ad, 0x4c41, 0x99,0xb8, 0x8c,0x12,0xdf,0xf1,0xe9,0x74); 53 54 static BSTR a2bstr(const char *str) 55 { 56 BSTR ret; 57 int len; 58 59 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); 60 ret = SysAllocStringLen(NULL, len); 61 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); 62 63 return ret; 64 } 65 66 static void variant_set_string(VARIANT *v, const char *s) 67 { 68 V_VT(v) = VT_BSTR; 69 V_BSTR(v) = a2bstr(s); 70 } 71 72 static void init_function_pointers(void) 73 { 74 HMODULE hshell32; 75 76 hshell32 = GetModuleHandleA("shell32.dll"); 77 pSHGetNameFromIDList = (void*)GetProcAddress(hshell32, "SHGetNameFromIDList"); 78 } 79 80 static void test_namespace(void) 81 { 82 static const ShellSpecialFolderConstants special_folders[] = 83 { 84 ssfDESKTOP, 85 ssfPROGRAMS, 86 ssfCONTROLS, 87 ssfPRINTERS, 88 ssfPERSONAL, 89 ssfFAVORITES, 90 ssfSTARTUP, 91 ssfRECENT, 92 ssfSENDTO, 93 ssfBITBUCKET, 94 ssfSTARTMENU, 95 ssfDESKTOPDIRECTORY, 96 ssfDRIVES, 97 ssfNETWORK, 98 ssfNETHOOD, 99 ssfFONTS, 100 ssfTEMPLATES, 101 ssfCOMMONSTARTMENU, 102 ssfCOMMONPROGRAMS, 103 ssfCOMMONSTARTUP, 104 ssfCOMMONDESKTOPDIR, 105 ssfAPPDATA, 106 ssfPRINTHOOD, 107 ssfLOCALAPPDATA, 108 ssfALTSTARTUP, 109 ssfCOMMONALTSTARTUP, 110 ssfCOMMONFAVORITES, 111 ssfINTERNETCACHE, 112 ssfCOOKIES, 113 ssfHISTORY, 114 ssfCOMMONAPPDATA, 115 ssfWINDOWS, 116 ssfSYSTEM, 117 ssfPROGRAMFILES, 118 ssfMYPICTURES, 119 ssfPROFILE, 120 ssfSYSTEMx86, 121 ssfPROGRAMFILESx86, 122 }; 123 124 static const WCHAR backslashW[] = {'\\',0}; 125 static const WCHAR clsidW[] = { 126 ':',':','{','6','4','5','F','F','0','4','0','-','5','0','8','1','-', 127 '1','0','1','B','-','9','F','0','8','-', 128 '0','0','A','A','0','0','2','F','9','5','4','E','}',0}; 129 130 static WCHAR tempW[MAX_PATH], curW[MAX_PATH]; 131 WCHAR *long_pathW = NULL; 132 HRESULT r; 133 IShellDispatch *sd; 134 Folder *folder; 135 Folder2 *folder2; 136 FolderItem *item; 137 VARIANT var; 138 BSTR title, item_path; 139 IDispatch *disp; 140 int len, i; 141 142 r = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, &IID_IShellDispatch, (void **)&sd); 143 ok(SUCCEEDED(r), "Failed to create ShellDispatch object: %#x.\n", r); 144 145 disp = NULL; 146 r = IShellDispatch_get_Application(sd, &disp); 147 ok(r == S_OK, "Failed to get application pointer, hr %#x.\n", r); 148 ok(disp == (IDispatch *)sd, "Unexpected application pointer %p.\n", disp); 149 IDispatch_Release(disp); 150 151 disp = NULL; 152 r = IShellDispatch_get_Parent(sd, &disp); 153 ok(r == S_OK, "Failed to get Shell object parent, hr %#x.\n", r); 154 ok(disp == (IDispatch *)sd, "Unexpected parent pointer %p.\n", disp); 155 IDispatch_Release(disp); 156 157 VariantInit(&var); 158 folder = (void*)0xdeadbeef; 159 r = IShellDispatch_NameSpace(sd, var, &folder); 160 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 161 ok(folder == NULL, "expected NULL, got %p\n", folder); 162 163 /* test valid folder ids */ 164 for (i = 0; i < sizeof(special_folders)/sizeof(special_folders[0]); i++) 165 { 166 V_VT(&var) = VT_I4; 167 V_I4(&var) = special_folders[i]; 168 folder = (void*)0xdeadbeef; 169 r = IShellDispatch_NameSpace(sd, var, &folder); 170 if (special_folders[i] == ssfALTSTARTUP || special_folders[i] == ssfCOMMONALTSTARTUP) 171 todo_wine 172 ok(r == S_OK || broken(r == S_FALSE) /* winxp */, "Failed to get folder for index %#x, got %08x\n", special_folders[i], r); 173 else 174 ok(r == S_OK, "Failed to get folder for index %#x, got %08x\n", special_folders[i], r); 175 if (folder) 176 Folder_Release(folder); 177 } 178 179 V_VT(&var) = VT_I4; 180 V_I4(&var) = -1; 181 folder = (void *)0xdeadbeef; 182 r = IShellDispatch_NameSpace(sd, var, &folder); 183 ok(r == S_FALSE, "Unexpected hr %#x.\n", r); 184 ok(folder == NULL, "Unexpected folder instance %p\n", folder); 185 186 V_VT(&var) = VT_I4; 187 V_I4(&var) = ssfPROGRAMFILES; 188 r = IShellDispatch_NameSpace(sd, var, &folder); 189 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r); 190 if (r == S_OK) 191 { 192 static WCHAR path[MAX_PATH]; 193 194 r = SHGetFolderPathW(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, path); 195 ok(r == S_OK, "Failed to get folder path: %#x.\n", r); 196 197 r = Folder_get_Title(folder, &title); 198 ok(r == S_OK, "Folder::get_Title failed: %08x\n", r); 199 if (r == S_OK) 200 { 201 /* On Win2000-2003 title is equal to program files directory name in 202 HKLM\Software\Microsoft\Windows\CurrentVersion\ProgramFilesDir. 203 On newer Windows it seems constant and is not changed 204 if the program files directory name is changed */ 205 if (pSHGetNameFromIDList) 206 { 207 LPITEMIDLIST pidl; 208 PWSTR name; 209 210 r = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl); 211 ok(r == S_OK, "SHGetSpecialFolderLocation failed: %08x\n", r); 212 r = pSHGetNameFromIDList(pidl, SIGDN_NORMALDISPLAY, &name); 213 ok(r == S_OK, "SHGetNameFromIDList failed: %08x\n", r); 214 ok(!lstrcmpW(title, name), "expected %s, got %s\n", wine_dbgstr_w(name), wine_dbgstr_w(title)); 215 CoTaskMemFree(name); 216 CoTaskMemFree(pidl); 217 } 218 else 219 { 220 WCHAR *p; 221 222 p = path + lstrlenW(path); 223 while (path < p && *(p - 1) != '\\') 224 p--; 225 ok(!lstrcmpiW(title, p), "expected %s, got %s\n", 226 wine_dbgstr_w(p), wine_dbgstr_w(title)); 227 } 228 SysFreeString(title); 229 } 230 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2); 231 ok(r == S_OK, "Folder::QueryInterface failed: %08x\n", r); 232 if (r == S_OK) 233 { 234 r = Folder2_get_Self(folder2, &item); 235 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r); 236 if (r == S_OK) 237 { 238 r = FolderItem_get_Path(item, &item_path); 239 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r); 240 ok(!lstrcmpiW(item_path, path), "expected %s, got %s\n", wine_dbgstr_w(path), wine_dbgstr_w(item_path)); 241 SysFreeString(item_path); 242 FolderItem_Release(item); 243 } 244 Folder2_Release(folder2); 245 } 246 Folder_Release(folder); 247 } 248 249 V_VT(&var) = VT_I4; 250 V_I4(&var) = ssfBITBUCKET; 251 r = IShellDispatch_NameSpace(sd, var, &folder); 252 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r); 253 254 r = Folder_QueryInterface(folder, &IID_Folder2, (void **)&folder2); 255 ok(r == S_OK, "Failed to get Folder2 interface: %#x.\n", r); 256 r = Folder2_get_Self(folder2, &item); 257 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r); 258 r = FolderItem_get_Path(item, &item_path); 259 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r); 260 /* TODO: we return lowercase GUID here */ 261 ok(!lstrcmpiW(item_path, clsidW), "expected %s, got %s\n", wine_dbgstr_w(clsidW), wine_dbgstr_w(item_path)); 262 263 SysFreeString(item_path); 264 FolderItem_Release(item); 265 Folder2_Release(folder2); 266 Folder_Release(folder); 267 268 GetTempPathW(MAX_PATH, tempW); 269 GetCurrentDirectoryW(MAX_PATH, curW); 270 SetCurrentDirectoryW(tempW); 271 CreateDirectoryW(winetestW, NULL); 272 V_VT(&var) = VT_BSTR; 273 V_BSTR(&var) = SysAllocString(winetestW); 274 r = IShellDispatch_NameSpace(sd, var, &folder); 275 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 276 SysFreeString(V_BSTR(&var)); 277 278 GetFullPathNameW(winetestW, MAX_PATH, tempW, NULL); 279 280 len = GetLongPathNameW(tempW, NULL, 0); 281 long_pathW = heap_alloc(len * sizeof(WCHAR)); 282 GetLongPathNameW(tempW, long_pathW, len); 283 284 V_VT(&var) = VT_BSTR; 285 V_BSTR(&var) = SysAllocString(tempW); 286 r = IShellDispatch_NameSpace(sd, var, &folder); 287 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r); 288 289 disp = (void *)0xdeadbeef; 290 r = Folder_get_Parent(folder, &disp); 291 ok(r == E_NOTIMPL, "Unexpected hr %#x.\n", r); 292 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp); 293 294 r = Folder_get_Title(folder, &title); 295 ok(r == S_OK, "Failed to get folder title: %#x.\n", r); 296 ok(!lstrcmpW(title, winetestW), "Unexpected title: %s\n", wine_dbgstr_w(title)); 297 SysFreeString(title); 298 299 r = Folder_QueryInterface(folder, &IID_Folder2, (void **)&folder2); 300 ok(r == S_OK, "Failed to get Folder2 interface: %#x.\n", r); 301 r = Folder2_get_Self(folder2, &item); 302 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r); 303 r = FolderItem_get_Path(item, &item_path); 304 ok(r == S_OK, "Failed to get item path: %#x.\n", r); 305 ok(!lstrcmpW(item_path, long_pathW), "Unexpected path %s, got %s\n", wine_dbgstr_w(item_path), wine_dbgstr_w(long_pathW)); 306 SysFreeString(item_path); 307 FolderItem_Release(item); 308 Folder2_Release(folder2); 309 310 Folder_Release(folder); 311 VariantClear(&var); 312 313 len = lstrlenW(tempW); 314 if (len < MAX_PATH - 1) 315 { 316 lstrcatW(tempW, backslashW); 317 V_VT(&var) = VT_BSTR; 318 V_BSTR(&var) = SysAllocString(tempW); 319 r = IShellDispatch_NameSpace(sd, var, &folder); 320 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r); 321 if (r == S_OK) 322 { 323 r = Folder_get_Title(folder, &title); 324 ok(r == S_OK, "Folder::get_Title failed: %08x\n", r); 325 if (r == S_OK) 326 { 327 ok(!lstrcmpW(title, winetestW), "bad title: %s\n", 328 wine_dbgstr_w(title)); 329 SysFreeString(title); 330 } 331 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2); 332 ok(r == S_OK, "Failed to get Folder2 interface: %#x.\n", r); 333 if (r == S_OK) 334 { 335 r = Folder2_get_Self(folder2, &item); 336 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r); 337 if (r == S_OK) 338 { 339 r = FolderItem_get_Path(item, &item_path); 340 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r); 341 ok(!lstrcmpW(item_path, long_pathW), "Unexpected path %s, got %s\n", wine_dbgstr_w(item_path), 342 wine_dbgstr_w(long_pathW)); 343 SysFreeString(item_path); 344 FolderItem_Release(item); 345 } 346 Folder2_Release(folder2); 347 } 348 Folder_Release(folder); 349 } 350 SysFreeString(V_BSTR(&var)); 351 } 352 353 heap_free(long_pathW); 354 RemoveDirectoryW(winetestW); 355 SetCurrentDirectoryW(curW); 356 IShellDispatch_Release(sd); 357 } 358 359 static void test_items(void) 360 { 361 static const struct 362 { 363 char name[32]; 364 enum 365 { 366 DIRECTORY, 367 EMPTY_FILE, 368 } 369 type; 370 } 371 file_defs[] = 372 { 373 { "00-Myfolder", DIRECTORY }, 374 { "01-empty.bin", EMPTY_FILE }, 375 }; 376 WCHAR path[MAX_PATH], cur_dir[MAX_PATH], orig_dir[MAX_PATH]; 377 HRESULT r; 378 IShellDispatch *sd = NULL; 379 Folder *folder = NULL; 380 FolderItems *items; 381 FolderItems2 *items2 = NULL; 382 FolderItems3 *items3 = NULL; 383 FolderItem *item = (FolderItem*)0xdeadbeef, *item2; 384 FolderItemVerbs *verbs = (FolderItemVerbs*)0xdeadbeef; 385 VARIANT var, int_index, str_index, str_index2; 386 IDispatch *disp, *disp2; 387 LONG count = -1; 388 IUnknown *unk; 389 HANDLE file; 390 BSTR bstr; 391 char cstr[64]; 392 BOOL ret; 393 int i; 394 395 r = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, &IID_IShellDispatch, (void**)&sd); 396 ok(SUCCEEDED(r), "CoCreateInstance failed: %08x\n", r); 397 ok(!!sd, "sd is null\n"); 398 399 /* create and enter a temporary directory and a folder object for it */ 400 GetTempPathW(MAX_PATH, path); 401 GetCurrentDirectoryW(MAX_PATH, orig_dir); 402 SetCurrentDirectoryW(path); 403 ret = CreateDirectoryW(winetestW, NULL); 404 ok(ret, "CreateDirectory failed: %08x\n", GetLastError()); 405 GetFullPathNameW(winetestW, MAX_PATH, path, NULL); 406 V_VT(&var) = VT_BSTR; 407 V_BSTR(&var) = SysAllocString(path); 408 409 EXPECT_REF(sd, 1); 410 r = IShellDispatch_NameSpace(sd, var, &folder); 411 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r); 412 ok(!!folder, "folder is null\n"); 413 EXPECT_REF(folder, 1); 414 EXPECT_REF(sd, 1); 415 416 VariantClear(&var); 417 SetCurrentDirectoryW(winetestW); 418 GetCurrentDirectoryW(MAX_PATH, path); 419 GetLongPathNameW(path, cur_dir, MAX_PATH); 420 421 /* FolderItems grabs its Folder reference */ 422 items = NULL; 423 r = Folder_Items(folder, &items); 424 ok(r == S_OK, "Folder::Items failed: %08x\n", r); 425 ok(!!items, "items is null\n"); 426 EXPECT_REF(folder, 2); 427 EXPECT_REF(items, 1); 428 429 unk = NULL; 430 r = Folder_Items(folder, (FolderItems **)&unk); 431 ok(r == S_OK, "Folder::Items failed: %08x\n", r); 432 EXPECT_REF(folder, 3); 433 IUnknown_Release(unk); 434 EXPECT_REF(folder, 2); 435 436 FolderItems_AddRef(items); 437 EXPECT_REF(folder, 2); 438 FolderItems_Release(items); 439 440 /* Application property */ 441 disp = NULL; 442 EXPECT_REF(sd, 1); 443 r = Folder_get_Application(folder, &disp); 444 ok(r == S_OK, "Failed to get application %#x.\n", r); 445 ok(disp != (IDispatch *)sd, "Unexpected application pointer\n"); 446 EXPECT_REF(sd, 1); 447 448 disp2 = NULL; 449 r = Folder_get_Application(folder, &disp2); 450 ok(r == S_OK, "Failed to get application %#x.\n", r); 451 ok(disp2 == disp, "Unexpected application pointer\n"); 452 IDispatch_Release(disp2); 453 454 r = IDispatch_QueryInterface(disp, &IID_IShellDispatch, (void **)&disp2); 455 ok(r == S_OK, "Wrong instance, hr %#x.\n", r); 456 IDispatch_Release(disp2); 457 IDispatch_Release(disp); 458 459 if (0) /* crashes on all versions of Windows */ 460 r = FolderItems_get_Count(items, NULL); 461 462 r = FolderItems_get_Count(items, &count); 463 ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r); 464 ok(!count, "expected 0 files, got %d\n", count); 465 466 V_VT(&var) = VT_I4; 467 V_I4(&var) = 0; 468 469 if (0) /* crashes on all versions of Windows */ 470 r = FolderItems_Item(items, var, NULL); 471 472 r = FolderItems_Item(items, var, &item); 473 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 474 ok(!item, "item is not null\n"); 475 476 /* create test files */ 477 for (i = 0; i < sizeof(file_defs)/sizeof(file_defs[0]); i++) 478 { 479 switch (file_defs[i].type) 480 { 481 case DIRECTORY: 482 r = CreateDirectoryA(file_defs[i].name, NULL); 483 ok(r, "CreateDirectory failed: %08x\n", GetLastError()); 484 PathCombineA(cstr, file_defs[i].name, "foo.txt"); 485 file = CreateFileA(cstr, 0, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 486 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %08x\n", GetLastError()); 487 CloseHandle(file); 488 break; 489 490 case EMPTY_FILE: 491 file = CreateFileA(file_defs[i].name, 0, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 492 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %08x\n", GetLastError()); 493 CloseHandle(file); 494 break; 495 } 496 } 497 498 /* test that get_Count is not aware of the newly created files */ 499 count = -1; 500 r = FolderItems_get_Count(items, &count); 501 ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r); 502 ok(!count, "expected 0 files, got %d\n", count); 503 504 /* test that the newly created files CAN be retrieved by string index */ 505 variant_set_string(&var, file_defs[0].name); 506 item = NULL; 507 r = FolderItems_Item(items, var, &item); 508 ok(r == S_OK, "FolderItems::Item failed: %08x\n", r); 509 ok(!!item, "item is null\n"); 510 511 disp = (void *)0xdeadbeef; 512 r = FolderItems_get_Parent(items, &disp); 513 ok(r == E_NOTIMPL, "Unexpected hr %#x.\n", r); 514 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp); 515 516 r = FolderItem_get_Parent(item, &disp); 517 ok(r == S_OK, "Failed to get parent pointer, hr %#x.\n", r); 518 ok(disp == (IDispatch *)folder, "Unexpected parent pointer %p.\n", disp); 519 IDispatch_Release(disp); 520 521 if (item) FolderItem_Release(item); 522 VariantClear(&var); 523 524 /* recreate the items object */ 525 FolderItems_Release(items); 526 items = NULL; 527 r = Folder_Items(folder, &items); 528 ok(r == S_OK, "Folder::Items failed: %08x\n", r); 529 ok(!!items, "items is null\n"); 530 r = FolderItems_QueryInterface(items, &IID_FolderItems2, (void**)&items2); 531 ok(r == S_OK || broken(r == E_NOINTERFACE) /* xp and later */, "FolderItems::QueryInterface failed: %08x\n", r); 532 if (r == S_OK) 533 { 534 ok(!!items2, "items2 is null\n"); 535 FolderItems2_Release(items2); 536 } 537 r = FolderItems_QueryInterface(items, &IID_FolderItems3, (void**)&items3); 538 ok(r == S_OK, "FolderItems::QueryInterface failed: %08x\n", r); 539 ok(!!items3, "items3 is null\n"); 540 541 count = -1; 542 r = FolderItems_get_Count(items, &count); 543 ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r); 544 ok(count == sizeof(file_defs)/sizeof(file_defs[0]), 545 "expected %d files, got %d\n", (LONG)(sizeof(file_defs)/sizeof(file_defs[0])), count); 546 547 V_VT(&var) = VT_EMPTY; 548 item = (FolderItem*)0xdeadbeef; 549 r = FolderItems_Item(items, var, &item); 550 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r); 551 ok(!item, "item is not null\n"); 552 553 V_VT(&var) = VT_I2; 554 V_I2(&var) = 0; 555 556 EXPECT_REF(folder, 2); 557 EXPECT_REF(items, 2); 558 item = NULL; 559 r = FolderItems_Item(items, var, &item); 560 ok(r == S_OK, "FolderItems::Item failed: %08x\n", r); 561 ok(!!item, "item is null\n"); 562 EXPECT_REF(folder, 3); 563 EXPECT_REF(items, 2); 564 565 r = Folder_get_Application(folder, &disp); 566 ok(r == S_OK, "Failed to get application pointer %#x.\n", r); 567 r = FolderItem_get_Application(item, &disp2); 568 ok(r == S_OK, "Failed to get application pointer %#x.\n", r); 569 ok(disp == disp2, "Unexpected application pointer.\n"); 570 IDispatch_Release(disp2); 571 IDispatch_Release(disp); 572 573 FolderItem_Release(item); 574 575 V_VT(&var) = VT_I4; 576 V_I4(&var) = 0; 577 item = NULL; 578 r = FolderItems_Item(items, var, &item); 579 ok(r == S_OK, "FolderItems::Item failed: %08x\n", r); 580 ok(!!item, "item is null\n"); 581 if (item) FolderItem_Release(item); 582 583 V_I4(&var) = -1; 584 item = (FolderItem*)0xdeadbeef; 585 r = FolderItems_Item(items, var, &item); 586 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 587 ok(!item, "item is not null\n"); 588 589 V_VT(&var) = VT_ERROR; 590 V_ERROR(&var) = 0; 591 item = NULL; 592 r = FolderItems_Item(items, var, &item); 593 ok(r == S_OK, "expected S_OK, got %08x\n", r); 594 ok(!!item, "item is null\n"); 595 if (item) 596 { 597 bstr = NULL; 598 r = FolderItem_get_Path(item, &bstr); 599 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r); 600 ok(!lstrcmpW(bstr, cur_dir), 601 "expected %s, got %s\n", wine_dbgstr_w(cur_dir), wine_dbgstr_w(bstr)); 602 SysFreeString(bstr); 603 FolderItem_Release(item); 604 } 605 606 V_VT(&int_index) = VT_I4; 607 608 /* test the folder item corresponding to each file */ 609 for (i = 0; i < sizeof(file_defs)/sizeof(file_defs[0]); i++) 610 { 611 VARIANT_BOOL b; 612 BSTR name; 613 614 V_I4(&int_index) = i; 615 variant_set_string(&str_index, file_defs[i].name); 616 617 item = NULL; 618 r = FolderItems_Item(items, int_index, &item); 619 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); 620 ok(!!item, "file_defs[%d]: item is null\n", i); 621 622 item2 = NULL; 623 r = FolderItems_Item(items, int_index, &item2); 624 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); 625 ok(item2 != item, "file_defs[%d]: item and item2 are the same\n", i); 626 FolderItem_Release(item2); 627 628 bstr = NULL; 629 r = FolderItem_get_Path(item, &bstr); 630 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r); 631 PathCombineW(path, cur_dir, V_BSTR(&str_index)); 632 ok(!lstrcmpW(bstr, path), 633 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr)); 634 SysFreeString(bstr); 635 636 bstr = a2bstr(file_defs[i].name); 637 r = FolderItem_get_Name(item, &name); 638 ok(r == S_OK, "Failed to get item name, hr %#x.\n", r); 639 /* Returned display name does not have to strictly match file name, e.g. extension could be omitted. */ 640 ok(lstrlenW(name) <= lstrlenW(bstr), "file_defs[%d]: unexpected name length.\n", i); 641 ok(!memcmp(bstr, name, lstrlenW(name) * sizeof(WCHAR)), "file_defs[%d]: unexpected name %s.\n", i, wine_dbgstr_w(name)); 642 SysFreeString(name); 643 SysFreeString(bstr); 644 645 FolderItem_Release(item); 646 647 item = NULL; 648 r = FolderItems_Item(items, str_index, &item); 649 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); 650 ok(!!item, "file_defs[%d]: item is null\n", i); 651 652 bstr = NULL; 653 r = FolderItem_get_Path(item, &bstr); 654 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r); 655 PathCombineW(path, cur_dir, V_BSTR(&str_index)); 656 ok(!lstrcmpW(bstr, path), 657 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr)); 658 SysFreeString(bstr); 659 660 b = 0xdead; 661 r = FolderItem_get_IsFolder(item, &b); 662 ok(r == S_OK, "Failed to get IsFolder property, %#x.\n", r); 663 ok(file_defs[i].type == DIRECTORY ? b == VARIANT_TRUE : b == VARIANT_FALSE, "Unexpected prop value %#x.\n", b); 664 665 FolderItem_Release(item); 666 667 if (file_defs[i].type == DIRECTORY) 668 { 669 /* test that getting an item object for a file in a subdirectory succeeds */ 670 PathCombineA(cstr, file_defs[i].name, "foo.txt"); 671 variant_set_string(&str_index2, cstr); 672 item2 = NULL; 673 r = FolderItems_Item(items, str_index2, &item2); 674 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); 675 ok(!!item2, "file_defs[%d]: item is null\n", i); 676 if (item2) FolderItem_Release(item2); 677 VariantClear(&str_index2); 678 679 /* delete the file in the subdirectory */ 680 ret = DeleteFileA(cstr); 681 ok(ret, "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError()); 682 683 /* test that getting an item object via a relative path fails */ 684 strcpy(cstr, file_defs[i].name); 685 strcat(cstr, "\\..\\"); 686 strcat(cstr, file_defs[i].name); 687 variant_set_string(&str_index2, cstr); 688 item2 = (FolderItem*)0xdeadbeef; 689 r = FolderItems_Item(items, str_index2, &item2); 690 todo_wine { 691 ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08x\n", i, r); 692 ok(!item2, "file_defs[%d]: item is not null\n", i); 693 } 694 if (item2) FolderItem_Release(item2); 695 VariantClear(&str_index2); 696 697 /* remove the directory */ 698 ret = RemoveDirectoryA(file_defs[i].name); 699 ok(ret, "file_defs[%d]: RemoveDirectory failed: %08x\n", i, GetLastError()); 700 } 701 else 702 { 703 ret = DeleteFileA(file_defs[i].name); 704 ok(ret, "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError()); 705 } 706 707 /* test that the folder item is still accessible by integer index */ 708 item = NULL; 709 r = FolderItems_Item(items, int_index, &item); 710 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); 711 ok(!!item, "file_defs[%d]: item is null\n", i); 712 713 bstr = NULL; 714 r = FolderItem_get_Path(item, &bstr); 715 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r); 716 PathCombineW(path, cur_dir, V_BSTR(&str_index)); 717 ok(!lstrcmpW(bstr, path), 718 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr)); 719 SysFreeString(bstr); 720 721 FolderItem_Release(item); 722 723 /* test that the folder item is no longer accessible by string index */ 724 item = (FolderItem*)0xdeadbeef; 725 r = FolderItems_Item(items, str_index, &item); 726 ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08x\n", i, r); 727 ok(!item, "file_defs[%d]: item is not null\n", i); 728 729 VariantClear(&str_index); 730 } 731 732 /* test that there are only as many folder items as there were files */ 733 V_I4(&int_index) = sizeof(file_defs)/sizeof(file_defs[0]); 734 item = (FolderItem*)0xdeadbeef; 735 r = FolderItems_Item(items, int_index, &item); 736 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 737 ok(!item, "item is not null\n"); 738 739 if (0) /* crashes on xp */ 740 { 741 r = FolderItems_get_Application(items, NULL); 742 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r); 743 } 744 745 r = FolderItems_get_Application(items, &disp); 746 ok(r == S_OK, "FolderItems::get_Application failed: %08x\n", r); 747 748 r = Folder_get_Application(folder, &disp2); 749 ok(r == S_OK, "Failed to get application pointer, hr %#x.\n", r); 750 ok(disp == disp2, "Unexpected application pointer.\n"); 751 IDispatch_Release(disp2); 752 IDispatch_Release(disp); 753 754 if (0) /* crashes on xp */ 755 { 756 r = FolderItems_get_Parent(items, NULL); 757 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r); 758 } 759 760 disp = (IDispatch*)0xdeadbeef; 761 r = FolderItems_get_Parent(items, &disp); 762 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r); 763 ok(!disp, "disp is not null\n"); 764 765 if (0) /* crashes on xp */ 766 { 767 r = FolderItems__NewEnum(items, NULL); 768 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r); 769 } 770 771 r = FolderItems__NewEnum(items, &unk); 772 todo_wine 773 ok(r == S_OK, "FolderItems::_NewEnum failed: %08x\n", r); 774 todo_wine 775 ok(!!unk, "unk is null\n"); 776 if (unk) IUnknown_Release(unk); 777 778 if (items3) 779 { 780 r = FolderItems3_Filter(items3, 0, NULL); 781 todo_wine 782 ok(r == S_OK, "expected S_OK, got %08x\n", r); 783 784 if (0) /* crashes on xp */ 785 { 786 r = FolderItems3_get_Verbs(items3, NULL); 787 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r); 788 } 789 790 r = FolderItems3_get_Verbs(items3, &verbs); 791 todo_wine 792 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 793 ok(!verbs, "verbs is not null\n"); 794 } 795 796 /* remove the temporary directory and restore the original working directory */ 797 GetTempPathW(MAX_PATH, path); 798 SetCurrentDirectoryW(path); 799 ret = RemoveDirectoryW(winetestW); 800 ok(ret, "RemoveDirectory failed: %08x\n", GetLastError()); 801 SetCurrentDirectoryW(orig_dir); 802 803 /* test that everything stops working after the directory has been removed */ 804 count = -1; 805 r = FolderItems_get_Count(items, &count); 806 ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r); 807 ok(!count, "expected 0 files, got %d\n", count); 808 809 item = NULL; 810 V_I4(&int_index) = 0; 811 item = (FolderItem*)0xdeadbeef; 812 r = FolderItems_Item(items, int_index, &item); 813 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 814 ok(!item, "item is not null\n"); 815 816 variant_set_string(&str_index, file_defs[0].name); 817 item = (FolderItem*)0xdeadbeef; 818 r = FolderItems_Item(items, str_index, &item); 819 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 820 ok(!item, "item is not null\n"); 821 VariantClear(&str_index); 822 823 FolderItems_Release(items); 824 Folder_Release(folder); 825 if (items3) FolderItems3_Release(items3); 826 IShellDispatch_Release(sd); 827 } 828 829 static void test_service(void) 830 { 831 static const WCHAR spooler[] = {'S','p','o','o','l','e','r',0}; 832 static const WCHAR dummyW[] = {'d','u','m','m','y',0}; 833 SERVICE_STATUS_PROCESS status; 834 SC_HANDLE scm, service; 835 IShellDispatch2 *sd; 836 DWORD dummy; 837 HRESULT hr; 838 BSTR name; 839 VARIANT v; 840 841 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 842 &IID_IShellDispatch2, (void**)&sd); 843 if (hr != S_OK) 844 { 845 win_skip("IShellDispatch2 not supported\n"); 846 return; 847 } 848 849 V_VT(&v) = VT_I2; 850 V_I2(&v) = 10; 851 hr = IShellDispatch2_IsServiceRunning(sd, NULL, &v); 852 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v)); 853 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v)); 854 EXPECT_HR(hr, S_OK); 855 856 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); 857 service = OpenServiceW(scm, spooler, SERVICE_QUERY_STATUS); 858 QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy); 859 CloseServiceHandle(service); 860 CloseServiceHandle(scm); 861 862 /* service should exist */ 863 name = SysAllocString(spooler); 864 V_VT(&v) = VT_I2; 865 hr = IShellDispatch2_IsServiceRunning(sd, name, &v); 866 EXPECT_HR(hr, S_OK); 867 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v)); 868 if (status.dwCurrentState == SERVICE_RUNNING) 869 ok(V_BOOL(&v) == VARIANT_TRUE, "got %d\n", V_BOOL(&v)); 870 else 871 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v)); 872 SysFreeString(name); 873 874 /* service doesn't exist */ 875 name = SysAllocString(dummyW); 876 V_VT(&v) = VT_I2; 877 hr = IShellDispatch2_IsServiceRunning(sd, name, &v); 878 EXPECT_HR(hr, S_OK); 879 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v)); 880 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v)); 881 SysFreeString(name); 882 883 IShellDispatch2_Release(sd); 884 } 885 886 static void test_dispatch_typeinfo(IDispatch *disp, REFIID *riid) 887 { 888 ITypeInfo *typeinfo; 889 TYPEATTR *typeattr; 890 UINT count; 891 HRESULT hr; 892 893 count = 10; 894 hr = IDispatch_GetTypeInfoCount(disp, &count); 895 ok(hr == S_OK, "got 0x%08x\n", hr); 896 ok(count == 1, "got %u\n", count); 897 898 hr = IDispatch_GetTypeInfo(disp, 0, LOCALE_SYSTEM_DEFAULT, &typeinfo); 899 ok(hr == S_OK, "got 0x%08x\n", hr); 900 901 hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr); 902 ok(hr == S_OK, "got 0x%08x\n", hr); 903 while (!IsEqualGUID(*riid, &IID_NULL)) { 904 if (IsEqualGUID(&typeattr->guid, *riid)) 905 break; 906 riid++; 907 } 908 ok(IsEqualGUID(&typeattr->guid, *riid), "unexpected type guid %s\n", wine_dbgstr_guid(&typeattr->guid)); 909 910 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr); 911 ITypeInfo_Release(typeinfo); 912 } 913 914 static void test_ShellFolderViewDual(void) 915 { 916 static const IID *shelldisp_riids[] = { 917 &IID_IShellDispatch6, 918 &IID_IShellDispatch5, 919 &IID_IShellDispatch4, 920 &IID_IShellDispatch2, 921 &IID_IWin7ShellDispatch6, 922 &IID_NULL 923 }; 924 IShellFolderViewDual *viewdual; 925 IShellFolder *desktop, *tmpdir; 926 IShellView *view, *view2; 927 IDispatch *disp, *disp2; 928 WCHAR pathW[MAX_PATH]; 929 LPITEMIDLIST pidl; 930 HRESULT hr; 931 932 /* IShellFolderViewDual is not an IShellView extension */ 933 hr = SHGetDesktopFolder(&desktop); 934 ok(hr == S_OK, "got 0x%08x\n", hr); 935 936 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view); 937 ok(hr == S_OK, "got 0x%08x\n", hr); 938 939 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual); 940 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 941 942 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp); 943 ok(hr == S_OK, "got 0x%08x\n", hr); 944 945 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp2); 946 ok(hr == S_OK, "got 0x%08x\n", hr); 947 ok(disp2 == disp, "got %p, %p\n", disp2, disp); 948 IDispatch_Release(disp2); 949 950 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&viewdual); 951 ok(hr == S_OK, "got 0x%08x\n", hr); 952 ok(disp == (IDispatch*)viewdual, "got %p, expected %p\n", viewdual, disp); 953 954 hr = IShellFolderViewDual_QueryInterface(viewdual, &IID_IShellView, (void**)&view2); 955 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 956 957 /* get_Application() */ 958 959 if (0) /* crashes on pre-vista */ { 960 hr = IShellFolderViewDual_get_Application(viewdual, NULL); 961 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 962 } 963 hr = IShellFolderViewDual_get_Application(viewdual, &disp2); 964 ok(hr == S_OK, "got 0x%08x\n", hr); 965 ok(disp2 != (IDispatch*)viewdual, "got %p, %p\n", disp2, viewdual); 966 test_dispatch_typeinfo(disp2, shelldisp_riids); 967 IDispatch_Release(disp2); 968 969 IShellFolderViewDual_Release(viewdual); 970 IDispatch_Release(disp); 971 972 disp = (void*)0xdeadbeef; 973 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IShellFolderViewDual, (void**)&disp); 974 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* win2k */, "got 0x%08x\n", hr); 975 ok(disp == NULL, "got %p\n", disp); 976 IShellView_Release(view); 977 978 /* Try with some other folder, that's not a desktop */ 979 GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW); 980 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, pathW, NULL, &pidl, NULL); 981 ok(hr == S_OK, "got 0x%08x\n", hr); 982 983 hr = IShellFolder_BindToObject(desktop, pidl, NULL, &IID_IShellFolder, (void**)&tmpdir); 984 ok(hr == S_OK, "got 0x%08x\n", hr); 985 CoTaskMemFree(pidl); 986 987 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view); 988 ok(hr == S_OK, "got 0x%08x\n", hr); 989 990 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual); 991 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 992 993 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp); 994 ok(hr == S_OK, "got 0x%08x\n", hr); 995 IDispatch_Release(disp); 996 IShellView_Release(view); 997 998 IShellFolder_Release(tmpdir); 999 IShellFolder_Release(desktop); 1000 } 1001 1002 static void test_ShellWindows(void) 1003 { 1004 IShellWindows *shellwindows; 1005 LONG cookie, cookie2, ret; 1006 IDispatch *disp; 1007 VARIANT v, v2; 1008 HRESULT hr; 1009 HWND hwnd; 1010 1011 hr = CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, 1012 &IID_IShellWindows, (void**)&shellwindows); 1013 ok(hr == S_OK, "got 0x%08x\n", hr); 1014 /* TODO: remove when explorer startup with clean prefix is fixed */ 1015 if (hr != S_OK) 1016 return; 1017 1018 if (0) /* NULL out argument - currently crashes on Wine */ { 1019 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, NULL); 1020 ok(hr == HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), "got 0x%08x\n", hr); 1021 } 1022 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, &cookie); 1023 todo_wine 1024 ok(hr == E_POINTER, "got 0x%08x\n", hr); 1025 1026 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie); 1027 todo_wine 1028 ok(hr == E_POINTER, "got 0x%08x\n", hr); 1029 1030 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie); 1031 todo_wine 1032 ok(hr == E_POINTER, "got 0x%08x\n", hr); 1033 1034 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP, 1035 0, 0, 50, 14, 0, 0, 0, NULL); 1036 ok(hwnd != NULL, "got %p, error %d\n", hwnd, GetLastError()); 1037 1038 cookie = 0; 1039 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie); 1040 todo_wine { 1041 ok(hr == S_OK, "got 0x%08x\n", hr); 1042 ok(cookie != 0, "got %d\n", cookie); 1043 } 1044 cookie2 = 0; 1045 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie2); 1046 todo_wine { 1047 ok(hr == S_OK, "got 0x%08x\n", hr); 1048 ok(cookie2 != 0 && cookie2 != cookie, "got %d\n", cookie2); 1049 } 1050 hr = IShellWindows_Revoke(shellwindows, cookie); 1051 todo_wine 1052 ok(hr == S_OK, "got 0x%08x\n", hr); 1053 hr = IShellWindows_Revoke(shellwindows, cookie2); 1054 todo_wine 1055 ok(hr == S_OK, "got 0x%08x\n", hr); 1056 1057 hr = IShellWindows_Revoke(shellwindows, 0); 1058 todo_wine 1059 ok(hr == S_FALSE, "got 0x%08x\n", hr); 1060 1061 /* we can register ourselves as desktop, but FindWindowSW still returns real desktop window */ 1062 cookie = 0; 1063 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_DESKTOP, &cookie); 1064 todo_wine { 1065 ok(hr == S_OK, "got 0x%08x\n", hr); 1066 ok(cookie != 0, "got %d\n", cookie); 1067 } 1068 disp = (void*)0xdeadbeef; 1069 ret = 0xdead; 1070 VariantInit(&v); 1071 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, SWFO_NEEDDISPATCH, &disp); 1072 ok(hr == S_OK || broken(hr == S_FALSE), "got 0x%08x\n", hr); 1073 if (hr == S_FALSE) /* winxp and earlier */ { 1074 win_skip("SWC_DESKTOP is not supported, some tests will be skipped.\n"); 1075 /* older versions allowed to register SWC_DESKTOP and access it with FindWindowSW */ 1076 ok(disp == NULL, "got %p\n", disp); 1077 ok(ret == 0, "got %d\n", ret); 1078 } 1079 else { 1080 static const IID *browser_riids[] = { 1081 &IID_IWebBrowser2, 1082 &IID_NULL 1083 }; 1084 1085 static const IID *viewdual_riids[] = { 1086 &IID_IShellFolderViewDual3, 1087 &IID_NULL 1088 }; 1089 1090 IShellFolderViewDual *view; 1091 IShellBrowser *sb, *sb2; 1092 IServiceProvider *sp; 1093 IDispatch *doc, *app; 1094 IWebBrowser2 *wb; 1095 IShellView *sv; 1096 IUnknown *unk; 1097 1098 ok(disp != NULL, "got %p\n", disp); 1099 1100 if (disp == NULL) goto skip_disp_tests; 1101 1102 ok(ret != HandleToUlong(hwnd), "got %d\n", ret); 1103 1104 /* IDispatch-related tests */ 1105 test_dispatch_typeinfo(disp, browser_riids); 1106 1107 /* IWebBrowser2 */ 1108 hr = IDispatch_QueryInterface(disp, &IID_IWebBrowser2, (void**)&wb); 1109 ok(hr == S_OK, "got 0x%08x\n", hr); 1110 1111 hr = IWebBrowser2_Refresh(wb); 1112 todo_wine 1113 ok(hr == S_OK, "got 0x%08x\n", hr); 1114 1115 hr = IWebBrowser2_get_Application(wb, &app); 1116 ok(hr == S_OK, "got 0x%08x\n", hr); 1117 ok(disp == app, "got %p, %p\n", app, disp); 1118 IDispatch_Release(app); 1119 1120 hr = IWebBrowser2_get_Document(wb, &doc); 1121 todo_wine 1122 ok(hr == S_OK, "got 0x%08x\n", hr); 1123 if (hr == S_OK) { 1124 test_dispatch_typeinfo(doc, viewdual_riids); 1125 } 1126 IWebBrowser2_Release(wb); 1127 1128 /* IServiceProvider */ 1129 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&view); 1130 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1131 1132 hr = IDispatch_QueryInterface(disp, &IID_IServiceProvider, (void**)&sp); 1133 ok(hr == S_OK, "got 0x%08x\n", hr); 1134 1135 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb); 1136 ok(hr == S_OK, "got 0x%08x\n", hr); 1137 1138 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb2); 1139 ok(hr == S_OK, "got 0x%08x\n", hr); 1140 ok(sb == sb2, "got %p, %p\n", sb, sb2); 1141 1142 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IOleWindow, (void**)&unk); 1143 ok(hr == S_OK, "got 0x%08x\n", hr); 1144 IUnknown_Release(unk); 1145 1146 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IExplorerBrowser, (void**)&unk); 1147 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1148 1149 hr = IShellBrowser_QueryInterface(sb, &IID_IExplorerBrowser, (void**)&unk); 1150 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1151 1152 hr = IShellBrowser_QueryInterface(sb, &IID_IWebBrowser2, (void**)&unk); 1153 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1154 1155 hr = IShellBrowser_QueryInterface(sb, &IID_IDispatch, (void**)&unk); 1156 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1157 1158 hr = IShellBrowser_QueryActiveShellView(sb, &sv); 1159 ok(hr == S_OK, "got 0x%08x\n", hr); 1160 IShellView_Release(sv); 1161 1162 IShellBrowser_Release(sb2); 1163 IShellBrowser_Release(sb); 1164 1165 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IUnknown, (void**)&unk); 1166 ok(hr == S_OK, "got 0x%08x\n", hr); 1167 1168 hr = IUnknown_QueryInterface(unk, &IID_IShellBrowser, (void**)&sb2); 1169 ok(hr == S_OK, "got 0x%08x\n", hr); 1170 IShellBrowser_Release(sb2); 1171 IUnknown_Release(unk); 1172 1173 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellView, (void**)&sv); 1174 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1175 1176 IServiceProvider_Release(sp); 1177 IDispatch_Release(disp); 1178 } 1179 skip_disp_tests: 1180 1181 disp = (void*)0xdeadbeef; 1182 ret = 0xdead; 1183 VariantInit(&v); 1184 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, 0, &disp); 1185 ok(hr == S_OK || broken(hr == S_FALSE) /* winxp */, "got 0x%08x\n", hr); 1186 ok(disp == NULL, "got %p\n", disp); 1187 ok(ret != HandleToUlong(hwnd), "got %d\n", ret); 1188 1189 disp = (void*)0xdeadbeef; 1190 ret = 0xdead; 1191 V_VT(&v) = VT_I4; 1192 V_I4(&v) = cookie; 1193 VariantInit(&v2); 1194 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_BROWSER, &ret, SWFO_COOKIEPASSED, &disp); 1195 todo_wine 1196 ok(hr == S_FALSE, "got 0x%08x\n", hr); 1197 ok(disp == NULL, "got %p\n", disp); 1198 ok(ret == 0, "got %d\n", ret); 1199 1200 hr = IShellWindows_Revoke(shellwindows, cookie); 1201 todo_wine 1202 ok(hr == S_OK, "got 0x%08x\n", hr); 1203 DestroyWindow(hwnd); 1204 IShellWindows_Release(shellwindows); 1205 } 1206 1207 static void test_ParseName(void) 1208 { 1209 static const WCHAR cadabraW[] = {'c','a','d','a','b','r','a',0}; 1210 WCHAR pathW[MAX_PATH]; 1211 IShellDispatch *sd; 1212 FolderItem *item; 1213 Folder *folder; 1214 HRESULT hr; 1215 VARIANT v; 1216 BSTR str; 1217 1218 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 1219 &IID_IShellDispatch, (void**)&sd); 1220 ok(hr == S_OK, "got 0x%08x\n", hr); 1221 1222 GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW); 1223 V_VT(&v) = VT_BSTR; 1224 V_BSTR(&v) = SysAllocString(pathW); 1225 hr = IShellDispatch_NameSpace(sd, v, &folder); 1226 ok(hr == S_OK, "got 0x%08x\n", hr); 1227 VariantClear(&v); 1228 1229 item = (void*)0xdeadbeef; 1230 hr = Folder_ParseName(folder, NULL, &item); 1231 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr); 1232 ok(item == NULL, "got %p\n", item); 1233 1234 /* empty name */ 1235 str = SysAllocStringLen(NULL, 0); 1236 item = (void*)0xdeadbeef; 1237 hr = Folder_ParseName(folder, str, &item); 1238 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr); 1239 ok(item == NULL, "got %p\n", item); 1240 SysFreeString(str); 1241 1242 /* path doesn't exist */ 1243 str = SysAllocString(cadabraW); 1244 item = (void*)0xdeadbeef; 1245 hr = Folder_ParseName(folder, str, &item); 1246 ok(hr == S_FALSE || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* win2k */, 1247 "got 0x%08x\n", hr); 1248 ok(item == NULL, "got %p\n", item); 1249 SysFreeString(str); 1250 1251 lstrcatW(pathW, cadabraW); 1252 CreateDirectoryW(pathW, NULL); 1253 1254 str = SysAllocString(cadabraW); 1255 item = NULL; 1256 hr = Folder_ParseName(folder, str, &item); 1257 ok(hr == S_OK, "got 0x%08x\n", hr); 1258 ok(item != NULL, "got %p\n", item); 1259 SysFreeString(str); 1260 1261 hr = FolderItem_get_Path(item, &str); 1262 ok(hr == S_OK, "got 0x%08x\n", hr); 1263 ok(str[0] != 0, "path %s\n", wine_dbgstr_w(str)); 1264 SysFreeString(str); 1265 1266 RemoveDirectoryW(pathW); 1267 FolderItem_Release(item); 1268 Folder_Release(folder); 1269 IShellDispatch_Release(sd); 1270 } 1271 1272 static void test_Verbs(void) 1273 { 1274 FolderItemVerbs *verbs, *verbs2; 1275 WCHAR pathW[MAX_PATH]; 1276 FolderItemVerb *verb; 1277 IShellDispatch *sd; 1278 FolderItem *item; 1279 Folder2 *folder2; 1280 IDispatch *disp; 1281 Folder *folder; 1282 HRESULT hr; 1283 LONG count, i; 1284 VARIANT v; 1285 BSTR str; 1286 1287 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 1288 &IID_IShellDispatch, (void**)&sd); 1289 ok(hr == S_OK, "got 0x%08x\n", hr); 1290 1291 GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW); 1292 V_VT(&v) = VT_BSTR; 1293 V_BSTR(&v) = SysAllocString(pathW); 1294 hr = IShellDispatch_NameSpace(sd, v, &folder); 1295 ok(hr == S_OK, "got 0x%08x\n", hr); 1296 VariantClear(&v); 1297 1298 hr = Folder_QueryInterface(folder, &IID_Folder2, (void**)&folder2); 1299 ok(hr == S_OK, "got 0x%08x\n", hr); 1300 Folder_Release(folder); 1301 1302 hr = Folder2_get_Self(folder2, &item); 1303 ok(hr == S_OK, "got 0x%08x\n", hr); 1304 Folder2_Release(folder2); 1305 1306 if (0) { /* crashes on some systems */ 1307 hr = FolderItem_Verbs(item, NULL); 1308 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 1309 } 1310 hr = FolderItem_Verbs(item, &verbs); 1311 ok(hr == S_OK, "got 0x%08x\n", hr); 1312 1313 hr = FolderItem_Verbs(item, &verbs2); 1314 ok(hr == S_OK, "got 0x%08x\n", hr); 1315 ok(verbs2 != verbs, "Unexpected verbs pointer.\n"); 1316 FolderItemVerbs_Release(verbs2); 1317 1318 disp = (void *)0xdeadbeef; 1319 hr = FolderItemVerbs_get_Application(verbs, &disp); 1320 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); 1321 ok(disp == NULL, "Unexpected application pointer.\n"); 1322 1323 disp = (void *)0xdeadbeef; 1324 hr = FolderItemVerbs_get_Parent(verbs, &disp); 1325 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); 1326 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp); 1327 1328 if (0) { /* crashes on winxp/win2k3 */ 1329 hr = FolderItemVerbs_get_Count(verbs, NULL); 1330 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 1331 } 1332 count = 0; 1333 hr = FolderItemVerbs_get_Count(verbs, &count); 1334 ok(hr == S_OK, "got 0x%08x\n", hr); 1335 ok(count > 0, "got count %d\n", count); 1336 1337 if (0) { /* crashes on winxp/win2k3 */ 1338 V_VT(&v) = VT_I4; 1339 V_I4(&v) = 0; 1340 hr = FolderItemVerbs_Item(verbs, v, NULL); 1341 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 1342 } 1343 /* there's always one item more, so you can access [0,count], 1344 instead of actual [0,count) */ 1345 for (i = 0; i <= count; i++) { 1346 V_VT(&v) = VT_I4; 1347 V_I4(&v) = i; 1348 hr = FolderItemVerbs_Item(verbs, v, &verb); 1349 ok(hr == S_OK, "got 0x%08x\n", hr); 1350 hr = FolderItemVerb_get_Name(verb, &str); 1351 ok(hr == S_OK, "got 0x%08x\n", hr); 1352 ok(str != NULL, "%d: name %s\n", i, wine_dbgstr_w(str)); 1353 if (i == count) 1354 ok(str[0] == 0, "%d: got terminating item %s\n", i, wine_dbgstr_w(str)); 1355 1356 disp = (void *)0xdeadbeef; 1357 hr = FolderItemVerb_get_Parent(verb, &disp); 1358 ok(hr == E_NOTIMPL, "got %#x.\n", hr); 1359 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp); 1360 1361 disp = (void *)0xdeadbeef; 1362 hr = FolderItemVerb_get_Application(verb, &disp); 1363 ok(hr == E_NOTIMPL, "got %#x.\n", hr); 1364 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp); 1365 1366 SysFreeString(str); 1367 FolderItemVerb_Release(verb); 1368 } 1369 1370 V_VT(&v) = VT_I4; 1371 V_I4(&v) = count+1; 1372 verb = NULL; 1373 hr = FolderItemVerbs_Item(verbs, v, &verb); 1374 ok(hr == S_OK, "got 0x%08x\n", hr); 1375 ok(verb == NULL, "got %p\n", verb); 1376 1377 FolderItemVerbs_Release(verbs); 1378 FolderItem_Release(item); 1379 IShellDispatch_Release(sd); 1380 } 1381 1382 static void test_ShellExecute(void) 1383 { 1384 HRESULT hr; 1385 IShellDispatch2 *sd; 1386 BSTR name; 1387 VARIANT args, dir, op, show; 1388 1389 static const WCHAR regW[] = {'r','e','g',0}; 1390 1391 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 1392 &IID_IShellDispatch2, (void**)&sd); 1393 if (hr != S_OK) 1394 { 1395 win_skip("IShellDispatch2 not supported\n"); 1396 return; 1397 } 1398 1399 VariantInit(&args); 1400 VariantInit(&dir); 1401 VariantInit(&op); 1402 VariantInit(&show); 1403 1404 V_VT(&show) = VT_I4; 1405 V_I4(&show) = 0; 1406 1407 name = SysAllocString(regW); 1408 1409 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show); 1410 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr); 1411 1412 /* test invalid value for show */ 1413 V_VT(&show) = VT_BSTR; 1414 V_BSTR(&show) = name; 1415 1416 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show); 1417 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr); 1418 1419 SysFreeString(name); 1420 IShellDispatch2_Release(sd); 1421 } 1422 1423 START_TEST(shelldispatch) 1424 { 1425 HRESULT r; 1426 1427 r = CoInitialize(NULL); 1428 ok(SUCCEEDED(r), "CoInitialize failed: %08x\n", r); 1429 if (FAILED(r)) 1430 return; 1431 1432 init_function_pointers(); 1433 test_namespace(); 1434 test_items(); 1435 test_service(); 1436 test_ShellFolderViewDual(); 1437 test_ShellWindows(); 1438 test_ParseName(); 1439 test_Verbs(); 1440 test_ShellExecute(); 1441 1442 CoUninitialize(); 1443 } 1444