Reactos
at master 483 lines 19 kB view raw
1/* 2 * PROJECT: ReactOS api tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Test for CShellLink 5 * PROGRAMMER: Andreas Maier 6 */ 7 8#include "shelltest.h" 9 10#define NDEBUG 11#include <debug.h> 12#include <stdio.h> 13#include <shellutils.h> 14 15/* Test IShellLink::SetPath with environment-variables, existing, non-existing, ...*/ 16typedef struct 17{ 18 PCWSTR pathIn; 19 HRESULT hrSetPath; 20 21 /* Test 1 - hrGetPathX = IShellLink::GetPath(pathOutX, ... , flagsX); */ 22 PCWSTR pathOut1; 23 DWORD flags1; 24 HRESULT hrGetPath1; 25 BOOL expandPathOut1; 26 27 /* Test 2 */ 28 PCWSTR pathOut2; 29 DWORD flags2; 30 HRESULT hrGetPath2; 31 BOOL expandPathOut2; 32} TEST_SHELL_LINK_DEF; 33 34static TEST_SHELL_LINK_DEF linkTestList_WS03[] = 35{ 36 { 37 L"%comspec%", S_OK, 38 L"%comspec%", SLGP_SHORTPATH, S_OK, TRUE, 39 L"%comspec%", SLGP_RAWPATH, S_OK, FALSE 40 }, 41 { 42 L"%anyvar%", E_INVALIDARG, 43 L"", SLGP_SHORTPATH, S_FALSE, FALSE, 44 L"", SLGP_RAWPATH, S_FALSE, FALSE 45 }, 46 { 47 L"%anyvar%%comspec%", S_OK, 48 L"c:\\%anyvar%%comspec%", SLGP_SHORTPATH, S_OK, TRUE, 49 L"%anyvar%%comspec%", SLGP_RAWPATH, S_OK, FALSE 50 }, 51 { 52 L"%temp%", S_OK, 53 L"%temp%", SLGP_SHORTPATH, S_OK, TRUE, 54 L"%temp%", SLGP_RAWPATH, S_OK, FALSE 55 }, 56 { 57 L"%shell%", S_OK, 58 L"%systemroot%\\system32\\%shell%", SLGP_SHORTPATH, S_OK, TRUE, 59 L"%shell%", SLGP_RAWPATH, S_OK, FALSE 60 }, 61 { 62 L"u:\\anypath\\%anyvar%", S_OK, 63 L"u:\\anypath\\%anyvar%", SLGP_SHORTPATH, S_OK, TRUE, 64 L"u:\\anypath\\%anyvar%", SLGP_RAWPATH, S_OK, FALSE 65 }, 66 { 67 L"c:\\temp", S_OK, 68 L"c:\\temp", SLGP_SHORTPATH, S_OK, FALSE, 69 L"c:\\temp", SLGP_RAWPATH, S_OK, FALSE 70 }, 71 { 72 L"cmd.exe", S_OK, 73 L"%comspec%", SLGP_SHORTPATH, S_OK, TRUE, 74 L"%comspec%", SLGP_RAWPATH, S_OK, TRUE 75 }, 76 { 77 L"%systemroot%\\non-existent-file", S_OK, 78 L"%systemroot%\\non-existent-file", SLGP_SHORTPATH, S_OK, TRUE, 79 L"%systemroot%\\non-existent-file", SLGP_RAWPATH, S_OK, FALSE 80 }, 81 { 82 L"c:\\non-existent-path\\non-existent-file", S_OK, 83 L"c:\\non-existent-path\\non-existent-file", SLGP_SHORTPATH, S_OK, FALSE, 84 L"c:\\non-existent-path\\non-existent-file", SLGP_RAWPATH, S_OK, FALSE 85 }, 86 { 87 L"non-existent-file", E_INVALIDARG, 88 L"", SLGP_SHORTPATH, S_FALSE, FALSE, 89 L"", SLGP_RAWPATH, S_FALSE, FALSE 90 }, 91}; 92 93static TEST_SHELL_LINK_DEF linkTestList_Vista[] = 94{ 95 { 96 L"%comspec%", S_OK, 97 L"%comspec%", SLGP_SHORTPATH, S_OK, TRUE, 98 L"%comspec%", SLGP_RAWPATH, S_OK, FALSE 99 }, 100 { 101 L"%anyvar%", S_OK, 102 L"%USERPROFILE%\\Desktop\\%anyvar%", SLGP_SHORTPATH, S_OK, TRUE, 103 L"%USERPROFILE%\\Desktop\\%anyvar%", SLGP_RAWPATH, S_OK, TRUE 104 }, 105 { 106 L"%anyvar%%comspec%", E_INVALIDARG, 107 L"", SLGP_SHORTPATH, S_FALSE, TRUE, 108 L"%anyvar%%comspec%", SLGP_RAWPATH, S_OK, FALSE 109 }, 110 { 111 L"%temp%", S_OK, 112 L"%temp%", SLGP_SHORTPATH, S_OK, TRUE, 113 L"%temp%", SLGP_RAWPATH, S_OK, FALSE 114 }, 115 { 116 L"%shell%", S_OK, 117 L"%systemroot%\\system32\\%shell%", SLGP_SHORTPATH, S_OK, TRUE, 118 L"%shell%", SLGP_RAWPATH, S_OK, FALSE 119 }, 120 { 121 L"u:\\anypath\\%anyvar%", S_OK, 122 L"u:\\anypath\\%anyvar%", SLGP_SHORTPATH, S_OK, TRUE, 123 L"u:\\anypath\\%anyvar%", SLGP_RAWPATH, S_OK, FALSE 124 }, 125 { 126 L"c:\\temp", S_OK, 127 L"c:\\temp", SLGP_SHORTPATH, S_OK, FALSE, 128 L"c:\\temp", SLGP_RAWPATH, S_OK, FALSE 129 }, 130 { 131 L"cmd.exe", S_OK, 132 L"%comspec%", SLGP_SHORTPATH, S_OK, TRUE, 133 L"%comspec%", SLGP_RAWPATH, S_OK, TRUE 134 }, 135 { 136 L"%systemroot%\\non-existent-file", S_OK, 137 L"%systemroot%\\non-existent-file", SLGP_SHORTPATH, S_OK, TRUE, 138 L"%systemroot%\\non-existent-file", SLGP_RAWPATH, S_OK, FALSE 139 }, 140 { 141 L"c:\\non-existent-path\\non-existent-file", S_OK, 142 L"c:\\non-existent-path\\non-existent-file", SLGP_SHORTPATH, S_OK, FALSE, 143 L"c:\\non-existent-path\\non-existent-file", SLGP_RAWPATH, S_OK, FALSE 144 }, 145 { 146 L"non-existent-file", S_OK, 147 L"%USERPROFILE%\\Desktop\\non-existent-file", SLGP_SHORTPATH, S_OK, TRUE, 148 L"%USERPROFILE%\\Desktop\\non-existent-file", SLGP_RAWPATH, S_OK, TRUE 149 }, 150}; 151 152static 153VOID 154test_checklinkpath(UINT i, TEST_SHELL_LINK_DEF* testDef) 155{ 156static WCHAR evVar[MAX_PATH]; 157 158 HRESULT hr, expectedHr; 159 WCHAR wPathOut[MAX_PATH]; 160 BOOL expandPathOut; 161 PCWSTR expectedPathOut; 162 CComPtr<IShellLinkW> psl; 163 UINT i1; 164 DWORD flags; 165 166 hr = CoCreateInstance(CLSID_ShellLink, 167 NULL, 168 CLSCTX_INPROC_SERVER, 169 IID_PPV_ARG(IShellLinkW, &psl)); 170 ok(hr == S_OK, "CoCreateInstance, hr = 0x%lx\n", hr); 171 if (FAILED(hr)) 172 { 173 skip("Could not instantiate CShellLink\n"); 174 return; 175 } 176 177 hr = psl->SetPath(testDef->pathIn); 178 ok(hr == testDef->hrSetPath, "IShellLink::SetPath(%d), got hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrSetPath); 179 180 expectedPathOut = NULL; 181 for (i1 = 0; i1 <= 1; i1++) 182 { 183 if (i1 == 0) /* Usually SLGP_SHORTPATH */ 184 { 185 flags = testDef->flags1; 186 expandPathOut = testDef->expandPathOut1; 187 expectedPathOut = testDef->pathOut1; 188 expectedHr = testDef->hrGetPath1; 189 } 190 else // if (i1 == 1) /* Usually SLGP_RAWPATH */ 191 { 192 flags = testDef->flags2; 193 expandPathOut = testDef->expandPathOut2; 194 expectedPathOut = testDef->pathOut2; 195 expectedHr = testDef->hrGetPath2; 196 } 197 198 /* Patch some variables */ 199 if (expandPathOut) 200 { 201 ExpandEnvironmentStringsW(expectedPathOut, evVar, _countof(evVar)); 202 DPRINT("** %S **\n",evVar); 203 expectedPathOut = evVar; 204 } 205 206 hr = psl->GetPath(wPathOut, _countof(wPathOut), NULL, flags); 207 ok(hr == expectedHr, 208 "IShellLink::GetPath(%d), flags 0x%lx, got hr = 0x%lx, expected 0x%lx\n", 209 i, flags, hr, expectedHr); 210 ok(_wcsicmp(wPathOut, expectedPathOut) == 0, 211 "IShellLink::GetPath(%d), flags 0x%lx, in %S, got %S, expected %S\n", 212 i, flags, testDef->pathIn, wPathOut, expectedPathOut); 213 } 214} 215 216static 217VOID 218TestShellLink(void) 219{ 220 UINT i, TestListCnt; 221 TEST_SHELL_LINK_DEF* Test; 222 223 /* Needed for test */ 224 SetEnvironmentVariableW(L"shell", L"cmd.exe"); 225 226 if (GetNTVersion() <= _WIN32_WINNT_WS03) 227 { 228 Test = linkTestList_WS03; 229 TestListCnt = _countof(linkTestList_WS03); 230 } 231 else 232 { 233 Test = linkTestList_Vista; 234 TestListCnt = _countof(linkTestList_Vista); 235 } 236 237 for (i = 0; i < TestListCnt; ++i) 238 { 239 DPRINT("IShellLink-Test(%d): %S\n", i, Test[i].pathIn); 240 test_checklinkpath(i, &Test[i]); 241 } 242 243 SetEnvironmentVariableW(L"shell",NULL); 244} 245 246static 247VOID 248TestDescription(void) 249{ 250 HRESULT hr; 251 CComPtr<IShellLinkW> psl; 252 WCHAR buffer[64]; 253 PCWSTR testDescription = L"This is a test description"; 254 255 /* Test SetDescription */ 256 hr = CoCreateInstance(CLSID_ShellLink, 257 NULL, 258 CLSCTX_INPROC_SERVER, 259 IID_PPV_ARG(IShellLinkW, &psl)); 260 ok(hr == S_OK, "CoCreateInstance, hr = 0x%lx\n", hr); 261 if (FAILED(hr)) 262 { 263 skip("Could not instantiate CShellLink\n"); 264 return; 265 } 266 267 memset(buffer, 0x55, sizeof(buffer)); 268 hr = psl->GetDescription(buffer, RTL_NUMBER_OF(buffer)); 269 ok(hr == S_OK, "IShellLink::GetDescription returned hr = 0x%lx\n", hr); 270 ok(buffer[0] == 0, "buffer[0] = %x\n", buffer[0]); 271 ok(buffer[1] == 0x5555, "buffer[1] = %x\n", buffer[1]); 272 273 hr = psl->SetDescription(testDescription); 274 ok(hr == S_OK, "IShellLink::SetDescription returned hr = 0x%lx\n", hr); 275 276 memset(buffer, 0x55, sizeof(buffer)); 277 hr = psl->GetDescription(buffer, RTL_NUMBER_OF(buffer)); 278 ok(hr == S_OK, "IShellLink::GetDescription returned hr = 0x%lx\n", hr); 279 ok(buffer[wcslen(testDescription)] == 0, "buffer[n] = %x\n", buffer[wcslen(testDescription)]); 280 ok(buffer[wcslen(testDescription) + 1] == 0x5555, "buffer[n+1] = %x\n", buffer[wcslen(testDescription) + 1]); 281 ok(!wcscmp(buffer, testDescription), "buffer = '%ls'\n", buffer); 282 283 hr = psl->SetDescription(NULL); 284 ok(hr == S_OK, "IShellLink::SetDescription returned hr = 0x%lx\n", hr); 285 286 memset(buffer, 0x55, sizeof(buffer)); 287 hr = psl->GetDescription(buffer, RTL_NUMBER_OF(buffer)); 288 ok(hr == S_OK, "IShellLink::GetDescription returned hr = 0x%lx\n", hr); 289 ok(buffer[0] == 0, "buffer[0] = %x\n", buffer[0]); 290 ok(buffer[1] == 0x5555, "buffer[1] = %x\n", buffer[1]); 291} 292 293 294/* Test IShellLink::Get/SetIconLocation and IExtractIcon::GetIconLocation */ 295typedef struct 296{ 297 PCWSTR FilePath; 298 299 /* Expected results */ 300 HRESULT hrDefIcon; // Return value for GIL_DEFAULTICON 301 HRESULT hrForShrt; // Return value for GIL_FORSHORTCUT 302 /* Return values for GIL_FORSHELL */ 303 HRESULT hrForShell; 304 PCWSTR IconPath; 305 UINT Flags; 306} TEST_SHELL_ICON; 307 308static TEST_SHELL_ICON ShIconTests[] = 309{ 310 /* Executable with icons */ 311 {L"%SystemRoot%\\system32\\cmd.exe", S_FALSE, E_INVALIDARG, 312 S_OK, L"%SystemRoot%\\system32\\cmd.exe", GIL_NOTFILENAME | GIL_PERINSTANCE}, 313 314 /* Executable without icon */ 315 {L"%SystemRoot%\\system32\\autochk.exe", S_FALSE, E_INVALIDARG, 316 S_OK, L"%SystemRoot%\\system32\\autochk.exe", GIL_NOTFILENAME | GIL_PERINSTANCE}, 317 318 /* Existing file */ 319 {L"%SystemRoot%\\system32\\shell32.dll", S_FALSE, E_INVALIDARG, 320 S_OK, L"*", GIL_NOTFILENAME | GIL_PERCLASS}, 321 322 /* Non-existing files */ 323 {L"%SystemRoot%\\non-existent-file.sdf", S_FALSE, E_INVALIDARG, 324 S_OK, L"*", GIL_NOTFILENAME | GIL_PERCLASS}, 325 {L"c:\\non-existent-path\\non-existent-file.sdf", S_FALSE, E_INVALIDARG, 326 S_OK, L"*", GIL_NOTFILENAME | GIL_PERCLASS}, 327}; 328 329static 330VOID 331test_iconlocation(UINT i, TEST_SHELL_ICON* testDef) 332{ 333 HRESULT hr; 334 CComPtr<IShellLinkW> psl; 335 CComPtr<IExtractIconW> pei; 336 INT iIcon; 337 UINT wFlags; 338 PCWSTR pszExplorer = L"%SystemRoot%\\explorer.exe"; 339 WCHAR szPath[MAX_PATH]; 340 WCHAR szPath2[MAX_PATH]; 341 342 hr = CoCreateInstance(CLSID_ShellLink, 343 NULL, 344 CLSCTX_INPROC_SERVER, 345 IID_PPV_ARG(IShellLinkW, &psl)); 346 ok(hr == S_OK, "CoCreateInstance, hr = 0x%lx\n", hr); 347 if (FAILED(hr)) 348 { 349 skip("Could not instantiate CShellLink\n"); 350 return; 351 } 352 353 /* Set the path to a file */ 354 ExpandEnvironmentStringsW(testDef->FilePath, szPath, _countof(szPath)); 355 hr = psl->SetPath(szPath); 356 ok(hr == S_OK, "IShellLink::SetPath failed, hr = 0x%lx\n", hr); 357 358 /* 359 * This test shows that this does not imply that the icon is automatically 360 * set and be retrieved naively by a call to IShellLink::GetIconLocation. 361 */ 362 iIcon = 0xdeadbeef; 363 wcscpy(szPath, L"garbage"); 364 hr = psl->GetIconLocation(szPath, _countof(szPath), &iIcon); 365 ok(hr == S_OK, "IShellLink::GetIconLocation(%d) failed, hr = 0x%lx\n", i, hr); 366 ok(*szPath == L'\0', "IShellLink::GetIconLocation(%d) returned '%S'\n", i, szPath); 367 ok(iIcon == 0, "IShellLink::GetIconLocation(%d) returned %d, expected %d\n", i, iIcon, 0); 368 369 /* Try to grab the IExtractIconW interface */ 370 hr = psl->QueryInterface(IID_PPV_ARG(IExtractIconW, &pei)); 371 ok(hr == S_OK, "IShellLink::QueryInterface(IExtractIconW)(%d) failed, hr = 0x%lx\n", i, hr); 372 if (!pei) 373 { 374 win_skip("No IExtractIconW interface\n"); 375 return; 376 } 377 378 iIcon = wFlags = 0xdeadbeef; 379 wcscpy(szPath, L"garbage"); 380 hr = pei->GetIconLocation(GIL_DEFAULTICON, szPath, _countof(szPath), &iIcon, &wFlags); 381 ok(hr == testDef->hrDefIcon, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrDefIcon); 382 ok(*szPath == L'\0', "IExtractIcon::GetIconLocation(%d) returned '%S'\n", i, szPath); 383 // ok(iIcon == 0, "IExtractIcon::GetIconLocation(%d) returned %d\n", i, iIcon); 384 385 iIcon = wFlags = 0xdeadbeef; 386 wcscpy(szPath, L"garbage"); 387 hr = pei->GetIconLocation(GIL_FORSHORTCUT, szPath, _countof(szPath), &iIcon, &wFlags); 388 ok(hr == testDef->hrForShrt, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrForShrt); 389 // Here, both szPath and iIcon are untouched... 390 391 iIcon = wFlags = 0xdeadbeef; 392 wcscpy(szPath, L"garbage"); 393 hr = pei->GetIconLocation(GIL_FORSHELL, szPath, _countof(szPath), &iIcon, &wFlags); 394 ok(hr == testDef->hrForShell, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrForShell); 395 ok(wFlags == testDef->Flags, "IExtractIcon::GetIconLocation(%d) returned wFlags = 0x%x, expected 0x%x\n", i, wFlags, testDef->Flags); 396 /* 397 * Actually, even if wFlags specifies GIL_NOTFILENAME, a correct file name is returned 398 * for executables only (at least...), otherwise we can get an asterix '*'. 399 */ 400 ExpandEnvironmentStringsW(testDef->IconPath, szPath2, _countof(szPath2)); 401 ok(_wcsicmp(szPath2, szPath) == 0, "IExtractIcon::GetIconLocation(%d) returned '%S', expected '%S'\n", i, szPath, szPath2); 402 403 // ok(*szPath == L'\0', "IExtractIcon::GetIconLocation returned '%S'\n", szPath); 404 // ok(iIcon == 0, "IExtractIcon::GetIconLocation returned %d\n", iIcon); 405 // ok(FALSE, "hr = 0x%lx, szPath = '%S', iIcon = %d, wFlags = %d\n", hr, szPath, iIcon, wFlags); 406 407 408 /* 409 * Now we test what happens when we explicitly set an icon to the shortcut. 410 * Note that actually, SetIconLocation() does not verify whether the file 411 * really exists. 412 */ 413 hr = psl->SetIconLocation(pszExplorer, 1); 414 ok(hr == S_OK, "IShellLink::SetIconLocation(%d) failed, hr = 0x%lx\n", i, hr); 415 416 /* 417 * First, we call IShellLink::GetIconLocation. We retrieve 418 * exactly what we specified with SetIconLocation. 419 */ 420 iIcon = 0xdeadbeef; 421 wcscpy(szPath, L"garbage"); 422 hr = psl->GetIconLocation(szPath, _countof(szPath), &iIcon); 423 ok(hr == S_OK, "IShellLink::GetIconLocation(%d) failed, hr = 0x%lx\n", i, hr); 424 ok(wcscmp(szPath, pszExplorer) == 0, "IShellLink::GetIconLocation(%d) returned '%S', expected '%S'\n", i, szPath, pszExplorer); 425 ok(iIcon == 1, "IShellLink::GetIconLocation(%d) returned %d, expected %d\n", i, iIcon, 1); 426 427 /* 428 * Now we test what happens with IExtractIcon::GetIconLocation. 429 * We see that it retrieves the icon of the shortcut's underlying file. 430 */ 431 iIcon = wFlags = 0xdeadbeef; 432 wcscpy(szPath, L"garbage"); 433 hr = pei->GetIconLocation(GIL_DEFAULTICON, szPath, _countof(szPath), &iIcon, &wFlags); 434 ok(hr == testDef->hrDefIcon, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrDefIcon); 435 ok(*szPath == L'\0', "IExtractIcon::GetIconLocation(%d) returned '%S'\n", i, szPath); 436 // ok(iIcon == 0, "IExtractIcon::GetIconLocation(%d) returned %d\n", i, iIcon); 437 438 iIcon = wFlags = 0xdeadbeef; 439 wcscpy(szPath, L"garbage"); 440 hr = pei->GetIconLocation(GIL_FORSHORTCUT, szPath, _countof(szPath), &iIcon, &wFlags); 441 ok(hr == testDef->hrForShrt, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrForShrt); 442 // Here, both szPath and iIcon are untouched... 443 444 iIcon = wFlags = 0xdeadbeef; 445 wcscpy(szPath, L"garbage"); 446 hr = pei->GetIconLocation(GIL_FORSHELL, szPath, _countof(szPath), &iIcon, &wFlags); 447 ok(hr == testDef->hrForShell, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrForShell); 448 ok(wFlags == testDef->Flags, "IExtractIcon::GetIconLocation(%d) returned wFlags = 0x%x, expected 0x%x\n", i, wFlags, testDef->Flags); 449 /* 450 * Actually, even if wFlags specifies GIL_NOTFILENAME, a correct file name is returned 451 * for executables only (at least...), otherwise we can get an asterix '*'. 452 */ 453 ExpandEnvironmentStringsW(testDef->IconPath, szPath2, _countof(szPath2)); 454 ok(_wcsicmp(szPath2, szPath) == 0, "IExtractIcon::GetIconLocation(%d) returned '%S', expected '%S'\n", i, szPath, szPath2); 455 456 // ok(*szPath == L'\0', "IExtractIcon::GetIconLocation returned '%S'\n", szPath); 457 // ok(iIcon == 0, "IExtractIcon::GetIconLocation returned %d\n", iIcon); 458 // ok(FALSE, "hr = 0x%lx, szPath = '%S', iIcon = %d, wFlags = %d\n", hr, szPath, iIcon, wFlags); 459} 460 461static 462VOID 463TestIconLocation(void) 464{ 465 UINT i; 466 467 for (i = 0; i < _countof(ShIconTests); ++i) 468 { 469 test_iconlocation(i, &ShIconTests[i]); 470 } 471} 472 473 474START_TEST(CShellLink) 475{ 476 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 477 478 TestShellLink(); 479 TestDescription(); 480 TestIconLocation(); 481 482 CoUninitialize(); 483}