📄 shellpath.c
字号:
testDesktop();
testPersonal();
testShellValues(requiredShellValues, ARRAY_SIZE(requiredShellValues),
FALSE);
testShellValues(optionalShellValues, ARRAY_SIZE(optionalShellValues),
TRUE);
}
/* Verifies various shell virtual folders have the correct well-known GUIDs. */
static void testGUIDs(void)
{
matchGUID(CSIDL_BITBUCKET, &CLSID_RecycleBin);
matchGUID(CSIDL_CONTROLS, &CLSID_ControlPanel);
matchGUID(CSIDL_DRIVES, &CLSID_MyComputer);
matchGUID(CSIDL_INTERNET, &CLSID_Internet);
matchGUID(CSIDL_NETWORK, &CLSID_NetworkPlaces);
matchGUID(CSIDL_PERSONAL, &CLSID_MyDocuments);
matchGUID(CSIDL_COMMON_DOCUMENTS, &CLSID_CommonDocuments);
}
/* Verifies various shell paths match the environment variables to which they
* correspond.
*/
static void testEnvVars(void)
{
matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES, "ProgramFiles");
matchSpecialFolderPathToEnv(CSIDL_APPDATA, "APPDATA");
matchSpecialFolderPathToEnv(CSIDL_PROFILE, "USERPROFILE");
matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "SystemRoot");
matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "windir");
matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES_COMMON,
"CommonProgramFiles");
/* this is only set on Wine, but can't hurt to verify it: */
matchSpecialFolderPathToEnv(CSIDL_SYSTEM, "winsysdir");
}
/* Verifies the shell path for CSIDL_WINDOWS matches the return from
* GetWindowsDirectory. If SHGetSpecialFolderPath fails, no harm, no foul--not
* every shell32 version supports CSIDL_WINDOWS.
*/
static void testWinDir(void)
{
char windowsShellPath[MAX_PATH], windowsDir[MAX_PATH] = { 0 };
if (!pSHGetSpecialFolderPathA) return;
if (pSHGetSpecialFolderPathA(NULL, windowsShellPath, CSIDL_WINDOWS, FALSE))
{
PathRemoveBackslashA(windowsShellPath);
GetWindowsDirectoryA(windowsDir, sizeof(windowsDir));
PathRemoveBackslashA(windowsDir);
ok(!lstrcmpiA(windowsDir, windowsShellPath),
"GetWindowsDirectory does not match SHGetSpecialFolderPath:\n"
"GetWindowsDirectory returns %s\nSHGetSpecialFolderPath returns %s\n",
windowsDir, windowsShellPath);
}
}
/* Verifies the shell path for CSIDL_SYSTEM and CSIDL_SYSTEMX86 matches the
* return from GetSystemDirectory. If SHGetSpecialFolderPath fails, no harm,
* no foul--not every shell32 version supports CSIDL_SYSTEM.
*/
static void testSystemDir(void)
{
char systemShellPath[MAX_PATH], systemDir[MAX_PATH] = { 0 };
if (!pSHGetSpecialFolderPathA) return;
GetSystemDirectoryA(systemDir, sizeof(systemDir));
PathRemoveBackslashA(systemDir);
if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEM, FALSE))
{
PathRemoveBackslashA(systemShellPath);
ok(!lstrcmpiA(systemDir, systemShellPath),
"GetSystemDirectory does not match SHGetSpecialFolderPath:\n"
"GetSystemDirectory returns %s\nSHGetSpecialFolderPath returns %s\n",
systemDir, systemShellPath);
}
/* check CSIDL_SYSTEMX86; note that this isn't always present, so don't
* worry if it fails
*/
if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEMX86, FALSE))
{
PathRemoveBackslashA(systemShellPath);
ok(!lstrcmpiA(systemDir, systemShellPath),
"GetSystemDirectory does not match SHGetSpecialFolderPath:\n"
"GetSystemDirectory returns %s\nSHGetSpecialFolderPath returns %s\n",
systemDir, systemShellPath);
}
}
/* Globals used by subprocesses */
static int myARGC;
static char **myARGV;
static char base[MAX_PATH];
static char selfname[MAX_PATH];
static int init(void)
{
myARGC = winetest_get_mainargs(&myARGV);
if (!GetCurrentDirectoryA(sizeof(base), base)) return 0;
strcpy(selfname, myARGV[0]);
return 1;
}
/* Subprocess helper 1: test what happens when CSIDL_FAVORITES is set to a
* nonexistent directory.
*/
static void testNonExistentPath1(void)
{
HRESULT hr;
LPITEMIDLIST pidl;
char path[MAX_PATH];
/* test some failure cases first: */
hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES, NULL,
SHGFP_TYPE_CURRENT, NULL);
ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
"SHGetFolderPath returned 0x%08lx, expected 0x80070002\n", hr);
pidl = NULL;
hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, NULL, 0,
&pidl);
ok(hr == E_FAIL,
"SHGetFolderLocation returned 0x%08lx, expected E_FAIL\n", hr);
if (SUCCEEDED(hr) && pidl)
IMalloc_Free(pMalloc, pidl);
ok(!pSHGetSpecialFolderPathA(NULL, path, CSIDL_FAVORITES, FALSE),
"SHGetSpecialFolderPath succeeded, expected failure\n");
pidl = NULL;
hr = pSHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl);
ok(hr == E_FAIL, "SHGetFolderLocation returned 0x%08lx, expected E_FAIL\n",
hr);
if (SUCCEEDED(hr) && pidl)
IMalloc_Free(pMalloc, pidl);
/* now test success: */
hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
SHGFP_TYPE_CURRENT, path);
if (SUCCEEDED(hr))
{
BOOL ret;
if (winetest_interactive)
printf("CSIDL_FAVORITES was changed to %s\n", path);
ret = CreateDirectoryA(path, NULL);
ok(!ret,
"CreateDirectoryA succeeded but should have failed "
"with ERROR_ALREADY_EXISTS\n");
if (!ret)
ok(GetLastError() == ERROR_ALREADY_EXISTS,
"CreateDirectoryA failed with %ld, "
"expected ERROR_ALREADY_EXISTS\n",
GetLastError());
}
ok(SUCCEEDED(hr),
"SHGetFolderPath(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, "
"NULL, SHGFP_TYPE_CURRENT, path)\nfailed: 0x%08lx\n", hr);
}
/* Subprocess helper 2: make sure SHGetFolderPath still succeeds when the
* original value of CSIDL_FAVORITES is restored.
*/
static void testNonExistentPath2(void)
{
HRESULT hr;
hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
SHGFP_TYPE_CURRENT, NULL);
ok(SUCCEEDED(hr), "SHGetFolderPath failed: 0x%08lx\n", hr);
}
static void doChild(const char *arg)
{
if (arg[0] == '1')
testNonExistentPath1();
else if (arg[0] == '2')
testNonExistentPath2();
}
/* Tests the return values from the various shell functions both with and
* without the use of the CSIDL_FLAG_CREATE flag. This flag only appeared in
* version 5 of the shell, so don't test unless it's at least version 5.
* The test reads a value from the registry, modifies it, calls
* SHGetFolderPath once with the CSIDL_FLAG_CREATE flag, and immediately
* afterward without it. Then it restores the registry and deletes the folder
* that was created.
* One oddity with respect to restoration: shell32 caches somehow, so it needs
* to be reloaded in order to see the correct (restored) value.
* Some APIs unrelated to the ones under test may fail, but I expect they're
* covered by other unit tests; I just print out something about failure to
* help trace what's going on.
*/
static void testNonExistentPath(void)
{
static const char userShellFolders[] =
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
char originalPath[MAX_PATH], modifiedPath[MAX_PATH];
HKEY key;
if (!pSHGetFolderPathA) return;
if (!pSHGetFolderLocation) return;
if (!pSHGetSpecialFolderPathA) return;
if (!pSHGetSpecialFolderLocation) return;
if (!pSHFileOperationA) return;
if (shellVersion.dwMajorVersion < 5) return;
if (!RegOpenKeyExA(HKEY_CURRENT_USER, userShellFolders, 0, KEY_ALL_ACCESS,
&key))
{
DWORD len, type;
len = sizeof(originalPath);
if (!RegQueryValueExA(key, "Favorites", NULL, &type,
(LPBYTE)&originalPath, &len))
{
size_t len = strlen(originalPath);
memcpy(modifiedPath, originalPath, len);
modifiedPath[len++] = '2';
modifiedPath[len++] = '\0';
if (winetest_interactive)
printf("Changing CSIDL_FAVORITES to %s\n", modifiedPath);
if (!RegSetValueExA(key, "Favorites", 0, type, (LPBYTE) modifiedPath, len))
{
char buffer[MAX_PATH];
STARTUPINFOA startup;
PROCESS_INFORMATION info;
HRESULT hr;
BOOL ret;
wnsprintfA(buffer, sizeof(buffer), "%s tests/shellpath.c 1",
selfname);
memset(&startup, 0, sizeof(startup));
startup.cb = sizeof(startup);
startup.dwFlags = STARTF_USESHOWWINDOW;
startup.dwFlags = SW_SHOWNORMAL;
CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
&startup, &info);
ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0,
"child process termination\n");
/* Query the path to be able to delete it below */
hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES, NULL,
SHGFP_TYPE_CURRENT, modifiedPath);
ok(SUCCEEDED(hr), "SHGetFolderPathA failed: 0x%08lx\n", hr);
/* restore original values: */
if (winetest_interactive)
printf("Restoring CSIDL_FAVORITES to %s\n", originalPath);
RegSetValueExA(key, "Favorites", 0, type, (LPBYTE) originalPath,
strlen(originalPath) + 1);
RegFlushKey(key);
wnsprintfA(buffer, sizeof(buffer), "%s tests/shellpath.c 2",
selfname);
memset(&startup, 0, sizeof(startup));
startup.cb = sizeof(startup);
startup.dwFlags = STARTF_USESHOWWINDOW;
startup.dwFlags = SW_SHOWNORMAL;
CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
&startup, &info);
ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0,
"child process termination\n");
ret = RemoveDirectoryA(modifiedPath);
ok( ret, "RemoveDirectoryA failed: %ld\n", GetLastError());
}
}
else if (winetest_interactive)
printf("RegQueryValueExA(key, Favorites, ...) failed\n");
if (key)
RegCloseKey(key);
}
else if (winetest_interactive)
printf("RegOpenKeyExA(HKEY_CURRENT_USER, %s, ...) failed\n",
userShellFolders);
}
START_TEST(shellpath)
{
if (!init()) return;
loadShell32();
if (!hShell32) return;
if (myARGC >= 3)
doChild(myARGV[2]);
else
{
/* first test various combinations of parameters: */
testApiParameters();
/* check known values: */
testPidlTypes();
testGUIDs();
testEnvVars();
testWinDir();
testSystemDir();
testNonExistentPath();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -