1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: GPLv2+ - See COPYING in the top level directory 4 * PURPOSE: Test for ACListISF objects 5 * PROGRAMMER: Mark Jansen 6 */ 7 8 #define _UNICODE 9 #define UNICODE 10 #include <apitest.h> 11 #include <shlobj.h> 12 #include <atlbase.h> 13 #include <tchar.h> // 14 #include <atlcom.h> // These 3 includes only exist here to make gcc happy about (unused) templates.. 15 #include <atlwin.h> // 16 17 // Yes, gcc at it again, let's validate everything found inside unused templates! 18 ULONG DbgPrint(PCH Format,...); 19 20 #include <stdio.h> 21 #include <shellutils.h> 22 #include <shlwapi.h> 23 #include <strsafe.h> 24 25 static bool g_ShowHidden; 26 static DWORD g_WinVersion; 27 #define WINVER_VISTA 0x0600 28 29 30 #define ok_hr(status, expected) ok_hex(status, expected) 31 32 // We do not want our results to originate from the helper functions, so have them originate from the calls to them 33 #define test_at_end (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_at_end_imp 34 #define test_ExpectDrives (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_ExpectDrives_imp 35 #define test_ExpectFolders (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_ExpectFolders_imp 36 #define winetest_ok_hr(expression, expected) \ 37 do { \ 38 int _value = (expression); \ 39 winetest_ok(_value == (expected), "Wrong value for '%s', expected: " #expected " (0x%x), got: 0x%x\n", \ 40 #expression, (int)(expected), _value); \ 41 } while (0) 42 43 44 45 46 static void test_at_end_imp(CComPtr<IEnumString>& EnumStr) 47 { 48 CComHeapPtr<OLECHAR> Result; 49 ULONG Fetched = 12345; 50 HRESULT hr = EnumStr->Next(1, &Result, &Fetched); 51 winetest_ok(hr == S_FALSE, "Expected hr to be S_FALSE, was 0x%lx\n", hr); 52 winetest_ok(Fetched == 0u, "Expected Fetched to be 0, was: %lu\n", Fetched); 53 if (Fetched == 1u) 54 winetest_ok(0, "Expected there not to be a result, got: %s\n", wine_dbgstr_w(Result)); 55 } 56 57 static bool GetDisplayname(CComPtr<IShellFolder>& spDrives, CComHeapPtr<ITEMIDLIST>& pidl, CComHeapPtr<WCHAR>& DisplayName) 58 { 59 STRRET StrRet; 60 HRESULT hr; 61 winetest_ok_hr(hr = spDrives->GetDisplayNameOf(pidl, SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR, &StrRet), S_OK); 62 if (!SUCCEEDED(hr)) 63 return false; 64 65 winetest_ok_hr(hr = StrRetToStrW(&StrRet, NULL, &DisplayName), S_OK); 66 if (!SUCCEEDED(hr)) 67 return false; 68 return true; 69 } 70 71 enum ExpectOptions 72 { 73 None = 0, 74 IgnoreRoot = 1, 75 CheckLast = 2, 76 IgnoreHidden = 4, 77 IgnoreFiles = 8, 78 }; 79 80 // wtf c++ 81 ExpectOptions operator | (const ExpectOptions& left, const ExpectOptions& right) 82 { 83 return static_cast<ExpectOptions>(static_cast<int>(left) | static_cast<int>(right)); 84 } 85 86 87 static void 88 test_ExpectFolders_imp(CComPtr<IEnumString>& EnumStr, LPITEMIDLIST pidlTarget, const WCHAR* Root, ExpectOptions options) 89 { 90 CComPtr<IShellFolder> spDesktop; 91 HRESULT hr = SHGetDesktopFolder(&spDesktop); 92 93 CComPtr<IShellFolder> spTarget; 94 if (pidlTarget) 95 { 96 winetest_ok_hr(hr = spDesktop->BindToObject(pidlTarget, NULL, IID_PPV_ARG(IShellFolder, &spTarget)), S_OK); 97 if (!SUCCEEDED(hr)) 98 return; 99 } 100 else 101 { 102 spTarget = spDesktop; 103 } 104 105 SHCONTF EnumFlags = SHCONTF_FOLDERS | SHCONTF_INIT_ON_FIRST_NEXT; 106 if (g_ShowHidden && !(options & IgnoreHidden)) 107 EnumFlags |= SHCONTF_INCLUDEHIDDEN; 108 if (!(options & IgnoreFiles)) 109 EnumFlags |= SHCONTF_NONFOLDERS; 110 111 CComPtr<IEnumIDList> spEnumIDList; 112 winetest_ok_hr(hr = spTarget->EnumObjects(NULL, EnumFlags, &spEnumIDList), S_OK); 113 if (!SUCCEEDED(hr)) 114 return; 115 116 WCHAR Buffer[512]; 117 CComHeapPtr<ITEMIDLIST> pidl; 118 INT Count = 0; 119 while (spEnumIDList->Next(1, &pidl, NULL) == S_OK) 120 { 121 CComHeapPtr<WCHAR> DisplayName; 122 if (!GetDisplayname(spTarget, pidl, DisplayName)) 123 break; 124 125 CComHeapPtr<OLECHAR> Result; 126 ULONG Fetched; 127 hr = EnumStr->Next(1, &Result, &Fetched); 128 winetest_ok_hr(hr, S_OK); 129 130 131 if (hr != S_OK) 132 break; 133 134 135 StringCchPrintfW(Buffer, _ARRAYSIZE(Buffer), L"%s%s", (options & IgnoreRoot) ? L"" : Root, (WCHAR*)DisplayName); 136 137 winetest_ok(!wcscmp(Buffer, Result), "Expected %s, got %s\n", wine_dbgstr_w(Buffer), wine_dbgstr_w(Result)); 138 139 pidl.Free(); 140 Count++; 141 } 142 if (options & CheckLast) 143 { 144 test_at_end_imp(EnumStr); 145 } 146 } 147 148 static void 149 test_ExpectDrives_imp(CComPtr<IEnumString>& EnumStr, CComHeapPtr<ITEMIDLIST>& pidlTarget) 150 { 151 test_ExpectFolders_imp(EnumStr, pidlTarget, NULL, IgnoreRoot | CheckLast); 152 } 153 154 static void 155 test_ACListISF_NONE() 156 { 157 CComPtr<IEnumString> EnumStr; 158 HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); 159 ok_hr(hr, S_OK); 160 if (!SUCCEEDED(hr)) 161 return; 162 163 CComPtr<IACList2> ACList; 164 ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); 165 if (!SUCCEEDED(hr)) 166 return; 167 168 ok_hr(hr = ACList->SetOptions(ACLO_NONE), S_OK); 169 test_at_end(EnumStr); 170 171 172 WCHAR Buffer[MAX_PATH]; 173 GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer)); 174 Buffer[3] = '\0'; 175 176 CComHeapPtr<ITEMIDLIST> pidlDiskRoot; 177 ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK); 178 if (!SUCCEEDED(hr)) 179 return; 180 181 ok_hr(hr = ACList->Expand(Buffer), S_OK); 182 test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast | IgnoreHidden); 183 184 ok_hr(hr = EnumStr->Reset(), S_OK); 185 ok_hr(hr = ACList->Expand(Buffer), S_OK); 186 ok_hr(hr = ACList->SetOptions(ACLO_NONE), S_OK); 187 test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast); 188 } 189 190 static void 191 test_ACListISF_CURRENTDIR() 192 { 193 CComPtr<IEnumString> EnumStr; 194 HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); 195 ok_hr(hr, S_OK); 196 if (!SUCCEEDED(hr)) 197 return; 198 199 CComPtr<IACList2> ACList; 200 ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); 201 if (!SUCCEEDED(hr)) 202 return; 203 204 CComPtr<ICurrentWorkingDirectory> CurrentWorkingDir; 205 ok_hr(hr = EnumStr->QueryInterface(IID_ICurrentWorkingDirectory, (void**)&CurrentWorkingDir), S_OK); 206 if (!SUCCEEDED(hr)) 207 return; 208 209 ok_hr(hr = ACList->SetOptions(ACLO_CURRENTDIR), S_OK); 210 test_at_end(EnumStr); 211 212 213 WCHAR Buffer[MAX_PATH] = { 1, 1, 1, 1, 1, 0 }, Buffer2[MAX_PATH]; 214 if (g_WinVersion < WINVER_VISTA) 215 ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_NOTIMPL); 216 else 217 ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_UNEXPECTED); 218 ok(!wcscmp(L"\x1\x1\x1\x1\x1", Buffer), "Expected %s, got %s\n", wine_dbgstr_w(L"\x1\x1\x1\x1\x1"), wine_dbgstr_w(Buffer)); 219 220 GetSystemWindowsDirectoryW(Buffer2, _ARRAYSIZE(Buffer2)); 221 // Windows 2k3 does not parse it without the trailing '\\' 222 Buffer2[3] = '\0'; 223 CComHeapPtr<ITEMIDLIST> pidlDiskRoot; 224 ok_hr(hr = SHParseDisplayName(Buffer2, NULL, &pidlDiskRoot, NULL, NULL), S_OK); 225 if (!SUCCEEDED(hr)) 226 return; 227 228 ok_hr(hr = CurrentWorkingDir->SetDirectory(Buffer2), S_OK); 229 test_at_end(EnumStr); 230 231 Buffer[0] = '\0'; 232 if (g_WinVersion < WINVER_VISTA) 233 { 234 ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_NOTIMPL); 235 } 236 else 237 { 238 ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), S_OK); 239 ok(!wcscmp(Buffer2, Buffer), "Expected %s, got %s\n", wine_dbgstr_w(Buffer2), wine_dbgstr_w(Buffer)); 240 } 241 242 Buffer2[2] = '\0'; 243 ok_hr(hr = CurrentWorkingDir->SetDirectory(Buffer2), S_OK); 244 test_at_end(EnumStr); 245 246 Buffer[0] = '\0'; 247 Buffer2[2] = '\\'; 248 if (g_WinVersion < WINVER_VISTA) 249 { 250 ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_NOTIMPL); 251 } 252 else 253 { 254 ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), S_OK); 255 ok(!wcscmp(Buffer2, Buffer), "Expected %s, got %s\n", wine_dbgstr_w(Buffer2), wine_dbgstr_w(Buffer)); 256 } 257 258 ok_hr(hr = ACList->Expand(Buffer2), S_OK); 259 // The first set of results are absolute paths, without hidden files?! 260 test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer2, IgnoreHidden); 261 test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer2, IgnoreHidden | IgnoreRoot | CheckLast); 262 } 263 264 static void 265 test_ACListISF_MYCOMPUTER() 266 { 267 CComPtr<IACList2> ACList; 268 HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IACList2, &ACList)); 269 ok_hr(hr, S_OK); 270 if (!SUCCEEDED(hr)) 271 return; 272 273 // Check the default 274 DWORD CurrentOption = 0xdeadbeef; 275 ok_hr(ACList->GetOptions(&CurrentOption), S_OK); 276 ok(CurrentOption == (ACLO_CURRENTDIR|ACLO_MYCOMPUTER), "Expected the default to be %x, was %lx\n", 277 (ACLO_CURRENTDIR|ACLO_MYCOMPUTER), CurrentOption); 278 279 280 CComPtr<IEnumString> EnumStr; 281 ok_hr(hr = ACList->QueryInterface(IID_IEnumString, (void**)&EnumStr), S_OK); 282 if (!SUCCEEDED(hr)) 283 return; 284 285 CComPtr<IPersistFolder> PersistFolder; 286 ok_hr(hr = EnumStr->QueryInterface(IID_IPersistFolder, (void**)&PersistFolder), S_OK); 287 if (!SUCCEEDED(hr)) 288 return; 289 290 CComHeapPtr<ITEMIDLIST> pidlMyComputer; 291 ok_hr(hr = SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlMyComputer), S_OK); 292 if (!SUCCEEDED(hr)) 293 return; 294 295 296 hr = EnumStr->Reset(); 297 if (g_WinVersion < WINVER_VISTA) 298 ok_hr(hr, S_FALSE); 299 else 300 ok_hr(hr, S_OK); 301 test_ExpectDrives(EnumStr, pidlMyComputer); 302 303 ok_hr(hr = ACList->SetOptions(ACLO_MYCOMPUTER), S_OK); 304 ok_hr(EnumStr->Reset(), S_OK); 305 test_ExpectDrives(EnumStr, pidlMyComputer); 306 307 WCHAR Buffer[MAX_PATH]; 308 GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer)); 309 // Windows 2k3 does not parse it without the trailing '\\' 310 Buffer[3] = '\0'; 311 CComHeapPtr<ITEMIDLIST> pidlDiskRoot; 312 ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK); 313 if (!SUCCEEDED(hr)) 314 return; 315 Buffer[2] = '\0'; 316 317 ok_hr(hr = ACList->Expand(Buffer), S_OK); 318 test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, None); 319 test_ExpectDrives(EnumStr, pidlMyComputer); 320 321 ok_hr(hr = ACList->Expand(Buffer), S_OK); 322 ok_hr(EnumStr->Reset(), S_OK); 323 // Pre vista does not remove the expanded data from the enumeration, it changes it to relative paths??? 324 if (g_WinVersion < WINVER_VISTA) 325 test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, IgnoreRoot); 326 test_ExpectDrives(EnumStr, pidlMyComputer); 327 328 ok_hr(EnumStr->Reset(), S_OK); 329 ok_hr(hr = ACList->Expand(Buffer), S_OK); 330 test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, None); 331 test_ExpectDrives(EnumStr, pidlMyComputer); 332 } 333 334 static void 335 test_ACListISF_DESKTOP() 336 { 337 CComPtr<IEnumString> EnumStr; 338 HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); 339 ok_hr(hr, S_OK); 340 if (!SUCCEEDED(hr)) 341 return; 342 343 CComPtr<IACList2> ACList; 344 ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); 345 if (!SUCCEEDED(hr)) 346 return; 347 348 ok_hr(hr = ACList->SetOptions(ACLO_DESKTOP), S_OK); 349 test_ExpectFolders(EnumStr, NULL, NULL, IgnoreRoot | CheckLast | IgnoreHidden); 350 } 351 352 static void 353 test_ACListISF_FAVORITES() 354 { 355 CComPtr<IEnumString> EnumStr; 356 HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); 357 ok_hr(hr, S_OK); 358 if (!SUCCEEDED(hr)) 359 return; 360 361 CComPtr<IACList2> ACList; 362 ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); 363 if (!SUCCEEDED(hr)) 364 return; 365 366 CComHeapPtr<ITEMIDLIST> pidlFavorites; 367 ok_hr(hr = SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidlFavorites), S_OK); 368 if (!SUCCEEDED(hr)) 369 return; 370 371 ok_hr(hr = ACList->SetOptions(ACLO_FAVORITES), S_OK); 372 test_ExpectFolders(EnumStr, pidlFavorites, NULL, IgnoreRoot | CheckLast | IgnoreHidden); 373 } 374 375 static void 376 test_ACListISF_FILESYSONLY() 377 { 378 CComPtr<IEnumString> EnumStr; 379 HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); 380 ok_hr(hr, S_OK); 381 if (!SUCCEEDED(hr)) 382 return; 383 384 CComPtr<IACList2> ACList; 385 ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); 386 if (!SUCCEEDED(hr)) 387 return; 388 389 WCHAR Buffer[MAX_PATH]; 390 GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer)); 391 // Windows 2k3 does not parse it without the trailing '\\' 392 Buffer[3] = '\0'; 393 CComHeapPtr<ITEMIDLIST> pidlDiskRoot; 394 ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK); 395 if (!SUCCEEDED(hr)) 396 return; 397 398 ok_hr(hr = ACList->SetOptions(ACLO_FILESYSONLY), S_OK); 399 test_at_end(EnumStr); 400 401 ok_hr(hr = ACList->Expand(Buffer), S_OK); 402 test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast | IgnoreHidden); 403 } 404 405 static void 406 test_ACListISF_FILESYSDIRS() 407 { 408 CComPtr<IEnumString> EnumStr; 409 HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); 410 ok_hr(hr, S_OK); 411 if (!SUCCEEDED(hr)) 412 return; 413 414 CComPtr<IACList2> ACList; 415 ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); 416 if (!SUCCEEDED(hr)) 417 return; 418 419 WCHAR Buffer[MAX_PATH]; 420 GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer)); 421 // Windows 2k3 does not parse it without the trailing '\\' 422 Buffer[3] = '\0'; 423 CComHeapPtr<ITEMIDLIST> pidlDiskRoot; 424 ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK); 425 if (!SUCCEEDED(hr)) 426 return; 427 428 ok_hr(hr = ACList->SetOptions(ACLO_FILESYSDIRS), S_OK); 429 test_at_end(EnumStr); 430 431 ok_hr(hr = ACList->Expand(Buffer), S_OK); 432 test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast | IgnoreFiles | IgnoreHidden); 433 } 434 435 static void GetEnvStatus() 436 { 437 RTL_OSVERSIONINFOEXW rtlinfo = {0}; 438 void (__stdcall* pRtlGetVersion)(RTL_OSVERSIONINFOEXW*); 439 pRtlGetVersion = (void (__stdcall*)(RTL_OSVERSIONINFOEXW*))GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion"); 440 441 rtlinfo.dwOSVersionInfoSize = sizeof(rtlinfo); 442 pRtlGetVersion(&rtlinfo); 443 g_WinVersion = (rtlinfo.dwMajorVersion << 8) | rtlinfo.dwMinorVersion; 444 445 SHELLFLAGSTATE sfs = {0}; 446 SHGetSettings(&sfs, SSF_SHOWALLOBJECTS); 447 g_ShowHidden = !!sfs.fShowAllObjects; 448 trace("Show hidden folders: %s\n", g_ShowHidden ? "yes" : "no"); 449 } 450 451 struct CCoInit 452 { 453 CCoInit() { hres = CoInitialize(NULL); } 454 ~CCoInit() { if (SUCCEEDED(hres)) { CoUninitialize(); } } 455 HRESULT hres; 456 }; 457 458 START_TEST(ACListISF) 459 { 460 GetEnvStatus(); 461 CCoInit init; 462 ok_hr(init.hres, S_OK); 463 if (!SUCCEEDED(init.hres)) 464 return; 465 466 test_ACListISF_NONE(); 467 test_ACListISF_CURRENTDIR(); 468 test_ACListISF_MYCOMPUTER(); 469 test_ACListISF_DESKTOP(); 470 test_ACListISF_FAVORITES(); 471 test_ACListISF_FILESYSONLY(); 472 test_ACListISF_FILESYSDIRS(); 473 } 474