/* * PROJECT: ReactOS api tests * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory * PURPOSE: Test for CShellLink * PROGRAMMER: Andreas Maier */ #include "shelltest.h" #define NDEBUG #include #include #include /* Test IShellLink::SetPath with environment-variables, existing, non-existing, ...*/ typedef struct { PCWSTR pathIn; HRESULT hrSetPath; /* Test 1 - hrGetPathX = IShellLink::GetPath(pathOutX, ... , flagsX); */ PCWSTR pathOut1; DWORD flags1; HRESULT hrGetPath1; BOOL expandPathOut1; /* Test 2 */ PCWSTR pathOut2; DWORD flags2; HRESULT hrGetPath2; BOOL expandPathOut2; } TEST_SHELL_LINK_DEF; static TEST_SHELL_LINK_DEF linkTestList[] = { { L"%comspec%", S_OK, L"%comspec%", SLGP_SHORTPATH, S_OK, TRUE, L"%comspec%", SLGP_RAWPATH, S_OK, FALSE }, { L"%anyvar%", E_INVALIDARG, L"", SLGP_SHORTPATH, S_FALSE, FALSE, L"", SLGP_RAWPATH, S_FALSE, FALSE }, { L"%anyvar%%comspec%", S_OK, L"c:\\%anyvar%%comspec%", SLGP_SHORTPATH, S_OK, TRUE, L"%anyvar%%comspec%", SLGP_RAWPATH, S_OK, FALSE }, { L"%temp%", S_OK, L"%temp%", SLGP_SHORTPATH, S_OK, TRUE, L"%temp%", SLGP_RAWPATH, S_OK, FALSE }, { L"%shell%", S_OK, L"%systemroot%\\system32\\%shell%", SLGP_SHORTPATH, S_OK, TRUE, L"%shell%", SLGP_RAWPATH, S_OK, FALSE }, { L"u:\\anypath\\%anyvar%", S_OK, L"u:\\anypath\\%anyvar%", SLGP_SHORTPATH, S_OK, TRUE, L"u:\\anypath\\%anyvar%", SLGP_RAWPATH, S_OK, FALSE }, { L"c:\\temp", S_OK, L"c:\\temp", SLGP_SHORTPATH, S_OK, FALSE, L"c:\\temp", SLGP_RAWPATH, S_OK, FALSE }, { L"cmd.exe", S_OK, L"%comspec%", SLGP_SHORTPATH, S_OK, TRUE, L"%comspec%", SLGP_RAWPATH, S_OK, TRUE }, { L"%systemroot%\\non-existent-file", S_OK, L"%systemroot%\\non-existent-file", SLGP_SHORTPATH, S_OK, TRUE, L"%systemroot%\\non-existent-file", SLGP_RAWPATH, S_OK, FALSE }, { L"c:\\non-existent-path\\non-existent-file", S_OK, L"c:\\non-existent-path\\non-existent-file", SLGP_SHORTPATH, S_OK, FALSE, L"c:\\non-existent-path\\non-existent-file", SLGP_RAWPATH, S_OK, FALSE }, { L"non-existent-file", E_INVALIDARG, L"", SLGP_SHORTPATH, S_FALSE, FALSE, L"", SLGP_RAWPATH, S_FALSE, FALSE }, }; static VOID test_checklinkpath(UINT i, TEST_SHELL_LINK_DEF* testDef) { static WCHAR evVar[MAX_PATH]; HRESULT hr, expectedHr; WCHAR wPathOut[MAX_PATH]; BOOL expandPathOut; PCWSTR expectedPathOut; CComPtr psl; UINT i1; DWORD flags; hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkW, &psl)); ok(hr == S_OK, "CoCreateInstance, hr = 0x%lx\n", hr); if (FAILED(hr)) { skip("Could not instantiate CShellLink\n"); return; } hr = psl->SetPath(testDef->pathIn); ok(hr == testDef->hrSetPath, "IShellLink::SetPath(%d), got hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrSetPath); expectedPathOut = NULL; for (i1 = 0; i1 <= 1; i1++) { if (i1 == 0) /* Usually SLGP_SHORTPATH */ { flags = testDef->flags1; expandPathOut = testDef->expandPathOut1; expectedPathOut = testDef->pathOut1; expectedHr = testDef->hrGetPath1; } else // if (i1 == 1) /* Usually SLGP_RAWPATH */ { flags = testDef->flags2; expandPathOut = testDef->expandPathOut2; expectedPathOut = testDef->pathOut2; expectedHr = testDef->hrGetPath2; } /* Patch some variables */ if (expandPathOut) { ExpandEnvironmentStringsW(expectedPathOut, evVar, _countof(evVar)); DPRINT("** %S **\n",evVar); expectedPathOut = evVar; } hr = psl->GetPath(wPathOut, _countof(wPathOut), NULL, flags); ok(hr == expectedHr, "IShellLink::GetPath(%d), flags 0x%lx, got hr = 0x%lx, expected 0x%lx\n", i, flags, hr, expectedHr); ok(wcsicmp(wPathOut, expectedPathOut) == 0, "IShellLink::GetPath(%d), flags 0x%lx, in %S, got %S, expected %S\n", i, flags, testDef->pathIn, wPathOut, expectedPathOut); } } static VOID TestShellLink(void) { UINT i; /* Needed for test */ SetEnvironmentVariableW(L"shell", L"cmd.exe"); for (i = 0; i < _countof(linkTestList); ++i) { DPRINT("IShellLink-Test(%d): %S\n", i, linkTestList[i].pathIn); test_checklinkpath(i, &linkTestList[i]); } SetEnvironmentVariableW(L"shell",NULL); } static VOID TestDescription(void) { HRESULT hr; CComPtr psl; WCHAR buffer[64]; PCWSTR testDescription = L"This is a test description"; /* Test SetDescription */ hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkW, &psl)); ok(hr == S_OK, "CoCreateInstance, hr = 0x%lx\n", hr); if (FAILED(hr)) { skip("Could not instantiate CShellLink\n"); return; } memset(buffer, 0x55, sizeof(buffer)); hr = psl->GetDescription(buffer, RTL_NUMBER_OF(buffer)); ok(hr == S_OK, "IShellLink::GetDescription returned hr = 0x%lx\n", hr); ok(buffer[0] == 0, "buffer[0] = %x\n", buffer[0]); ok(buffer[1] == 0x5555, "buffer[1] = %x\n", buffer[1]); hr = psl->SetDescription(testDescription); ok(hr == S_OK, "IShellLink::SetDescription returned hr = 0x%lx\n", hr); memset(buffer, 0x55, sizeof(buffer)); hr = psl->GetDescription(buffer, RTL_NUMBER_OF(buffer)); ok(hr == S_OK, "IShellLink::GetDescription returned hr = 0x%lx\n", hr); ok(buffer[wcslen(testDescription)] == 0, "buffer[n] = %x\n", buffer[wcslen(testDescription)]); ok(buffer[wcslen(testDescription) + 1] == 0x5555, "buffer[n+1] = %x\n", buffer[wcslen(testDescription) + 1]); ok(!wcscmp(buffer, testDescription), "buffer = '%ls'\n", buffer); hr = psl->SetDescription(NULL); ok(hr == S_OK, "IShellLink::SetDescription returned hr = 0x%lx\n", hr); memset(buffer, 0x55, sizeof(buffer)); hr = psl->GetDescription(buffer, RTL_NUMBER_OF(buffer)); ok(hr == S_OK, "IShellLink::GetDescription returned hr = 0x%lx\n", hr); ok(buffer[0] == 0, "buffer[0] = %x\n", buffer[0]); ok(buffer[1] == 0x5555, "buffer[1] = %x\n", buffer[1]); } /* Test IShellLink::Get/SetIconLocation and IExtractIcon::GetIconLocation */ typedef struct { PCWSTR FilePath; /* Expected results */ HRESULT hrDefIcon; // Return value for GIL_DEFAULTICON HRESULT hrForShrt; // Return value for GIL_FORSHORTCUT /* Return values for GIL_FORSHELL */ HRESULT hrForShell; PCWSTR IconPath; UINT Flags; } TEST_SHELL_ICON; static TEST_SHELL_ICON ShIconTests[] = { /* Executable with icons */ {L"%SystemRoot%\\system32\\cmd.exe", S_FALSE, E_INVALIDARG, S_OK, L"%SystemRoot%\\system32\\cmd.exe", GIL_NOTFILENAME | GIL_PERINSTANCE}, /* Executable without icon */ {L"%SystemRoot%\\system32\\autochk.exe", S_FALSE, E_INVALIDARG, S_OK, L"%SystemRoot%\\system32\\autochk.exe", GIL_NOTFILENAME | GIL_PERINSTANCE}, /* Existing file */ {L"%SystemRoot%\\system32\\shell32.dll", S_FALSE, E_INVALIDARG, S_OK, L"*", GIL_NOTFILENAME | GIL_PERCLASS}, /* Non-existing files */ {L"%SystemRoot%\\non-existent-file.sdf", S_FALSE, E_INVALIDARG, S_OK, L"*", GIL_NOTFILENAME | GIL_PERCLASS}, {L"c:\\non-existent-path\\non-existent-file.sdf", S_FALSE, E_INVALIDARG, S_OK, L"*", GIL_NOTFILENAME | GIL_PERCLASS}, }; static VOID test_iconlocation(UINT i, TEST_SHELL_ICON* testDef) { HRESULT hr; CComPtr psl; CComPtr pei; INT iIcon; UINT wFlags; PCWSTR pszExplorer = L"%SystemRoot%\\explorer.exe"; WCHAR szPath[MAX_PATH]; WCHAR szPath2[MAX_PATH]; hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkW, &psl)); ok(hr == S_OK, "CoCreateInstance, hr = 0x%lx\n", hr); if (FAILED(hr)) { skip("Could not instantiate CShellLink\n"); return; } /* Set the path to a file */ ExpandEnvironmentStringsW(testDef->FilePath, szPath, _countof(szPath)); hr = psl->SetPath(szPath); ok(hr == S_OK, "IShellLink::SetPath failed, hr = 0x%lx\n", hr); /* * This test shows that this does not imply that the icon is automatically * set and be retrieved naively by a call to IShellLink::GetIconLocation. */ iIcon = 0xdeadbeef; wcscpy(szPath, L"garbage"); hr = psl->GetIconLocation(szPath, _countof(szPath), &iIcon); ok(hr == S_OK, "IShellLink::GetIconLocation(%d) failed, hr = 0x%lx\n", i, hr); ok(*szPath == L'\0', "IShellLink::GetIconLocation(%d) returned '%S'\n", i, szPath); ok(iIcon == 0, "IShellLink::GetIconLocation(%d) returned %d, expected %d\n", i, iIcon, 0); /* Try to grab the IExtractIconW interface */ hr = psl->QueryInterface(IID_PPV_ARG(IExtractIconW, &pei)); ok(hr == S_OK, "IShellLink::QueryInterface(IExtractIconW)(%d) failed, hr = 0x%lx\n", i, hr); if (!pei) { win_skip("No IExtractIconW interface\n"); return; } iIcon = wFlags = 0xdeadbeef; wcscpy(szPath, L"garbage"); hr = pei->GetIconLocation(GIL_DEFAULTICON, szPath, _countof(szPath), &iIcon, &wFlags); ok(hr == testDef->hrDefIcon, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrDefIcon); ok(*szPath == L'\0', "IExtractIcon::GetIconLocation(%d) returned '%S'\n", i, szPath); // ok(iIcon == 0, "IExtractIcon::GetIconLocation(%d) returned %d\n", i, iIcon); iIcon = wFlags = 0xdeadbeef; wcscpy(szPath, L"garbage"); hr = pei->GetIconLocation(GIL_FORSHORTCUT, szPath, _countof(szPath), &iIcon, &wFlags); ok(hr == testDef->hrForShrt, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrForShrt); // Here, both szPath and iIcon are untouched... iIcon = wFlags = 0xdeadbeef; wcscpy(szPath, L"garbage"); hr = pei->GetIconLocation(GIL_FORSHELL, szPath, _countof(szPath), &iIcon, &wFlags); ok(hr == testDef->hrForShell, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrForShell); ok(wFlags == testDef->Flags, "IExtractIcon::GetIconLocation(%d) returned wFlags = 0x%x, expected 0x%x\n", i, wFlags, testDef->Flags); /* * Actually, even if wFlags specifies GIL_NOTFILENAME, a correct file name is returned * for executables only (at least...), otherwise we can get an asterix '*'. */ ExpandEnvironmentStringsW(testDef->IconPath, szPath2, _countof(szPath2)); ok(_wcsicmp(szPath2, szPath) == 0, "IExtractIcon::GetIconLocation(%d) returned '%S', expected '%S'\n", i, szPath, szPath2); // ok(*szPath == L'\0', "IExtractIcon::GetIconLocation returned '%S'\n", szPath); // ok(iIcon == 0, "IExtractIcon::GetIconLocation returned %d\n", iIcon); // ok(FALSE, "hr = 0x%lx, szPath = '%S', iIcon = %d, wFlags = %d\n", hr, szPath, iIcon, wFlags); /* * Now we test what happens when we explicitly set an icon to the shortcut. * Note that actually, SetIconLocation() does not verify whether the file * really exists. */ hr = psl->SetIconLocation(pszExplorer, 1); ok(hr == S_OK, "IShellLink::SetIconLocation(%d) failed, hr = 0x%lx\n", i, hr); /* * First, we call IShellLink::GetIconLocation. We retrieve * exactly what we specified with SetIconLocation. */ iIcon = 0xdeadbeef; wcscpy(szPath, L"garbage"); hr = psl->GetIconLocation(szPath, _countof(szPath), &iIcon); ok(hr == S_OK, "IShellLink::GetIconLocation(%d) failed, hr = 0x%lx\n", i, hr); ok(wcscmp(szPath, pszExplorer) == 0, "IShellLink::GetIconLocation(%d) returned '%S', expected '%S'\n", i, szPath, pszExplorer); ok(iIcon == 1, "IShellLink::GetIconLocation(%d) returned %d, expected %d\n", i, iIcon, 1); /* * Now we test what happens with IExtractIcon::GetIconLocation. * We see that it retrieves the icon of the shortcut's underlying file. */ iIcon = wFlags = 0xdeadbeef; wcscpy(szPath, L"garbage"); hr = pei->GetIconLocation(GIL_DEFAULTICON, szPath, _countof(szPath), &iIcon, &wFlags); ok(hr == testDef->hrDefIcon, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrDefIcon); ok(*szPath == L'\0', "IExtractIcon::GetIconLocation(%d) returned '%S'\n", i, szPath); // ok(iIcon == 0, "IExtractIcon::GetIconLocation(%d) returned %d\n", i, iIcon); iIcon = wFlags = 0xdeadbeef; wcscpy(szPath, L"garbage"); hr = pei->GetIconLocation(GIL_FORSHORTCUT, szPath, _countof(szPath), &iIcon, &wFlags); ok(hr == testDef->hrForShrt, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrForShrt); // Here, both szPath and iIcon are untouched... iIcon = wFlags = 0xdeadbeef; wcscpy(szPath, L"garbage"); hr = pei->GetIconLocation(GIL_FORSHELL, szPath, _countof(szPath), &iIcon, &wFlags); ok(hr == testDef->hrForShell, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i, hr, testDef->hrForShell); ok(wFlags == testDef->Flags, "IExtractIcon::GetIconLocation(%d) returned wFlags = 0x%x, expected 0x%x\n", i, wFlags, testDef->Flags); /* * Actually, even if wFlags specifies GIL_NOTFILENAME, a correct file name is returned * for executables only (at least...), otherwise we can get an asterix '*'. */ ExpandEnvironmentStringsW(testDef->IconPath, szPath2, _countof(szPath2)); ok(_wcsicmp(szPath2, szPath) == 0, "IExtractIcon::GetIconLocation(%d) returned '%S', expected '%S'\n", i, szPath, szPath2); // ok(*szPath == L'\0', "IExtractIcon::GetIconLocation returned '%S'\n", szPath); // ok(iIcon == 0, "IExtractIcon::GetIconLocation returned %d\n", iIcon); // ok(FALSE, "hr = 0x%lx, szPath = '%S', iIcon = %d, wFlags = %d\n", hr, szPath, iIcon, wFlags); } static VOID TestIconLocation(void) { UINT i; for (i = 0; i < _countof(ShIconTests); ++i) { test_iconlocation(i, &ShIconTests[i]); } } START_TEST(CShellLink) { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); TestShellLink(); TestDescription(); TestIconLocation(); CoUninitialize(); }