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 "wine/test.h" 29 30 #include "initguid.h" 31 32 #define EXPECT_HR(hr,hr_exp) \ 33 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp) 34 35 static const WCHAR winetestW[] = {'w','i','n','e','t','e','s','t',0}; 36 37 static HRESULT (WINAPI *pSHGetFolderPathW)(HWND, int, HANDLE, DWORD, LPWSTR); 38 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*); 39 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *); 40 static DWORD (WINAPI *pGetLongPathNameW)(LPCWSTR, LPWSTR, DWORD); 41 42 /* Updated Windows 7 has a new IShellDispatch6 in its typelib */ 43 DEFINE_GUID(IID_IWin7ShellDispatch6, 0x34936ba1, 0x67ad, 0x4c41, 0x99,0xb8, 0x8c,0x12,0xdf,0xf1,0xe9,0x74); 44 45 static void init_function_pointers(void) 46 { 47 HMODULE hshell32, hkernel32; 48 49 hshell32 = GetModuleHandleA("shell32.dll"); 50 hkernel32 = GetModuleHandleA("kernel32.dll"); 51 pSHGetFolderPathW = (void*)GetProcAddress(hshell32, "SHGetFolderPathW"); 52 pSHGetNameFromIDList = (void*)GetProcAddress(hshell32, "SHGetNameFromIDList"); 53 pSHGetSpecialFolderLocation = (void*)GetProcAddress(hshell32, 54 "SHGetSpecialFolderLocation"); 55 pGetLongPathNameW = (void*)GetProcAddress(hkernel32, "GetLongPathNameW"); 56 } 57 58 static void test_namespace(void) 59 { 60 static const ShellSpecialFolderConstants special_folders[] = 61 { 62 ssfDESKTOP, 63 ssfPROGRAMS, 64 ssfCONTROLS, 65 ssfPRINTERS, 66 ssfPERSONAL, 67 ssfFAVORITES, 68 ssfSTARTUP, 69 ssfRECENT, 70 ssfSENDTO, 71 ssfBITBUCKET, 72 ssfSTARTMENU, 73 ssfDESKTOPDIRECTORY, 74 ssfDRIVES, 75 ssfNETWORK, 76 ssfNETHOOD, 77 ssfFONTS, 78 ssfTEMPLATES, 79 ssfCOMMONSTARTMENU, 80 ssfCOMMONPROGRAMS, 81 ssfCOMMONSTARTUP, 82 ssfCOMMONDESKTOPDIR, 83 ssfAPPDATA, 84 ssfPRINTHOOD, 85 ssfLOCALAPPDATA, 86 ssfALTSTARTUP, 87 ssfCOMMONALTSTARTUP, 88 ssfCOMMONFAVORITES, 89 ssfINTERNETCACHE, 90 ssfCOOKIES, 91 ssfHISTORY, 92 ssfCOMMONAPPDATA, 93 ssfWINDOWS, 94 ssfSYSTEM, 95 ssfPROGRAMFILES, 96 ssfMYPICTURES, 97 ssfPROFILE, 98 ssfSYSTEMx86, 99 ssfPROGRAMFILESx86, 100 }; 101 102 static const WCHAR backslashW[] = {'\\',0}; 103 static const WCHAR clsidW[] = { 104 ':',':','{','6','4','5','F','F','0','4','0','-','5','0','8','1','-', 105 '1','0','1','B','-','9','F','0','8','-', 106 '0','0','A','A','0','0','2','F','9','5','4','E','}',0}; 107 108 static WCHAR tempW[MAX_PATH], curW[MAX_PATH]; 109 WCHAR *long_pathW = NULL; 110 HRESULT r; 111 IShellDispatch *sd; 112 Folder *folder; 113 Folder2 *folder2; 114 FolderItem *item; 115 VARIANT var; 116 BSTR title, item_path; 117 int len, i; 118 119 r = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 120 &IID_IShellDispatch, (LPVOID*)&sd); 121 if (r == REGDB_E_CLASSNOTREG) /* NT4 */ 122 { 123 win_skip("skipping IShellDispatch tests\n"); 124 return; 125 } 126 ok(SUCCEEDED(r), "CoCreateInstance failed: %08x\n", r); 127 if (FAILED(r)) 128 return; 129 130 VariantInit(&var); 131 folder = (void*)0xdeadbeef; 132 r = IShellDispatch_NameSpace(sd, var, &folder); 133 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 134 ok(folder == NULL, "expected NULL, got %p\n", folder); 135 136 /* test valid folder ids */ 137 for (i = 0; i < sizeof(special_folders)/sizeof(special_folders[0]); i++) 138 { 139 V_VT(&var) = VT_I4; 140 V_I4(&var) = special_folders[i]; 141 folder = (void*)0xdeadbeef; 142 r = IShellDispatch_NameSpace(sd, var, &folder); 143 if (special_folders[i] == ssfALTSTARTUP || special_folders[i] == ssfCOMMONALTSTARTUP) 144 ok(r == S_OK || broken(r == S_FALSE) /* winxp */, "Failed to get folder for index %#x, got %08x\n", special_folders[i], r); 145 else 146 ok(r == S_OK, "Failed to get folder for index %#x, got %08x\n", special_folders[i], r); 147 if (folder) 148 Folder_Release(folder); 149 } 150 151 V_VT(&var) = VT_I4; 152 V_I4(&var) = -1; 153 folder = (void*)0xdeadbeef; 154 r = IShellDispatch_NameSpace(sd, var, &folder); 155 todo_wine { 156 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 157 ok(folder == NULL, "got %p\n", folder); 158 if (r == S_OK) 159 Folder_Release(folder); 160 } 161 V_VT(&var) = VT_I4; 162 V_I4(&var) = ssfPROGRAMFILES; 163 r = IShellDispatch_NameSpace(sd, var, &folder); 164 ok(r == S_OK || 165 broken(r == S_FALSE), /* NT4 */ 166 "IShellDispatch::NameSpace failed: %08x\n", r); 167 if (r == S_OK) 168 { 169 static WCHAR path[MAX_PATH]; 170 171 if (pSHGetFolderPathW) 172 { 173 r = pSHGetFolderPathW(NULL, CSIDL_PROGRAM_FILES, NULL, 174 SHGFP_TYPE_CURRENT, path); 175 ok(r == S_OK, "SHGetFolderPath failed: %08x\n", r); 176 } 177 r = Folder_get_Title(folder, &title); 178 todo_wine 179 ok(r == S_OK, "Folder::get_Title failed: %08x\n", r); 180 if (r == S_OK) 181 { 182 /* On Win2000-2003 title is equal to program files directory name in 183 HKLM\Software\Microsoft\Windows\CurrentVersion\ProgramFilesDir. 184 On newer Windows it seems constant and is not changed 185 if the program files directory name is changed */ 186 if (pSHGetSpecialFolderLocation && pSHGetNameFromIDList) 187 { 188 LPITEMIDLIST pidl; 189 PWSTR name; 190 191 r = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl); 192 ok(r == S_OK, "SHGetSpecialFolderLocation failed: %08x\n", r); 193 r = pSHGetNameFromIDList(pidl, SIGDN_NORMALDISPLAY, &name); 194 ok(r == S_OK, "SHGetNameFromIDList failed: %08x\n", r); 195 todo_wine 196 ok(!lstrcmpW(title, name), "expected %s, got %s\n", 197 wine_dbgstr_w(name), wine_dbgstr_w(title)); 198 CoTaskMemFree(name); 199 CoTaskMemFree(pidl); 200 } 201 else if (pSHGetFolderPathW) 202 { 203 WCHAR *p; 204 205 p = path + lstrlenW(path); 206 while (path < p && *(p - 1) != '\\') 207 p--; 208 ok(!lstrcmpiW(title, p), "expected %s, got %s\n", 209 wine_dbgstr_w(p), wine_dbgstr_w(title)); 210 } 211 else skip("skipping Folder::get_Title test\n"); 212 SysFreeString(title); 213 } 214 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2); 215 ok(r == S_OK, "Folder::QueryInterface failed: %08x\n", r); 216 if (r == S_OK) 217 { 218 r = Folder2_get_Self(folder2, &item); 219 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r); 220 if (r == S_OK) 221 { 222 r = FolderItem_get_Path(item, &item_path); 223 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r); 224 if (pSHGetFolderPathW) 225 ok(!lstrcmpiW(item_path, path), "expected %s, got %s\n", 226 wine_dbgstr_w(path), wine_dbgstr_w(item_path)); 227 SysFreeString(item_path); 228 FolderItem_Release(item); 229 } 230 Folder2_Release(folder2); 231 } 232 Folder_Release(folder); 233 } 234 235 V_VT(&var) = VT_I4; 236 V_I4(&var) = ssfBITBUCKET; 237 r = IShellDispatch_NameSpace(sd, var, &folder); 238 ok(r == S_OK || 239 broken(r == S_FALSE), /* NT4 */ 240 "IShellDispatch::NameSpace failed: %08x\n", r); 241 if (r == S_OK) 242 { 243 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2); 244 ok(r == S_OK || 245 broken(r == E_NOINTERFACE), /* NT4 */ 246 "Folder::QueryInterface failed: %08x\n", r); 247 if (r == S_OK) 248 { 249 r = Folder2_get_Self(folder2, &item); 250 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r); 251 if (r == S_OK) 252 { 253 r = FolderItem_get_Path(item, &item_path); 254 todo_wine 255 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r); 256 todo_wine 257 ok(!lstrcmpW(item_path, clsidW), "expected %s, got %s\n", 258 wine_dbgstr_w(clsidW), wine_dbgstr_w(item_path)); 259 SysFreeString(item_path); 260 FolderItem_Release(item); 261 } 262 Folder2_Release(folder2); 263 } 264 Folder_Release(folder); 265 } 266 267 GetTempPathW(MAX_PATH, tempW); 268 GetCurrentDirectoryW(MAX_PATH, curW); 269 SetCurrentDirectoryW(tempW); 270 CreateDirectoryW(winetestW, NULL); 271 V_VT(&var) = VT_BSTR; 272 V_BSTR(&var) = SysAllocString(winetestW); 273 r = IShellDispatch_NameSpace(sd, var, &folder); 274 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 275 SysFreeString(V_BSTR(&var)); 276 277 GetFullPathNameW(winetestW, MAX_PATH, tempW, NULL); 278 if (pGetLongPathNameW) 279 { 280 len = pGetLongPathNameW(tempW, NULL, 0); 281 long_pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 282 if (long_pathW) 283 pGetLongPathNameW(tempW, long_pathW, len); 284 } 285 V_VT(&var) = VT_BSTR; 286 V_BSTR(&var) = SysAllocString(tempW); 287 r = IShellDispatch_NameSpace(sd, var, &folder); 288 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r); 289 if (r == S_OK) 290 { 291 r = Folder_get_Title(folder, &title); 292 ok(r == S_OK, "Folder::get_Title failed: %08x\n", r); 293 if (r == S_OK) 294 { 295 ok(!lstrcmpW(title, winetestW), "bad title: %s\n", 296 wine_dbgstr_w(title)); 297 SysFreeString(title); 298 } 299 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2); 300 ok(r == S_OK || 301 broken(r == E_NOINTERFACE), /* NT4 */ 302 "Folder::QueryInterface failed: %08x\n", r); 303 if (r == S_OK) 304 { 305 r = Folder2_get_Self(folder2, &item); 306 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r); 307 if (r == S_OK) 308 { 309 r = FolderItem_get_Path(item, &item_path); 310 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r); 311 if (long_pathW) 312 ok(!lstrcmpW(item_path, long_pathW), 313 "expected %s, got %s\n", wine_dbgstr_w(long_pathW), 314 wine_dbgstr_w(item_path)); 315 SysFreeString(item_path); 316 FolderItem_Release(item); 317 } 318 Folder2_Release(folder2); 319 } 320 Folder_Release(folder); 321 } 322 SysFreeString(V_BSTR(&var)); 323 324 len = lstrlenW(tempW); 325 if (len < MAX_PATH - 1) 326 { 327 lstrcatW(tempW, backslashW); 328 V_VT(&var) = VT_BSTR; 329 V_BSTR(&var) = SysAllocString(tempW); 330 r = IShellDispatch_NameSpace(sd, var, &folder); 331 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r); 332 if (r == S_OK) 333 { 334 r = Folder_get_Title(folder, &title); 335 ok(r == S_OK, "Folder::get_Title failed: %08x\n", r); 336 if (r == S_OK) 337 { 338 ok(!lstrcmpW(title, winetestW), "bad title: %s\n", 339 wine_dbgstr_w(title)); 340 SysFreeString(title); 341 } 342 r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2); 343 ok(r == S_OK || 344 broken(r == E_NOINTERFACE), /* NT4 */ 345 "Folder::QueryInterface failed: %08x\n", r); 346 if (r == S_OK) 347 { 348 r = Folder2_get_Self(folder2, &item); 349 ok(r == S_OK, "Folder::get_Self failed: %08x\n", r); 350 if (r == S_OK) 351 { 352 r = FolderItem_get_Path(item, &item_path); 353 ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r); 354 if (long_pathW) 355 ok(!lstrcmpW(item_path, long_pathW), 356 "expected %s, got %s\n", wine_dbgstr_w(long_pathW), 357 wine_dbgstr_w(item_path)); 358 SysFreeString(item_path); 359 FolderItem_Release(item); 360 } 361 Folder2_Release(folder2); 362 } 363 Folder_Release(folder); 364 } 365 SysFreeString(V_BSTR(&var)); 366 } 367 368 HeapFree(GetProcessHeap(), 0, long_pathW); 369 RemoveDirectoryW(winetestW); 370 SetCurrentDirectoryW(curW); 371 IShellDispatch_Release(sd); 372 } 373 374 static void test_items(void) 375 { 376 WCHAR wstr[MAX_PATH], orig_dir[MAX_PATH]; 377 HRESULT r; 378 IShellDispatch *sd = NULL; 379 Folder *folder = NULL; 380 FolderItems *items = NULL; 381 FolderItems2 *items2 = NULL; 382 FolderItems3 *items3 = NULL; 383 FolderItem *item = (FolderItem*)0xdeadbeef; 384 IDispatch *disp = NULL; 385 IUnknown *unk = NULL; 386 FolderItemVerbs *verbs = (FolderItemVerbs*)0xdeadbeef; 387 VARIANT var; 388 LONG lcount = -1; 389 390 r = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, &IID_IShellDispatch, (void**)&sd); 391 ok(SUCCEEDED(r), "CoCreateInstance failed: %08x\n", r); 392 ok(!!sd, "sd is null\n"); 393 394 GetTempPathW(MAX_PATH, wstr); 395 GetCurrentDirectoryW(MAX_PATH, orig_dir); 396 SetCurrentDirectoryW(wstr); 397 CreateDirectoryW(winetestW, NULL); 398 GetFullPathNameW(winetestW, MAX_PATH, wstr, NULL); 399 V_VT(&var) = VT_BSTR; 400 V_BSTR(&var) = SysAllocString(wstr); 401 r = IShellDispatch_NameSpace(sd, var, &folder); 402 ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r); 403 ok(!!folder, "folder is null\n"); 404 SysFreeString(V_BSTR(&var)); 405 IShellDispatch_Release(sd); 406 SetCurrentDirectoryW(winetestW); 407 408 r = Folder_Items(folder, &items); 409 ok(r == S_OK, "Folder::Items failed: %08x\n", r); 410 ok(!!items, "items is null\n"); 411 r = FolderItems_QueryInterface(items, &IID_FolderItems2, (void**)&items2); 412 ok(r == S_OK || broken(r == E_NOINTERFACE) /* xp and later */, "FolderItems::QueryInterface failed: %08x\n", r); 413 ok(!!items2 || broken(!items2) /* xp and later */, "items2 is null\n"); 414 r = FolderItems_QueryInterface(items, &IID_FolderItems3, (void**)&items3); 415 ok(r == S_OK, "FolderItems::QueryInterface failed: %08x\n", r); 416 ok(!!items3, "items3 is null\n"); 417 Folder_Release(folder); 418 419 if (0) /* crashes on all versions of Windows */ 420 r = FolderItems_get_Count(items, NULL); 421 422 r = FolderItems_get_Count(items, &lcount); 423 ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r); 424 ok(!lcount, "expected 0 files, got %d\n", lcount); 425 426 V_VT(&var) = VT_I4; 427 V_I4(&var) = 0; 428 429 if (0) /* crashes on all versions of Windows */ 430 r = FolderItems_Item(items, var, NULL); 431 432 r = FolderItems_Item(items, var, &item); 433 todo_wine 434 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 435 ok(!item, "item is not null\n"); 436 437 if (0) /* crashes on xp */ 438 { 439 r = FolderItems_get_Application(items, NULL); 440 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r); 441 } 442 443 r = FolderItems_get_Application(items, &disp); 444 todo_wine 445 ok(r == S_OK, "FolderItems::get_Application failed: %08x\n", r); 446 todo_wine 447 ok(!!disp, "disp is null\n"); 448 if (disp) IDispatch_Release(disp); 449 450 if (0) /* crashes on xp */ 451 { 452 r = FolderItems_get_Parent(items, NULL); 453 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r); 454 } 455 456 disp = (IDispatch*)0xdeadbeef; 457 r = FolderItems_get_Parent(items, &disp); 458 ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r); 459 ok(!disp, "disp is not null\n"); 460 461 if (0) /* crashes on xp */ 462 { 463 r = FolderItems__NewEnum(items, NULL); 464 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r); 465 } 466 467 r = FolderItems__NewEnum(items, &unk); 468 todo_wine 469 ok(r == S_OK, "FolderItems::_NewEnum failed: %08x\n", r); 470 todo_wine 471 ok(!!unk, "unk is null\n"); 472 if (unk) IUnknown_Release(unk); 473 474 if (items3) 475 { 476 r = FolderItems3_Filter(items3, 0, NULL); 477 todo_wine 478 ok(r == S_OK, "expected S_OK, got %08x\n", r); 479 480 if (0) /* crashes on xp */ 481 { 482 r = FolderItems3_get_Verbs(items3, NULL); 483 ok(r == E_INVALIDARG, "expected E_INVALIDARG, got %08x\n", r); 484 } 485 486 r = FolderItems3_get_Verbs(items3, &verbs); 487 todo_wine 488 ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r); 489 ok(!verbs, "verbs is not null\n"); 490 } 491 492 GetTempPathW(MAX_PATH, wstr); 493 SetCurrentDirectoryW(wstr); 494 RemoveDirectoryW(winetestW); 495 SetCurrentDirectoryW(orig_dir); 496 497 FolderItems_Release(items); 498 if (items2) FolderItems2_Release(items2); 499 if (items3) FolderItems3_Release(items3); 500 } 501 502 static void test_service(void) 503 { 504 static const WCHAR spooler[] = {'S','p','o','o','l','e','r',0}; 505 static const WCHAR dummyW[] = {'d','u','m','m','y',0}; 506 SERVICE_STATUS_PROCESS status; 507 SC_HANDLE scm, service; 508 IShellDispatch2 *sd; 509 DWORD dummy; 510 HRESULT hr; 511 BSTR name; 512 VARIANT v; 513 514 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 515 &IID_IShellDispatch2, (void**)&sd); 516 if (hr != S_OK) 517 { 518 win_skip("IShellDispatch2 not supported\n"); 519 return; 520 } 521 522 V_VT(&v) = VT_I2; 523 V_I2(&v) = 10; 524 hr = IShellDispatch2_IsServiceRunning(sd, NULL, &v); 525 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v)); 526 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v)); 527 EXPECT_HR(hr, S_OK); 528 529 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); 530 service = OpenServiceW(scm, spooler, SERVICE_QUERY_STATUS); 531 QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy); 532 CloseServiceHandle(service); 533 CloseServiceHandle(scm); 534 535 /* service should exist */ 536 name = SysAllocString(spooler); 537 V_VT(&v) = VT_I2; 538 hr = IShellDispatch2_IsServiceRunning(sd, name, &v); 539 EXPECT_HR(hr, S_OK); 540 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v)); 541 if (status.dwCurrentState == SERVICE_RUNNING) 542 ok(V_BOOL(&v) == VARIANT_TRUE, "got %d\n", V_BOOL(&v)); 543 else 544 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v)); 545 SysFreeString(name); 546 547 /* service doesn't exist */ 548 name = SysAllocString(dummyW); 549 V_VT(&v) = VT_I2; 550 hr = IShellDispatch2_IsServiceRunning(sd, name, &v); 551 EXPECT_HR(hr, S_OK); 552 ok(V_VT(&v) == VT_BOOL, "got %d\n", V_VT(&v)); 553 ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v)); 554 SysFreeString(name); 555 556 IShellDispatch2_Release(sd); 557 } 558 559 static void test_dispatch_typeinfo(IDispatch *disp, REFIID *riid) 560 { 561 ITypeInfo *typeinfo; 562 TYPEATTR *typeattr; 563 UINT count; 564 HRESULT hr; 565 566 count = 10; 567 hr = IDispatch_GetTypeInfoCount(disp, &count); 568 ok(hr == S_OK, "got 0x%08x\n", hr); 569 ok(count == 1, "got %u\n", count); 570 571 hr = IDispatch_GetTypeInfo(disp, 0, LOCALE_SYSTEM_DEFAULT, &typeinfo); 572 ok(hr == S_OK, "got 0x%08x\n", hr); 573 574 hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr); 575 ok(hr == S_OK, "got 0x%08x\n", hr); 576 while (!IsEqualGUID(*riid, &IID_NULL)) { 577 if (IsEqualGUID(&typeattr->guid, *riid)) 578 break; 579 riid++; 580 } 581 ok(IsEqualGUID(&typeattr->guid, *riid), "unexpected type guid %s\n", wine_dbgstr_guid(&typeattr->guid)); 582 583 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr); 584 ITypeInfo_Release(typeinfo); 585 } 586 587 static void test_ShellFolderViewDual(void) 588 { 589 static const IID *shelldisp_riids[] = { 590 &IID_IShellDispatch6, 591 &IID_IShellDispatch5, 592 &IID_IShellDispatch4, 593 &IID_IShellDispatch2, 594 &IID_IWin7ShellDispatch6, 595 &IID_NULL 596 }; 597 IShellFolderViewDual *viewdual; 598 IShellFolder *desktop, *tmpdir; 599 IShellView *view, *view2; 600 IDispatch *disp, *disp2; 601 WCHAR pathW[MAX_PATH]; 602 LPITEMIDLIST pidl; 603 HRESULT hr; 604 605 /* IShellFolderViewDual is not an IShellView extension */ 606 hr = SHGetDesktopFolder(&desktop); 607 ok(hr == S_OK, "got 0x%08x\n", hr); 608 609 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view); 610 ok(hr == S_OK, "got 0x%08x\n", hr); 611 612 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual); 613 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 614 615 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp); 616 ok(hr == S_OK, "got 0x%08x\n", hr); 617 618 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp2); 619 ok(hr == S_OK, "got 0x%08x\n", hr); 620 ok(disp2 == disp, "got %p, %p\n", disp2, disp); 621 IDispatch_Release(disp2); 622 623 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&viewdual); 624 ok(hr == S_OK, "got 0x%08x\n", hr); 625 ok(disp == (IDispatch*)viewdual, "got %p, expected %p\n", viewdual, disp); 626 627 hr = IShellFolderViewDual_QueryInterface(viewdual, &IID_IShellView, (void**)&view2); 628 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 629 630 /* get_Application() */ 631 632 if (0) /* crashes on pre-vista */ { 633 hr = IShellFolderViewDual_get_Application(viewdual, NULL); 634 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 635 } 636 hr = IShellFolderViewDual_get_Application(viewdual, &disp2); 637 ok(hr == S_OK, "got 0x%08x\n", hr); 638 ok(disp2 != (IDispatch*)viewdual, "got %p, %p\n", disp2, viewdual); 639 test_dispatch_typeinfo(disp2, shelldisp_riids); 640 IDispatch_Release(disp2); 641 642 IShellFolderViewDual_Release(viewdual); 643 IDispatch_Release(disp); 644 645 disp = (void*)0xdeadbeef; 646 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IShellFolderViewDual, (void**)&disp); 647 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* win2k */, "got 0x%08x\n", hr); 648 ok(disp == NULL, "got %p\n", disp); 649 IShellView_Release(view); 650 651 /* Try with some other folder, that's not a desktop */ 652 GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW); 653 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, pathW, NULL, &pidl, NULL); 654 ok(hr == S_OK, "got 0x%08x\n", hr); 655 656 hr = IShellFolder_BindToObject(desktop, pidl, NULL, &IID_IShellFolder, (void**)&tmpdir); 657 ok(hr == S_OK, "got 0x%08x\n", hr); 658 CoTaskMemFree(pidl); 659 660 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view); 661 ok(hr == S_OK, "got 0x%08x\n", hr); 662 663 hr = IShellView_QueryInterface(view, &IID_IShellFolderViewDual, (void**)&viewdual); 664 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 665 666 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&disp); 667 ok(hr == S_OK, "got 0x%08x\n", hr); 668 IDispatch_Release(disp); 669 IShellView_Release(view); 670 671 IShellFolder_Release(tmpdir); 672 IShellFolder_Release(desktop); 673 } 674 675 static void test_ShellWindows(void) 676 { 677 IShellWindows *shellwindows; 678 LONG cookie, cookie2, ret; 679 IDispatch *disp; 680 VARIANT v, v2; 681 HRESULT hr; 682 HWND hwnd; 683 684 hr = CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, 685 &IID_IShellWindows, (void**)&shellwindows); 686 ok(hr == S_OK, "got 0x%08x\n", hr); 687 /* TODO: remove when explorer startup with clean prefix is fixed */ 688 if (hr != S_OK) 689 return; 690 691 if (0) /* NULL out argument - currently crashes on Wine */ { 692 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, NULL); 693 ok(hr == HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), "got 0x%08x\n", hr); 694 } 695 hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, &cookie); 696 todo_wine 697 ok(hr == E_POINTER, "got 0x%08x\n", hr); 698 699 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie); 700 todo_wine 701 ok(hr == E_POINTER, "got 0x%08x\n", hr); 702 703 hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie); 704 todo_wine 705 ok(hr == E_POINTER, "got 0x%08x\n", hr); 706 707 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP, 708 0, 0, 50, 14, 0, 0, 0, NULL); 709 ok(hwnd != NULL, "got %p, error %d\n", hwnd, GetLastError()); 710 711 cookie = 0; 712 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie); 713 todo_wine { 714 ok(hr == S_OK, "got 0x%08x\n", hr); 715 ok(cookie != 0, "got %d\n", cookie); 716 } 717 cookie2 = 0; 718 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie2); 719 todo_wine { 720 ok(hr == S_OK, "got 0x%08x\n", hr); 721 ok(cookie2 != 0 && cookie2 != cookie, "got %d\n", cookie2); 722 } 723 hr = IShellWindows_Revoke(shellwindows, cookie); 724 todo_wine 725 ok(hr == S_OK, "got 0x%08x\n", hr); 726 hr = IShellWindows_Revoke(shellwindows, cookie2); 727 todo_wine 728 ok(hr == S_OK, "got 0x%08x\n", hr); 729 730 hr = IShellWindows_Revoke(shellwindows, 0); 731 todo_wine 732 ok(hr == S_FALSE, "got 0x%08x\n", hr); 733 734 /* we can register ourselves as desktop, but FindWindowSW still returns real desktop window */ 735 cookie = 0; 736 hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_DESKTOP, &cookie); 737 todo_wine { 738 ok(hr == S_OK, "got 0x%08x\n", hr); 739 ok(cookie != 0, "got %d\n", cookie); 740 } 741 disp = (void*)0xdeadbeef; 742 ret = 0xdead; 743 VariantInit(&v); 744 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, SWFO_NEEDDISPATCH, &disp); 745 ok(hr == S_OK || broken(hr == S_FALSE), "got 0x%08x\n", hr); 746 if (hr == S_FALSE) /* winxp and earlier */ { 747 win_skip("SWC_DESKTOP is not supported, some tests will be skipped.\n"); 748 /* older versions allowed to regiser SWC_DESKTOP and access it with FindWindowSW */ 749 ok(disp == NULL, "got %p\n", disp); 750 ok(ret == 0, "got %d\n", ret); 751 } 752 else { 753 static const IID *browser_riids[] = { 754 &IID_IWebBrowser2, 755 &IID_NULL 756 }; 757 758 static const IID *viewdual_riids[] = { 759 &IID_IShellFolderViewDual3, 760 &IID_NULL 761 }; 762 763 IShellFolderViewDual *view; 764 IShellBrowser *sb, *sb2; 765 IServiceProvider *sp; 766 IDispatch *doc, *app; 767 IWebBrowser2 *wb; 768 IShellView *sv; 769 IUnknown *unk; 770 771 ok(disp != NULL, "got %p\n", disp); 772 ok(ret != HandleToUlong(hwnd), "got %d\n", ret); 773 774 /* IDispatch-related tests */ 775 test_dispatch_typeinfo(disp, browser_riids); 776 777 /* IWebBrowser2 */ 778 hr = IDispatch_QueryInterface(disp, &IID_IWebBrowser2, (void**)&wb); 779 ok(hr == S_OK, "got 0x%08x\n", hr); 780 781 hr = IWebBrowser2_Refresh(wb); 782 todo_wine 783 ok(hr == S_OK, "got 0x%08x\n", hr); 784 785 hr = IWebBrowser2_get_Application(wb, &app); 786 ok(hr == S_OK, "got 0x%08x\n", hr); 787 ok(disp == app, "got %p, %p\n", app, disp); 788 IDispatch_Release(app); 789 790 hr = IWebBrowser2_get_Document(wb, &doc); 791 todo_wine 792 ok(hr == S_OK, "got 0x%08x\n", hr); 793 if (hr == S_OK) { 794 test_dispatch_typeinfo(doc, viewdual_riids); 795 } 796 IWebBrowser2_Release(wb); 797 798 /* IServiceProvider */ 799 hr = IDispatch_QueryInterface(disp, &IID_IShellFolderViewDual, (void**)&view); 800 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 801 802 hr = IDispatch_QueryInterface(disp, &IID_IServiceProvider, (void**)&sp); 803 ok(hr == S_OK, "got 0x%08x\n", hr); 804 805 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb); 806 ok(hr == S_OK, "got 0x%08x\n", hr); 807 808 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellBrowser, (void**)&sb2); 809 ok(hr == S_OK, "got 0x%08x\n", hr); 810 ok(sb == sb2, "got %p, %p\n", sb, sb2); 811 812 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IOleWindow, (void**)&unk); 813 ok(hr == S_OK, "got 0x%08x\n", hr); 814 IUnknown_Release(unk); 815 816 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IExplorerBrowser, (void**)&unk); 817 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 818 819 hr = IShellBrowser_QueryInterface(sb, &IID_IExplorerBrowser, (void**)&unk); 820 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 821 822 hr = IShellBrowser_QueryInterface(sb, &IID_IWebBrowser2, (void**)&unk); 823 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 824 825 hr = IShellBrowser_QueryInterface(sb, &IID_IDispatch, (void**)&unk); 826 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 827 828 hr = IShellBrowser_QueryActiveShellView(sb, &sv); 829 ok(hr == S_OK, "got 0x%08x\n", hr); 830 IShellView_Release(sv); 831 832 IShellBrowser_Release(sb2); 833 IShellBrowser_Release(sb); 834 835 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IUnknown, (void**)&unk); 836 ok(hr == S_OK, "got 0x%08x\n", hr); 837 838 hr = IUnknown_QueryInterface(unk, &IID_IShellBrowser, (void**)&sb2); 839 ok(hr == S_OK, "got 0x%08x\n", hr); 840 IShellBrowser_Release(sb2); 841 IUnknown_Release(unk); 842 843 hr = IServiceProvider_QueryService(sp, &SID_STopLevelBrowser, &IID_IShellView, (void**)&sv); 844 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr); 845 846 IServiceProvider_Release(sp); 847 IDispatch_Release(disp); 848 } 849 850 disp = (void*)0xdeadbeef; 851 ret = 0xdead; 852 VariantInit(&v); 853 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v, SWC_DESKTOP, &ret, 0, &disp); 854 ok(hr == S_OK || broken(hr == S_FALSE) /* winxp */, "got 0x%08x\n", hr); 855 ok(disp == NULL, "got %p\n", disp); 856 ok(ret != HandleToUlong(hwnd), "got %d\n", ret); 857 858 disp = (void*)0xdeadbeef; 859 ret = 0xdead; 860 V_VT(&v) = VT_I4; 861 V_I4(&v) = cookie; 862 VariantInit(&v2); 863 hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_BROWSER, &ret, SWFO_COOKIEPASSED, &disp); 864 todo_wine 865 ok(hr == S_FALSE, "got 0x%08x\n", hr); 866 ok(disp == NULL, "got %p\n", disp); 867 ok(ret == 0, "got %d\n", ret); 868 869 hr = IShellWindows_Revoke(shellwindows, cookie); 870 todo_wine 871 ok(hr == S_OK, "got 0x%08x\n", hr); 872 DestroyWindow(hwnd); 873 IShellWindows_Release(shellwindows); 874 } 875 876 static void test_ParseName(void) 877 { 878 static const WCHAR cadabraW[] = {'c','a','d','a','b','r','a',0}; 879 WCHAR pathW[MAX_PATH]; 880 IShellDispatch *sd; 881 FolderItem *item; 882 Folder *folder; 883 HRESULT hr; 884 VARIANT v; 885 BSTR str; 886 887 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 888 &IID_IShellDispatch, (void**)&sd); 889 ok(hr == S_OK, "got 0x%08x\n", hr); 890 891 GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW); 892 V_VT(&v) = VT_BSTR; 893 V_BSTR(&v) = SysAllocString(pathW); 894 hr = IShellDispatch_NameSpace(sd, v, &folder); 895 ok(hr == S_OK, "got 0x%08x\n", hr); 896 VariantClear(&v); 897 898 item = (void*)0xdeadbeef; 899 hr = Folder_ParseName(folder, NULL, &item); 900 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr); 901 ok(item == NULL, "got %p\n", item); 902 903 /* empty name */ 904 str = SysAllocStringLen(NULL, 0); 905 item = (void*)0xdeadbeef; 906 hr = Folder_ParseName(folder, str, &item); 907 ok(hr == S_FALSE || broken(hr == E_INVALIDARG) /* win2k */, "got 0x%08x\n", hr); 908 ok(item == NULL, "got %p\n", item); 909 SysFreeString(str); 910 911 /* path doesn't exist */ 912 str = SysAllocString(cadabraW); 913 item = (void*)0xdeadbeef; 914 hr = Folder_ParseName(folder, str, &item); 915 ok(hr == S_FALSE || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* win2k */, 916 "got 0x%08x\n", hr); 917 ok(item == NULL, "got %p\n", item); 918 SysFreeString(str); 919 920 lstrcatW(pathW, cadabraW); 921 CreateDirectoryW(pathW, NULL); 922 923 str = SysAllocString(cadabraW); 924 item = NULL; 925 hr = Folder_ParseName(folder, str, &item); 926 ok(hr == S_OK, "got 0x%08x\n", hr); 927 ok(item != NULL, "got %p\n", item); 928 SysFreeString(str); 929 930 hr = FolderItem_get_Path(item, &str); 931 ok(hr == S_OK, "got 0x%08x\n", hr); 932 ok(str[0] != 0, "path %s\n", wine_dbgstr_w(str)); 933 SysFreeString(str); 934 935 RemoveDirectoryW(pathW); 936 FolderItem_Release(item); 937 Folder_Release(folder); 938 IShellDispatch_Release(sd); 939 } 940 941 static void test_Verbs(void) 942 { 943 FolderItemVerbs *verbs; 944 WCHAR pathW[MAX_PATH]; 945 FolderItemVerb *verb; 946 IShellDispatch *sd; 947 FolderItem *item; 948 Folder2 *folder2; 949 Folder *folder; 950 HRESULT hr; 951 LONG count, i; 952 VARIANT v; 953 BSTR str; 954 955 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 956 &IID_IShellDispatch, (void**)&sd); 957 ok(hr == S_OK, "got 0x%08x\n", hr); 958 959 GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW); 960 V_VT(&v) = VT_BSTR; 961 V_BSTR(&v) = SysAllocString(pathW); 962 hr = IShellDispatch_NameSpace(sd, v, &folder); 963 ok(hr == S_OK, "got 0x%08x\n", hr); 964 VariantClear(&v); 965 966 hr = Folder_QueryInterface(folder, &IID_Folder2, (void**)&folder2); 967 ok(hr == S_OK, "got 0x%08x\n", hr); 968 Folder_Release(folder); 969 970 hr = Folder2_get_Self(folder2, &item); 971 ok(hr == S_OK, "got 0x%08x\n", hr); 972 Folder2_Release(folder2); 973 974 if (0) { /* crashes on some systems */ 975 hr = FolderItem_Verbs(item, NULL); 976 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 977 } 978 hr = FolderItem_Verbs(item, &verbs); 979 ok(hr == S_OK, "got 0x%08x\n", hr); 980 981 if (0) { /* crashes on winxp/win2k3 */ 982 hr = FolderItemVerbs_get_Count(verbs, NULL); 983 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 984 } 985 count = 0; 986 hr = FolderItemVerbs_get_Count(verbs, &count); 987 ok(hr == S_OK, "got 0x%08x\n", hr); 988 ok(count > 0, "got count %d\n", count); 989 990 if (0) { /* crashes on winxp/win2k3 */ 991 V_VT(&v) = VT_I4; 992 V_I4(&v) = 0; 993 hr = FolderItemVerbs_Item(verbs, v, NULL); 994 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 995 } 996 /* there's always one item more, so you can access [0,count], 997 instead of actual [0,count) */ 998 for (i = 0; i <= count; i++) { 999 V_VT(&v) = VT_I4; 1000 V_I4(&v) = i; 1001 hr = FolderItemVerbs_Item(verbs, v, &verb); 1002 ok(hr == S_OK, "got 0x%08x\n", hr); 1003 hr = FolderItemVerb_get_Name(verb, &str); 1004 ok(hr == S_OK, "got 0x%08x\n", hr); 1005 ok(str != NULL, "%d: name %s\n", i, wine_dbgstr_w(str)); 1006 if (i == count) 1007 ok(str[0] == 0, "%d: got teminating item %s\n", i, wine_dbgstr_w(str)); 1008 1009 SysFreeString(str); 1010 FolderItemVerb_Release(verb); 1011 } 1012 1013 V_VT(&v) = VT_I4; 1014 V_I4(&v) = count+1; 1015 verb = NULL; 1016 hr = FolderItemVerbs_Item(verbs, v, &verb); 1017 ok(hr == S_OK, "got 0x%08x\n", hr); 1018 ok(verb == NULL, "got %p\n", verb); 1019 1020 FolderItemVerbs_Release(verbs); 1021 FolderItem_Release(item); 1022 IShellDispatch_Release(sd); 1023 } 1024 1025 static void test_ShellExecute(void) 1026 { 1027 HRESULT hr; 1028 IShellDispatch2 *sd; 1029 BSTR name; 1030 VARIANT args, dir, op, show; 1031 1032 static const WCHAR regW[] = {'r','e','g',0}; 1033 1034 hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, 1035 &IID_IShellDispatch2, (void**)&sd); 1036 if (hr != S_OK) 1037 { 1038 win_skip("IShellDispatch2 not supported\n"); 1039 return; 1040 } 1041 1042 VariantInit(&args); 1043 VariantInit(&dir); 1044 VariantInit(&op); 1045 VariantInit(&show); 1046 1047 V_VT(&show) = VT_I4; 1048 V_I4(&show) = 0; 1049 1050 name = SysAllocString(regW); 1051 1052 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show); 1053 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr); 1054 1055 /* test invalid value for show */ 1056 V_VT(&show) = VT_BSTR; 1057 V_BSTR(&show) = name; 1058 1059 hr = IShellDispatch2_ShellExecute(sd, name, args, dir, op, show); 1060 ok(hr == S_OK, "ShellExecute failed: %08x\n", hr); 1061 1062 SysFreeString(name); 1063 } 1064 1065 START_TEST(shelldispatch) 1066 { 1067 HRESULT r; 1068 1069 r = CoInitialize(NULL); 1070 ok(SUCCEEDED(r), "CoInitialize failed: %08x\n", r); 1071 if (FAILED(r)) 1072 return; 1073 1074 init_function_pointers(); 1075 test_namespace(); 1076 test_items(); 1077 test_service(); 1078 test_ShellFolderViewDual(); 1079 test_ShellWindows(); 1080 test_ParseName(); 1081 test_Verbs(); 1082 test_ShellExecute(); 1083 1084 CoUninitialize(); 1085 } 1086