diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index ff989675c6e..e81347fe9a2 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -1240,13 +1240,6 @@ static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix, * CSIDL_Type_AllUsers: %ALLUSERSPROFILE% * CSIDL_Type_CurrVer: %SystemDrive% * (Others might make sense too, but as yet are unneeded.) - * FIXME: there are two special cases for the default value: - * - the "My Documents" (CSIDL_PERSONAL) entry should be $HOME - * - the CSIDL_DESKTOP and CSIDL_DESKTOPDIRECTORY (which have the same path) - * should be $HOME/Desktop if it exists - * But, $HOME doesn't seem to be inherited into the Wine environment. I could - * use getenv, but this returns me a UNIX path, which may or may not be - * reachable from any currently mounted DOS drives. */ static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath) { @@ -1261,6 +1254,51 @@ static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath) if (!pszPath) return E_INVALIDARG; + /* Try special cases first */ + hr = E_FAIL; + switch (folder) + { + case CSIDL_PERSONAL: + { + const char *home = getenv("HOME"); + + /* special case for "My Documents", map to $HOME */ + if (home) + { + WCHAR homeW[MAX_PATH]; + + MultiByteToWideChar(CP_UNIXCP, 0, home, -1, homeW, MAX_PATH); + if (GetFullPathNameW(homeW, MAX_PATH, pszPath, NULL) != 0 && + PathIsDirectoryW(pszPath)) + hr = S_OK; + } + break; + } + case CSIDL_DESKTOP: + case CSIDL_DESKTOPDIRECTORY: + { + const char *home = getenv("HOME"); + + /* special case for Desktop, map to $HOME/Desktop if it exists */ + if (home) + { + WCHAR desktopW[MAX_PATH]; + + MultiByteToWideChar(CP_UNIXCP, 0, home, -1, desktopW, MAX_PATH); + PathAppendW(desktopW, DesktopW); + if (GetFullPathNameW(desktopW, MAX_PATH, pszPath, NULL) != 0 && + PathIsDirectoryW(pszPath)) + hr = S_OK; + } + break; + } + } + if (SUCCEEDED(hr)) + return hr; + + /* Either the folder was unhandled, or a suitable default wasn't found, + * so use one of the resource-based defaults + */ if (CSIDL_Data[folder].szDefaultPath && IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath)) { diff --git a/dlls/shell32/tests/shellpath.c b/dlls/shell32/tests/shellpath.c index 0549f01f337..3f44f7fc79a 100644 --- a/dlls/shell32/tests/shellpath.c +++ b/dlls/shell32/tests/shellpath.c @@ -41,6 +41,9 @@ #ifndef PT_GUID #define PT_GUID 0x1f /* no path */ #endif +#ifndef PT_DRIVE +#define PT_DRIVE 0x23 /* has path */ +#endif #ifndef PT_DRIVE2 #define PT_DRIVE2 0x25 /* has path */ #endif @@ -496,6 +499,7 @@ static void testShellValues(const struct shellExpectedValues testEntries[], switch (type) { case PT_FOLDER: + case PT_DRIVE: case PT_DRIVE2: case PT_IESPECIAL2: testSHGetFolderPath(optional, testEntries[i].folder); @@ -577,14 +581,17 @@ static void testPersonal(void) { BYTE type; + /* The pidl may be a real folder, or a virtual directory, or a drive if the + * home directory is set to the root directory of a drive. + */ type = testSHGetFolderLocation(FALSE, CSIDL_PERSONAL); - ok(type == PT_FOLDER || type == PT_GUID, + ok(type == PT_FOLDER || type == PT_GUID || type == PT_DRIVE, "CSIDL_PERSONAL returned invalid type 0x%02x, " "expected PT_FOLDER or PT_GUID\n", type); if (type == PT_FOLDER) testSHGetFolderPath(FALSE, CSIDL_PERSONAL); type = testSHGetSpecialFolderLocation(FALSE, CSIDL_PERSONAL); - ok(type == PT_FOLDER || type == PT_GUID, + ok(type == PT_FOLDER || type == PT_GUID || type == PT_DRIVE, "CSIDL_PERSONAL returned invalid type 0x%02x, " "expected PT_FOLDER or PT_GUID\n", type); if (type == PT_FOLDER)