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 < ARRAY_SIZE(special_folders); 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, var2, 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 < ARRAY_SIZE(file_defs); 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 == ARRAY_SIZE(file_defs), "got %d files\n", count); 545 546 /* VT_EMPTY */ 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 /* VT_I2 */ 554 V_VT(&var) = VT_I2; 555 V_I2(&var) = 0; 556 557 EXPECT_REF(folder, 2); 558 EXPECT_REF(items, 2); 559 item = NULL; 560 r = FolderItems_Item(items, var, &item); 561 ok(r == S_OK, "FolderItems::Item failed: %08x\n", r); 562 ok(!!item, "item is null\n"); 563 EXPECT_REF(folder, 3); 564 EXPECT_REF(items, 2); 565 566 r = Folder_get_Application(folder, &disp); 567 ok(r == S_OK, "Failed to get application pointer %#x.\n", r); 568 r = FolderItem_get_Application(item, &disp2); 569 ok(r == S_OK, "Failed to get application pointer %#x.\n", r); 570 ok(disp == disp2, "Unexpected application pointer.\n"); 571 IDispatch_Release(disp2); 572 IDispatch_Release(disp); 573 574 FolderItem_Release(item); 575 576 /* VT_VARIANT | VT_BYREF */ 577 V_VT(&var2) = VT_I2; 578 V_I2(&var2) = 0; 579 580 V_VT(&var) = VT_BYREF | VT_VARIANT; 581 V_VARIANTREF(&var) = &var2; 582 583 item = NULL; 584 r = FolderItems_Item(items, var, &item); 585 ok(r == S_OK, "FolderItems::Item failed: %08x\n", r); 586 ok(!!item, "item is null\n"); 587 FolderItem_Release(item); 588 589 /* VT_I4 */ 590 V_VT(&var) = VT_I4; 591 V_I4(&var) = 0; 592 item = NULL; 593 r = FolderItems_Item(items, var, &item); 594 ok(r == S_OK, "FolderItems::Item failed: %08x\n", r); 595 ok(!!item, "item is null\n"); 596 if (item) FolderItem_Release(item); 597 598 V_I4(&var) = -1; 599 item = (FolderItem*)0xdeadbeef; 600 r = FolderItems_Item(items, var, &item); 601 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 602 ok(!item, "item is not null\n"); 603 604 V_VT(&var) = VT_ERROR; 605 V_ERROR(&var) = 0; 606 item = NULL; 607 r = FolderItems_Item(items, var, &item); 608 ok(r == S_OK, "expected S_OK, got %08x\n", r); 609 ok(!!item, "item is null\n"); 610 if (item) 611 { 612 bstr = NULL; 613 r = FolderItem_get_Path(item, &bstr); 614 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r); 615 ok(!lstrcmpW(bstr, cur_dir), 616 "expected %s, got %s\n", wine_dbgstr_w(cur_dir), wine_dbgstr_w(bstr)); 617 SysFreeString(bstr); 618 FolderItem_Release(item); 619 } 620 621 V_VT(&int_index) = VT_I4; 622 623 /* test the folder item corresponding to each file */ 624 for (i = 0; i < ARRAY_SIZE(file_defs); i++) 625 { 626 VARIANT_BOOL b; 627 BSTR name; 628 629 V_I4(&int_index) = i; 630 variant_set_string(&str_index, file_defs[i].name); 631 632 item = NULL; 633 r = FolderItems_Item(items, int_index, &item); 634 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); 635 ok(!!item, "file_defs[%d]: item is null\n", i); 636 637 item2 = NULL; 638 r = FolderItems_Item(items, int_index, &item2); 639 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); 640 ok(item2 != item, "file_defs[%d]: item and item2 are the same\n", i); 641 FolderItem_Release(item2); 642 643 bstr = NULL; 644 r = FolderItem_get_Path(item, &bstr); 645 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r); 646 PathCombineW(path, cur_dir, V_BSTR(&str_index)); 647 ok(!lstrcmpW(bstr, path), 648 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr)); 649 SysFreeString(bstr); 650 651 bstr = a2bstr(file_defs[i].name); 652 r = FolderItem_get_Name(item, &name); 653 ok(r == S_OK, "Failed to get item name, hr %#x.\n", r); 654 /* Returned display name does not have to strictly match file name, e.g. extension could be omitted. */ 655 ok(lstrlenW(name) <= lstrlenW(bstr), "file_defs[%d]: unexpected name length.\n", i); 656 ok(!memcmp(bstr, name, lstrlenW(name) * sizeof(WCHAR)), "file_defs[%d]: unexpected name %s.\n", i, wine_dbgstr_w(name)); 657 SysFreeString(name); 658 SysFreeString(bstr); 659 660 FolderItem_Release(item); 661 662 item = NULL; 663 r = FolderItems_Item(items, str_index, &item); 664 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); 665 ok(!!item, "file_defs[%d]: item is null\n", i); 666 667 bstr = NULL; 668 r = FolderItem_get_Path(item, &bstr); 669 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r); 670 PathCombineW(path, cur_dir, V_BSTR(&str_index)); 671 ok(!lstrcmpW(bstr, path), 672 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr)); 673 SysFreeString(bstr); 674 675 b = 0xdead; 676 r = FolderItem_get_IsFolder(item, &b); 677 ok(r == S_OK, "Failed to get IsFolder property, %#x.\n", r); 678 ok(file_defs[i].type == DIRECTORY ? b == VARIANT_TRUE : b == VARIANT_FALSE, "Unexpected prop value %#x.\n", b); 679 680 FolderItem_Release(item); 681 682 if (file_defs[i].type == DIRECTORY) 683 { 684 /* test that getting an item object for a file in a subdirectory succeeds */ 685 PathCombineA(cstr, file_defs[i].name, "foo.txt"); 686 variant_set_string(&str_index2, cstr); 687 item2 = NULL; 688 r = FolderItems_Item(items, str_index2, &item2); 689 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); 690 ok(!!item2, "file_defs[%d]: item is null\n", i); 691 if (item2) FolderItem_Release(item2); 692 VariantClear(&str_index2); 693 694 /* delete the file in the subdirectory */ 695 ret = DeleteFileA(cstr); 696 ok(ret, "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError()); 697 698 /* test that getting an item object via a relative path fails */ 699 strcpy(cstr, file_defs[i].name); 700 strcat(cstr, "\\..\\"); 701 strcat(cstr, file_defs[i].name); 702 variant_set_string(&str_index2, cstr); 703 item2 = (FolderItem*)0xdeadbeef; 704 r = FolderItems_Item(items, str_index2, &item2); 705 todo_wine { 706 ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08x\n", i, r); 707 ok(!item2, "file_defs[%d]: item is not null\n", i); 708 } 709 if (item2) FolderItem_Release(item2); 710 VariantClear(&str_index2); 711 712 /* remove the directory */ 713 ret = RemoveDirectoryA(file_defs[i].name); 714 ok(ret, "file_defs[%d]: RemoveDirectory failed: %08x\n", i, GetLastError()); 715 } 716 else 717 { 718 ret = DeleteFileA(file_defs[i].name); 719 ok(ret, "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError()); 720 } 721 722 /* test that the folder item is still accessible by integer index */ 723 item = NULL; 724 r = FolderItems_Item(items, int_index, &item); 725 ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r); 726 ok(!!item, "file_defs[%d]: item is null\n", i); 727 728 bstr = NULL; 729 r = FolderItem_get_Path(item, &bstr); 730 ok(r == S_OK, "file_defs[%d]: FolderItem::get_Path failed: %08x\n", i, r); 731 PathCombineW(path, cur_dir, V_BSTR(&str_index)); 732 ok(!lstrcmpW(bstr, path), 733 "file_defs[%d]: expected %s, got %s\n", i, wine_dbgstr_w(path), wine_dbgstr_w(bstr)); 734 SysFreeString(bstr); 735 736 FolderItem_Release(item); 737 738 /* test that the folder item is no longer accessible by string index */ 739 item = (FolderItem*)0xdeadbeef; 740 r = FolderItems_Item(items, str_index, &item); 741 ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08x\n", i, r); 742 ok(!item, "file_defs[%d]: item is not null\n", i); 743 744 VariantClear(&str_index); 745 } 746 747 /* test that there are only as many folder items as there were files */ 748 V_I4(&int_index) = ARRAY_SIZE(file_defs); 749 item = (FolderItem*)0xdeadbeef; 750 r = FolderItems_Item(items, int_index, &item); 751 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 752 ok(!item, "item is not null\n"); 753 754 if (0) /* crashes on xp */ 755 { 756 r = FolderItems_get_Application(items, NULL); 757 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r); 758 } 759 760 r = FolderItems_get_Application(items, &disp); 761 ok(r == S_OK, "FolderItems::get_Application failed: %08x\n", r); 762 763 r = Folder_get_Application(folder, &disp2); 764 ok(r == S_OK, "Failed to get application pointer, hr %#x.\n", r); 765 ok(disp == disp2, "Unexpected application pointer.\n"); 766 IDispatch_Release(disp2); 767 IDispatch_Release(disp); 768 769 if (0) /* crashes on xp */ 770 { 771 r = FolderItems_get_Parent(items, NULL); 772 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r); 773 } 774 775 disp = (IDispatch*)0xdeadbeef; 776 r = FolderItems_get_Parent(items, &disp); 777 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r); 778 ok(!disp, "disp is not null\n"); 779 780 if (0) /* crashes on xp */ 781 { 782 r = FolderItems__NewEnum(items, NULL); 783 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r); 784 } 785 786 r = FolderItems__NewEnum(items, &unk); 787 todo_wine 788 ok(r == S_OK, "FolderItems::_NewEnum failed: %08x\n", r); 789 todo_wine 790 ok(!!unk, "unk is null\n"); 791 if (unk) IUnknown_Release(unk); 792 793 if (items3) 794 { 795 r = FolderItems3_Filter(items3, 0, NULL); 796 todo_wine 797 ok(r == S_OK, "expected S_OK, got %08x\n", r); 798 799 if (0) /* crashes on xp */ 800 { 801 r = FolderItems3_get_Verbs(items3, NULL); 802 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r); 803 } 804 805 r = FolderItems3_get_Verbs(items3, &verbs); 806 todo_wine 807 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 808 ok(!verbs, "verbs is not null\n"); 809 } 810 811 /* remove the temporary directory and restore the original working directory */ 812 GetTempPathW(MAX_PATH, path); 813 SetCurrentDirectoryW(path); 814 ret = RemoveDirectoryW(winetestW); 815 ok(ret, "RemoveDirectory failed: %08x\n", GetLastError()); 816 SetCurrentDirectoryW(orig_dir); 817 818 /* test that everything stops working after the directory has been removed */ 819 count = -1; 820 r = FolderItems_get_Count(items, &count); 821 ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r); 822 ok(!count, "expected 0 files, got %d\n", count); 823 824 item = NULL; 825 V_I4(&int_index) = 0; 826 item = (FolderItem*)0xdeadbeef; 827 r = FolderItems_Item(items, int_index, &item); 828 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 829 ok(!item, "item is not null\n"); 830 831 variant_set_string(&str_index, file_defs[0].name); 832 item = (FolderItem*)0xdeadbeef; 833 r = FolderItems_Item(items, str_index, &item); 834 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 835 ok(!item, "item is not null\n"); 836 VariantClear(&str_index); 837 838 FolderItems_Release(items); 839 Folder_Release(folder); 840 if (items3) FolderItems3_Release(items3); 841 IShellDispatch_Release(sd); 842 } 843 844 static void test_service(void) 845 { 846 static const WCHAR spooler[] = {'S','p','o','o','l','e','r',0}; 847 static const WCHAR dummyW[] = {'d','u','m','m','y',0}; 848 SERVICE_STATUS_PROCESS status; 849 SC_HANDLE scm, service; 850 IShellDispatch2 *sd; 851 DWORD dummy; 852 HRESULT hr; 853 BSTR name; 854 VARIANT v; 855 856 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 857 &IID_IShellDispatch2, (void**)&sd); 858 if (hr != S_OK) 859 { 860 win_skip("IShellDispatch2 not supported\n"); 861 return; 862 } 863 864 V_VT(&v) = VT_I2; 865 V_I2(&v) = 10; 866 hr = IShellDispatch2_IsServiceRunning(sd, NULL, &v); 867 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v)); 868 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v)); 869 EXPECT_HR(hr, S_OK); 870 871 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); 872 service = OpenServiceW(scm, spooler, SERVICE_QUERY_STATUS); 873 QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy); 874 CloseServiceHandle(service); 875 CloseServiceHandle(scm); 876 877 /* service should exist */ 878 name = SysAllocString(spooler); 879 V_VT(&v) = VT_I2; 880 hr = IShellDispatch2_IsServiceRunning(sd, name, &v); 881 EXPECT_HR(hr, S_OK); 882 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v)); 883 if (status.dwCurrentState == SERVICE_RUNNING) 884 ok(V_BOOL(&v) == VARIANT_TRUE, "got %d\n", V_BOOL(&v)); 885 else 886 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v)); 887 SysFreeString(name); 888 889 /* service doesn't exist */ 890 name = SysAllocString(dummyW); 891 V_VT(&v) = VT_I2; 892 hr = IShellDispatch2_IsServiceRunning(sd, name, &v); 893 EXPECT_HR(hr, S_OK); 894 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v)); 895 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v)); 896 SysFreeString(name); 897 898 IShellDispatch2_Release(sd); 899 } 900 901 static void test_dispatch_typeinfo(IDispatch *disp, REFIID *riid) 902 { 903 ITypeInfo *typeinfo; 904 TYPEATTR *typeattr; 905 UINT count; 906 HRESULT hr; 907 908 count = 10; 909 hr = IDispatch_GetTypeInfoCount(disp, &count); 910 ok(hr == S_OK, "got 0x%08x\n", hr); 911 ok(count == 1, "got %u\n", count); 912 913 hr = IDispatch_GetTypeInfo(disp, 0, LOCALE_SYSTEM_DEFAULT, &typeinfo); 914 ok(hr == S_OK, "got 0x%08x\n", hr); 915 916 hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr); 917 ok(hr == S_OK, "got 0x%08x\n", hr); 918 while (!IsEqualGUID(*riid, &IID_NULL)) { 919 if (IsEqualGUID(&typeattr->guid, *riid)) 920 break; 921 riid++; 922 } 923 ok(IsEqualGUID(&typeattr->guid, *riid), "unexpected type guid %s\n", wine_dbgstr_guid(&typeattr->guid)); 924 925 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr); 926 ITypeInfo_Release(typeinfo); 927 } 928 929 static void test_ShellFolderViewDual(void) 930 { 931 static const IID *shelldisp_riids[] = { 932 &IID_IShellDispatch6, 933 &IID_IShellDispatch5, 934 &IID_IShellDispatch4, 935 &IID_IShellDispatch2, 936 &IID_IWin7ShellDispatch6, 937 &IID_NULL 938 }; 939 IShellFolderViewDual *viewdual; 940 IShellFolder *desktop, *tmpdir; 941 IShellView *view, *view2; 942 IDispatch *disp, *disp2; 943 WCHAR pathW[MAX_PATH]; 944 LPITEMIDLIST pidl; 945 HRESULT hr; 946 947 /* IShellFolderViewDual is not an IShellView extension */ 948 hr = SHGetDesktopFolder(&desktop); 949 ok(hr == S_OK, "got 0x%08x\n", hr); 950 951 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view); 952 ok(hr == S_OK, "got 0x%08x\n", hr); 953 954 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual); 955 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 956 957 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp); 958 ok(hr == S_OK, "got 0x%08x\n", hr); 959 960 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp2); 961 ok(hr == S_OK, "got 0x%08x\n", hr); 962 ok(disp2 == disp, "got %p, %p\n", disp2, disp); 963 IDispatch_Release(disp2); 964 965 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&viewdual); 966 ok(hr == S_OK, "got 0x%08x\n", hr); 967 ok(disp == (IDispatch*)viewdual, "got %p, expected %p\n", viewdual, disp); 968 969 hr = IShellFolderViewDual_QueryInterface(viewdual, &IID_IShellView, (void**)&view2); 970 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 971 972 /* get_Application() */ 973 974 if (0) /* crashes on pre-vista */ { 975 hr = IShellFolderViewDual_get_Application(viewdual, NULL); 976 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 977 } 978 hr = IShellFolderViewDual_get_Application(viewdual, &disp2); 979 ok(hr == S_OK, "got 0x%08x\n", hr); 980 ok(disp2 != (IDispatch*)viewdual, "got %p, %p\n", disp2, viewdual); 981 test_dispatch_typeinfo(disp2, shelldisp_riids); 982 IDispatch_Release(disp2); 983 984 IShellFolderViewDual_Release(viewdual); 985 IDispatch_Release(disp); 986 987 disp = (void*)0xdeadbeef; 988 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IShellFolderViewDual, (void**)&disp); 989 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* win2k */, "got 0x%08x\n", hr); 990 ok(disp == NULL, "got %p\n", disp); 991 IShellView_Release(view); 992 993 /* Try with some other folder, that's not a desktop */ 994 GetTempPathW(ARRAY_SIZE(pathW), pathW); 995 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, pathW, NULL, &pidl, NULL); 996 ok(hr == S_OK, "got 0x%08x\n", hr); 997 998 hr = IShellFolder_BindToObject(desktop, pidl, NULL, &IID_IShellFolder, (void**)&tmpdir); 999 ok(hr == S_OK, "got 0x%08x\n", hr); 1000 CoTaskMemFree(pidl); 1001 1002 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view); 1003 ok(hr == S_OK, "got 0x%08x\n", hr); 1004 1005 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual); 1006 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1007 1008 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp); 1009 ok(hr == S_OK, "got 0x%08x\n", hr); 1010 IDispatch_Release(disp); 1011 IShellView_Release(view); 1012 1013 IShellFolder_Release(tmpdir); 1014 IShellFolder_Release(desktop); 1015 } 1016 1017 static void test_ShellWindows(void) 1018 { 1019 IShellWindows *shellwindows; 1020 LONG cookie, cookie2, ret; 1021 IDispatch *disp; 1022 VARIANT v, v2; 1023 HRESULT hr; 1024 HWND hwnd; 1025 1026 hr = CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, 1027 &IID_IShellWindows, (void**)&shellwindows); 1028 ok(hr == S_OK, "got 0x%08x\n", hr); 1029 /* TODO: remove when explorer startup with clean prefix is fixed */ 1030 if (hr != S_OK) 1031 return; 1032 1033 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, NULL); 1034 ok(hr == HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), "got 0x%08x\n", hr); 1035 1036 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, &cookie); 1037 todo_wine 1038 ok(hr == E_POINTER, "got 0x%08x\n", hr); 1039 1040 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie); 1041 todo_wine 1042 ok(hr == E_POINTER, "got 0x%08x\n", hr); 1043 1044 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie); 1045 todo_wine 1046 ok(hr == E_POINTER, "got 0x%08x\n", hr); 1047 1048 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP, 1049 0, 0, 50, 14, 0, 0, 0, NULL); 1050 ok(hwnd != NULL, "got %p, error %d\n", hwnd, GetLastError()); 1051 1052 cookie = 0; 1053 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie); 1054 todo_wine { 1055 ok(hr == S_OK, "got 0x%08x\n", hr); 1056 ok(cookie != 0, "got %d\n", cookie); 1057 } 1058 cookie2 = 0; 1059 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie2); 1060 todo_wine { 1061 ok(hr == S_OK, "got 0x%08x\n", hr); 1062 ok(cookie2 != 0 && cookie2 != cookie, "got %d\n", cookie2); 1063 } 1064 hr = IShellWindows_Revoke(shellwindows, cookie); 1065 todo_wine 1066 ok(hr == S_OK, "got 0x%08x\n", hr); 1067 hr = IShellWindows_Revoke(shellwindows, cookie2); 1068 todo_wine 1069 ok(hr == S_OK, "got 0x%08x\n", hr); 1070 1071 hr = IShellWindows_Revoke(shellwindows, 0); 1072 todo_wine 1073 ok(hr == S_FALSE, "got 0x%08x\n", hr); 1074 1075 /* we can register ourselves as desktop, but FindWindowSW still returns real desktop window */ 1076 cookie = 0; 1077 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_DESKTOP, &cookie); 1078 todo_wine { 1079 ok(hr == S_OK, "got 0x%08x\n", hr); 1080 ok(cookie != 0, "got %d\n", cookie); 1081 } 1082 disp = (void*)0xdeadbeef; 1083 ret = 0xdead; 1084 VariantInit(&v); 1085 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, SWFO_NEEDDISPATCH, &disp); 1086 ok(hr == S_OK || broken(hr == S_FALSE), "got 0x%08x\n", hr); 1087 if (hr == S_FALSE) /* winxp and earlier */ { 1088 win_skip("SWC_DESKTOP is not supported, some tests will be skipped.\n"); 1089 /* older versions allowed to register SWC_DESKTOP and access it with FindWindowSW */ 1090 ok(disp == NULL, "got %p\n", disp); 1091 ok(ret == 0, "got %d\n", ret); 1092 } 1093 else { 1094 static const IID *browser_riids[] = { 1095 &IID_IWebBrowser2, 1096 &IID_NULL 1097 }; 1098 1099 static const IID *viewdual_riids[] = { 1100 &IID_IShellFolderViewDual3, 1101 &IID_NULL 1102 }; 1103 1104 IShellFolderViewDual *view; 1105 IShellBrowser *sb, *sb2; 1106 IServiceProvider *sp; 1107 IDispatch *doc, *app; 1108 IWebBrowser2 *wb; 1109 IShellView *sv; 1110 IUnknown *unk; 1111 1112 ok(disp != NULL, "got %p\n", disp); 1113 ok(ret != HandleToUlong(hwnd), "got %d\n", ret); 1114 1115 /* IDispatch-related tests */ 1116 test_dispatch_typeinfo(disp, browser_riids); 1117 1118 /* IWebBrowser2 */ 1119 hr = IDispatch_QueryInterface(disp, &IID_IWebBrowser2, (void**)&wb); 1120 ok(hr == S_OK, "got 0x%08x\n", hr); 1121 1122 hr = IWebBrowser2_Refresh(wb); 1123 todo_wine 1124 ok(hr == S_OK, "got 0x%08x\n", hr); 1125 1126 hr = IWebBrowser2_get_Application(wb, &app); 1127 ok(hr == S_OK, "got 0x%08x\n", hr); 1128 ok(disp == app, "got %p, %p\n", app, disp); 1129 IDispatch_Release(app); 1130 1131 hr = IWebBrowser2_get_Document(wb, &doc); 1132 todo_wine 1133 ok(hr == S_OK, "got 0x%08x\n", hr); 1134 if (hr == S_OK) { 1135 test_dispatch_typeinfo(doc, viewdual_riids); 1136 } 1137 IWebBrowser2_Release(wb); 1138 1139 /* IServiceProvider */ 1140 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&view); 1141 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1142 1143 hr = IDispatch_QueryInterface(disp, &IID_IServiceProvider, (void**)&sp); 1144 ok(hr == S_OK, "got 0x%08x\n", hr); 1145 1146 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb); 1147 ok(hr == S_OK, "got 0x%08x\n", hr); 1148 1149 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb2); 1150 ok(hr == S_OK, "got 0x%08x\n", hr); 1151 ok(sb == sb2, "got %p, %p\n", sb, sb2); 1152 1153 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IOleWindow, (void**)&unk); 1154 ok(hr == S_OK, "got 0x%08x\n", hr); 1155 IUnknown_Release(unk); 1156 1157 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IExplorerBrowser, (void**)&unk); 1158 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1159 1160 hr = IShellBrowser_QueryInterface(sb, &IID_IExplorerBrowser, (void**)&unk); 1161 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1162 1163 hr = IShellBrowser_QueryInterface(sb, &IID_IWebBrowser2, (void**)&unk); 1164 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1165 1166 hr = IShellBrowser_QueryInterface(sb, &IID_IDispatch, (void**)&unk); 1167 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1168 1169 hr = IShellBrowser_QueryActiveShellView(sb, &sv); 1170 ok(hr == S_OK, "got 0x%08x\n", hr); 1171 IShellView_Release(sv); 1172 1173 IShellBrowser_Release(sb2); 1174 IShellBrowser_Release(sb); 1175 1176 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IUnknown, (void**)&unk); 1177 ok(hr == S_OK, "got 0x%08x\n", hr); 1178 1179 hr = IUnknown_QueryInterface(unk, &IID_IShellBrowser, (void**)&sb2); 1180 ok(hr == S_OK, "got 0x%08x\n", hr); 1181 IShellBrowser_Release(sb2); 1182 IUnknown_Release(unk); 1183 1184 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellView, (void**)&sv); 1185 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 1186 1187 IServiceProvider_Release(sp); 1188 IDispatch_Release(disp); 1189 } 1190 1191 disp = (void*)0xdeadbeef; 1192 ret = 0xdead; 1193 VariantInit(&v); 1194 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, 0, &disp); 1195 ok(hr == S_OK || broken(hr == S_FALSE) /* winxp */, "got 0x%08x\n", hr); 1196 ok(disp == NULL, "got %p\n", disp); 1197 ok(ret != HandleToUlong(hwnd), "got %d\n", ret); 1198 1199 disp = (void*)0xdeadbeef; 1200 ret = 0xdead; 1201 V_VT(&v) = VT_I4; 1202 V_I4(&v) = cookie; 1203 VariantInit(&v2); 1204 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_BROWSER, &ret, SWFO_COOKIEPASSED, &disp); 1205 todo_wine 1206 ok(hr == S_FALSE, "got 0x%08x\n", hr); 1207 ok(disp == NULL, "got %p\n", disp); 1208 ok(ret == 0, "got %d\n", ret); 1209 1210 hr = IShellWindows_Revoke(shellwindows, cookie); 1211 todo_wine 1212 ok(hr == S_OK, "got 0x%08x\n", hr); 1213 DestroyWindow(hwnd); 1214 IShellWindows_Release(shellwindows); 1215 } 1216 1217 static void test_ParseName(void) 1218 { 1219 static const WCHAR cadabraW[] = {'c','a','d','a','b','r','a',0}; 1220 WCHAR pathW[MAX_PATH]; 1221 IShellDispatch *sd; 1222 FolderItem *item; 1223 Folder *folder; 1224 HRESULT hr; 1225 VARIANT v; 1226 BSTR str; 1227 1228 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 1229 &IID_IShellDispatch, (void**)&sd); 1230 ok(hr == S_OK, "got 0x%08x\n", hr); 1231 1232 GetTempPathW(ARRAY_SIZE(pathW), pathW); 1233 V_VT(&v) = VT_BSTR; 1234 V_BSTR(&v) = SysAllocString(pathW); 1235 hr = IShellDispatch_NameSpace(sd, v, &folder); 1236 ok(hr == S_OK, "got 0x%08x\n", hr); 1237 VariantClear(&v); 1238 1239 item = (void*)0xdeadbeef; 1240 hr = Folder_ParseName(folder, NULL, &item); 1241 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr); 1242 ok(item == NULL, "got %p\n", item); 1243 1244 /* empty name */ 1245 str = SysAllocStringLen(NULL, 0); 1246 item = (void*)0xdeadbeef; 1247 hr = Folder_ParseName(folder, str, &item); 1248 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr); 1249 ok(item == NULL, "got %p\n", item); 1250 SysFreeString(str); 1251 1252 /* path doesn't exist */ 1253 str = SysAllocString(cadabraW); 1254 item = (void*)0xdeadbeef; 1255 hr = Folder_ParseName(folder, str, &item); 1256 ok(hr == S_FALSE || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* win2k */, 1257 "got 0x%08x\n", hr); 1258 ok(item == NULL, "got %p\n", item); 1259 SysFreeString(str); 1260 1261 lstrcatW(pathW, cadabraW); 1262 CreateDirectoryW(pathW, NULL); 1263 1264 str = SysAllocString(cadabraW); 1265 item = NULL; 1266 hr = Folder_ParseName(folder, str, &item); 1267 ok(hr == S_OK, "got 0x%08x\n", hr); 1268 ok(item != NULL, "got %p\n", item); 1269 SysFreeString(str); 1270 1271 hr = FolderItem_get_Path(item, &str); 1272 ok(hr == S_OK, "got 0x%08x\n", hr); 1273 ok(str[0] != 0, "path %s\n", wine_dbgstr_w(str)); 1274 SysFreeString(str); 1275 1276 RemoveDirectoryW(pathW); 1277 FolderItem_Release(item); 1278 Folder_Release(folder); 1279 IShellDispatch_Release(sd); 1280 } 1281 1282 static void test_Verbs(void) 1283 { 1284 FolderItemVerbs *verbs, *verbs2; 1285 WCHAR pathW[MAX_PATH]; 1286 FolderItemVerb *verb; 1287 IShellDispatch *sd; 1288 FolderItem *item; 1289 Folder2 *folder2; 1290 IDispatch *disp; 1291 Folder *folder; 1292 HRESULT hr; 1293 LONG count, i; 1294 VARIANT v; 1295 BSTR str; 1296 1297 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 1298 &IID_IShellDispatch, (void**)&sd); 1299 ok(hr == S_OK, "got 0x%08x\n", hr); 1300 1301 GetTempPathW(ARRAY_SIZE(pathW), pathW); 1302 V_VT(&v) = VT_BSTR; 1303 V_BSTR(&v) = SysAllocString(pathW); 1304 hr = IShellDispatch_NameSpace(sd, v, &folder); 1305 ok(hr == S_OK, "got 0x%08x\n", hr); 1306 VariantClear(&v); 1307 1308 hr = Folder_QueryInterface(folder, &IID_Folder2, (void**)&folder2); 1309 ok(hr == S_OK, "got 0x%08x\n", hr); 1310 Folder_Release(folder); 1311 1312 hr = Folder2_get_Self(folder2, &item); 1313 ok(hr == S_OK, "got 0x%08x\n", hr); 1314 Folder2_Release(folder2); 1315 1316 if (0) { /* crashes on some systems */ 1317 hr = FolderItem_Verbs(item, NULL); 1318 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 1319 } 1320 hr = FolderItem_Verbs(item, &verbs); 1321 ok(hr == S_OK, "got 0x%08x\n", hr); 1322 1323 hr = FolderItem_Verbs(item, &verbs2); 1324 ok(hr == S_OK, "got 0x%08x\n", hr); 1325 ok(verbs2 != verbs, "Unexpected verbs pointer.\n"); 1326 FolderItemVerbs_Release(verbs2); 1327 1328 disp = (void *)0xdeadbeef; 1329 hr = FolderItemVerbs_get_Application(verbs, &disp); 1330 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); 1331 ok(disp == NULL, "Unexpected application pointer.\n"); 1332 1333 disp = (void *)0xdeadbeef; 1334 hr = FolderItemVerbs_get_Parent(verbs, &disp); 1335 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); 1336 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp); 1337 1338 if (0) { /* crashes on winxp/win2k3 */ 1339 hr = FolderItemVerbs_get_Count(verbs, NULL); 1340 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 1341 } 1342 count = 0; 1343 hr = FolderItemVerbs_get_Count(verbs, &count); 1344 ok(hr == S_OK, "got 0x%08x\n", hr); 1345 ok(count > 0, "got count %d\n", count); 1346 1347 if (0) { /* crashes on winxp/win2k3 */ 1348 V_VT(&v) = VT_I4; 1349 V_I4(&v) = 0; 1350 hr = FolderItemVerbs_Item(verbs, v, NULL); 1351 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 1352 } 1353 /* there's always one item more, so you can access [0,count], 1354 instead of actual [0,count) */ 1355 for (i = 0; i <= count; i++) { 1356 V_VT(&v) = VT_I4; 1357 V_I4(&v) = i; 1358 hr = FolderItemVerbs_Item(verbs, v, &verb); 1359 ok(hr == S_OK, "got 0x%08x\n", hr); 1360 hr = FolderItemVerb_get_Name(verb, &str); 1361 ok(hr == S_OK, "got 0x%08x\n", hr); 1362 ok(str != NULL, "%d: name %s\n", i, wine_dbgstr_w(str)); 1363 if (i == count) 1364 ok(str[0] == 0, "%d: got terminating item %s\n", i, wine_dbgstr_w(str)); 1365 1366 disp = (void *)0xdeadbeef; 1367 hr = FolderItemVerb_get_Parent(verb, &disp); 1368 ok(hr == E_NOTIMPL, "got %#x.\n", hr); 1369 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp); 1370 1371 disp = (void *)0xdeadbeef; 1372 hr = FolderItemVerb_get_Application(verb, &disp); 1373 ok(hr == E_NOTIMPL, "got %#x.\n", hr); 1374 ok(disp == NULL, "Unexpected parent pointer %p.\n", disp); 1375 1376 SysFreeString(str); 1377 FolderItemVerb_Release(verb); 1378 } 1379 1380 V_VT(&v) = VT_I4; 1381 V_I4(&v) = count+1; 1382 verb = NULL; 1383 hr = FolderItemVerbs_Item(verbs, v, &verb); 1384 ok(hr == S_OK, "got 0x%08x\n", hr); 1385 ok(verb == NULL, "got %p\n", verb); 1386 1387 FolderItemVerbs_Release(verbs); 1388 FolderItem_Release(item); 1389 IShellDispatch_Release(sd); 1390 } 1391 1392 static void test_ShellExecute(void) 1393 { 1394 HRESULT hr; 1395 IShellDispatch2 *sd; 1396 BSTR name; 1397 VARIANT args, dir, op, show; 1398 1399 static const WCHAR regW[] = {'r','e','g',0}; 1400 1401 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 1402 &IID_IShellDispatch2, (void**)&sd); 1403 if (hr != S_OK) 1404 { 1405 win_skip("IShellDispatch2 not supported\n"); 1406 return; 1407 } 1408 1409 VariantInit(&args); 1410 VariantInit(&dir); 1411 VariantInit(&op); 1412 VariantInit(&show); 1413 1414 V_VT(&show) = VT_I4; 1415 V_I4(&show) = 0; 1416 1417 name = SysAllocString(regW); 1418 1419 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show); 1420 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr); 1421 1422 /* test invalid value for show */ 1423 V_VT(&show) = VT_BSTR; 1424 V_BSTR(&show) = name; 1425 1426 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show); 1427 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr); 1428 1429 SysFreeString(name); 1430 IShellDispatch2_Release(sd); 1431 } 1432 1433 START_TEST(shelldispatch) 1434 { 1435 HRESULT r; 1436 1437 r = CoInitialize(NULL); 1438 ok(SUCCEEDED(r), "CoInitialize failed: %08x\n", r); 1439 if (FAILED(r)) 1440 return; 1441 1442 init_function_pointers(); 1443 test_namespace(); 1444 test_items(); 1445 test_service(); 1446 test_ShellFolderViewDual(); 1447 test_ShellWindows(); 1448 test_ParseName(); 1449 test_Verbs(); 1450 test_ShellExecute(); 1451 1452 CoUninitialize(); 1453 } 1454