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