[SHELL32] Shell Profile Folders fixes.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 30 Jun 2018 15:43:08 +0000 (17:43 +0200)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 30 Jun 2018 16:20:08 +0000 (18:20 +0200)
- Fix a regression introduced in r65415 (1795a3bf) where the directory
  paths stored in "Windows\CurrentVersion\Explorer\User Shell Folders"
  were stored in expanded format instead of in unexpanded format:
  _SHGetDefaultValue() *MUST* return unexpanded paths by design!!

- Augment _SHExpandEnvironmentStrings() and _SHGetUserShellFolderPath()
  to take a user token handle to be able to correctly resolve/expand
  user-specific directory paths.

- Fix _SHExpandEnvironmentStrings() so that it always retrieve the
  correct current user / all-users directory paths by calling userenv
  functions, instead of hardcoding a broken logic. As a result this
  removes the "C:\Documents and Settings\SYSTEM" ghost directory we got
  during ReactOS installation.

- Delimit the changes with respect to Wine by #if(n)def __REACTOS__ .

dll/win32/shell32/wine/shellpath.c

index a6f5d63..2637c17 100644 (file)
@@ -41,6 +41,8 @@
 #include <wine/debug.h>
 #include <wine/unicode.h>
 
+#include <shlwapi_undoc.h>
+
 #include <userenv.h>
 
 #include "pidl.h"
@@ -624,9 +626,11 @@ static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t','\0'};
 static const WCHAR AllUsersProfileW[] = {'%','A','L','L','U','S','E','R','S','P','R','O','F','I','L','E','%','\0'};
 static const WCHAR UserProfileW[] = {'%','U','S','E','R','P','R','O','F','I','L','E','%','\0'};
 static const WCHAR SystemDriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%','\0'};
+#ifndef __REACTOS__
 static const WCHAR ProfileListW[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','P','r','o','f','i','l','e','L','i','s','t',0};
 static const WCHAR ProfilesDirectoryW[] = {'P','r','o','f','i','l','e','s','D','i','r','e','c','t','o','r','y',0};
 static const WCHAR AllUsersProfileValueW[] = {'A','l','l','U','s','e','r','s','P','r','o','f','i','l','e','\0'};
+#endif
 static const WCHAR szSHFolders[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l','o','r','e','r','\\','S','h','e','l','l',' ','F','o','l','d','e','r','s','\0'};
 static const WCHAR szSHUserFolders[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l','o','r','e','r','\\','U','s','e','r',' ','S','h','e','l','l',' ','F','o','l','d','e','r','s','\0'};
 static const WCHAR szDefaultProfileDirW[] = {'u','s','e','r','s',0};
@@ -1396,7 +1400,11 @@ static const CSIDL_DATA CSIDL_Data[] =
 #endif
 };
 
+#ifndef __REACTOS__
 static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest);
+#else
+static HRESULT _SHExpandEnvironmentStrings(HANDLE hToken, LPCWSTR szSrc, LPWSTR szDest, DWORD cchDest);
+#endif
 
 /* Gets the value named value from the registry key
  * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
@@ -1407,7 +1415,11 @@ static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest);
  * Returns successful error code if the value was retrieved from the registry,
  * and a failure otherwise.
  */
+#ifndef __REACTOS__
 static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix,
+#else
+static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, HANDLE hToken, LPCWSTR userPrefix,
+#endif
  LPCWSTR value, LPWSTR path)
 {
     HRESULT hr;
@@ -1459,7 +1471,11 @@ static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix,
         {
             WCHAR szTemp[MAX_PATH];
 
+#ifndef __REACTOS__
             _SHExpandEnvironmentStrings(path, szTemp);
+#else
+            _SHExpandEnvironmentStrings(hToken, path, szTemp, _countof(szTemp));
+#endif
             lstrcpynW(path, szTemp, MAX_PATH);
         }
         ret = RegSetValueExW(shellFolderKey, value, 0, REG_SZ, (LPBYTE)path,
@@ -1512,9 +1528,12 @@ BOOL _SHGetUserProfileDirectoryW(HANDLE hToken, LPWSTR szPath, LPDWORD lpcchPath
  *   CSIDL_Type_CurrVer:  %SystemDrive%
  *   (Others might make sense too, but as yet are unneeded.)
  */
+#ifndef __REACTOS__
+static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath)
+#else
 static HRESULT _SHGetDefaultValue(HANDLE hToken, BYTE folder, LPWSTR pszPath)
+#endif
 {
-    DWORD cchSize;
     HRESULT hr;
     WCHAR resourcePath[MAX_PATH];
 
@@ -1525,6 +1544,13 @@ static HRESULT _SHGetDefaultValue(HANDLE hToken, BYTE folder, LPWSTR pszPath)
     if (!pszPath)
         return E_INVALIDARG;
 
+#ifdef __REACTOS__
+    if (hToken != NULL && hToken != (HANDLE)-1)
+    {
+        FIXME("unsupported for user other than current or default\n");
+    }
+#endif
+
     if (!is_win64)
     {
         BOOL is_wow64;
@@ -1546,21 +1572,17 @@ static HRESULT _SHGetDefaultValue(HANDLE hToken, BYTE folder, LPWSTR pszPath)
 
     switch (CSIDL_Data[folder].type)
     {
-    case CSIDL_Type_User:
-        cchSize = MAX_PATH;
-        if (!_SHGetUserProfileDirectoryW(hToken, pszPath, &cchSize))
-            return HRESULT_FROM_WIN32(GetLastError());
-        break;
-    case CSIDL_Type_AllUsers:
-        cchSize = MAX_PATH;
-        if (!GetAllUsersProfileDirectoryW(pszPath, &cchSize))
-            return HRESULT_FROM_WIN32(GetLastError());
-        break;
-    case CSIDL_Type_CurrVer:
-        strcpyW(pszPath, SystemDriveW);
-        break;
-    default:
-        ; /* no corresponding env. var, do nothing */
+        case CSIDL_Type_User:
+            strcpyW(pszPath, UserProfileW);
+            break;
+        case CSIDL_Type_AllUsers:
+            strcpyW(pszPath, AllUsersProfileW);
+            break;
+        case CSIDL_Type_CurrVer:
+            strcpyW(pszPath, SystemDriveW);
+            break;
+        default:
+            ; /* no corresponding env. var, do nothing */
     }
 
     hr = S_OK;
@@ -1610,7 +1632,11 @@ static HRESULT _SHGetCurrentVersionPath(DWORD dwFlags, BYTE folder,
         return E_INVALIDARG;
 
     if (dwFlags & SHGFP_TYPE_DEFAULT)
+#ifndef __REACTOS__
+        hr = _SHGetDefaultValue(folder, pszPath);
+#else
         hr = _SHGetDefaultValue(NULL, folder, pszPath);
+#endif
     else
     {
         HKEY hKey;
@@ -1625,7 +1651,11 @@ static HRESULT _SHGetCurrentVersionPath(DWORD dwFlags, BYTE folder,
              &dwType, (LPBYTE)pszPath, &dwPathLen) ||
              (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
             {
+#ifndef __REACTOS__
+                hr = _SHGetDefaultValue(folder, pszPath);
+#else
                 hr = _SHGetDefaultValue(NULL, folder, pszPath);
+#endif
                 dwType = REG_EXPAND_SZ;
                 switch (folder)
                 {
@@ -1715,7 +1745,11 @@ static HRESULT _SHGetUserProfilePath(HANDLE hToken, DWORD dwFlags, BYTE folder,
 
     if (dwFlags & SHGFP_TYPE_DEFAULT)
     {
+#ifndef __REACTOS__
+        hr = _SHGetDefaultValue(folder, pszPath);
+#else
         hr = _SHGetDefaultValue(hToken, folder, pszPath);
+#endif
     }
     else
     {
@@ -1748,11 +1782,19 @@ static HRESULT _SHGetUserProfilePath(HANDLE hToken, DWORD dwFlags, BYTE folder,
             szValueName = &buffer[0];
         }
 
+#ifndef __REACTOS__
         hr = _SHGetUserShellFolderPath(hRootKey, userPrefix, szValueName, pszPath);
         if (FAILED(hr) && hRootKey != HKEY_LOCAL_MACHINE)
             hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL, szValueName, pszPath);
+        if (FAILED(hr))
+            hr = _SHGetDefaultValue(folder, pszPath);
+#else
+        hr = _SHGetUserShellFolderPath(hRootKey, hToken, userPrefix, szValueName, pszPath);
+        if (FAILED(hr) && hRootKey != HKEY_LOCAL_MACHINE)
+            hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, hToken, NULL, szValueName, pszPath);
         if (FAILED(hr))
             hr = _SHGetDefaultValue(hToken, folder, pszPath);
+#endif
         if (userPrefix != NULL && userPrefix != DefaultW)
             LocalFree((HLOCAL) userPrefix);
     }
@@ -1781,18 +1823,31 @@ static HRESULT _SHGetAllUsersProfilePath(DWORD dwFlags, BYTE folder,
         return E_INVALIDARG;
 
     if (dwFlags & SHGFP_TYPE_DEFAULT)
+#ifndef __REACTOS__
+        hr = _SHGetDefaultValue(folder, pszPath);
+#else
         hr = _SHGetDefaultValue(NULL, folder, pszPath);
+#endif
     else
     {
+#ifndef __REACTOS__
         hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL,
+#else
+        hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL, NULL,
+#endif
          CSIDL_Data[folder].szValueName, pszPath);
         if (FAILED(hr))
+#ifndef __REACTOS__
+            hr = _SHGetDefaultValue(folder, pszPath);
+#else
             hr = _SHGetDefaultValue(NULL, folder, pszPath);
+#endif
     }
     TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath));
     return hr;
 }
 
+#ifndef __REACTOS__
 static HRESULT _SHOpenProfilesKey(PHKEY pKey)
 {
     LONG lRet;
@@ -1843,6 +1898,7 @@ static HRESULT _SHGetProfilesValue(HKEY profilesKey, LPCWSTR szValueName,
     TRACE("returning 0x%08x (output value is %s)\n", hr, debugstr_w(szValue));
     return hr;
 }
+#endif
 
 /* Attempts to expand environment variables from szSrc into szDest, which is
  * assumed to be MAX_PATH characters in length.  Before referring to the
@@ -1856,11 +1912,19 @@ static HRESULT _SHGetProfilesValue(HKEY profilesKey, LPCWSTR szValueName,
  * If one of the directly handled environment variables is expanded, only
  * expands a single variable, and only in the beginning of szSrc.
  */
+#ifndef __REACTOS__
 static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest)
+#else
+static HRESULT _SHExpandEnvironmentStrings(HANDLE hToken, LPCWSTR szSrc, LPWSTR szDest, DWORD cchDest)
+#endif
 {
     HRESULT hr;
+#ifndef __REACTOS__
     WCHAR szTemp[MAX_PATH], szProfilesPrefix[MAX_PATH] = { 0 };
     HKEY key = NULL;
+#else
+    WCHAR szTemp[MAX_PATH];
+#endif
 
     TRACE("%s, %p\n", debugstr_w(szSrc), szDest);
 
@@ -1873,6 +1937,7 @@ static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest)
         hr = S_OK;
         goto end;
     }
+#ifndef __REACTOS__
     /* Get the profile prefix, we'll probably be needing it */
     hr = _SHOpenProfilesKey(&key);
     if (SUCCEEDED(hr))
@@ -1886,6 +1951,9 @@ static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest)
 
         hr = _SHGetProfilesValue(key, ProfilesDirectoryW, szProfilesPrefix, def_val );
     }
+#else
+    hr = S_OK;
+#endif
 
     *szDest = 0;
     strcpyW(szTemp, szSrc);
@@ -1893,27 +1961,44 @@ static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest)
     {
         if (!strncmpiW(szTemp, AllUsersProfileW, strlenW(AllUsersProfileW)))
         {
+#ifndef __REACTOS__
             WCHAR szAllUsers[MAX_PATH];
 
             strcpyW(szDest, szProfilesPrefix);
             hr = _SHGetProfilesValue(key, AllUsersProfileValueW,
              szAllUsers, AllUsersW);
             PathAppendW(szDest, szAllUsers);
+#else
+            DWORD cchSize = cchDest;
+            if (!GetAllUsersProfileDirectoryW(szDest, &cchSize))
+                return HRESULT_FROM_WIN32(GetLastError());
+#endif
             PathAppendW(szDest, szTemp + strlenW(AllUsersProfileW));
         }
         else if (!strncmpiW(szTemp, UserProfileW, strlenW(UserProfileW)))
         {
+#ifndef __REACTOS__
             WCHAR userName[MAX_PATH];
             DWORD userLen = MAX_PATH;
 
             strcpyW(szDest, szProfilesPrefix);
             GetUserNameW(userName, &userLen);
             PathAppendW(szDest, userName);
+#else
+            DWORD cchSize = cchDest;
+            if (!_SHGetUserProfileDirectoryW(hToken, szDest, &cchSize))
+                return HRESULT_FROM_WIN32(GetLastError());
+#endif
             PathAppendW(szDest, szTemp + strlenW(UserProfileW));
         }
         else if (!strncmpiW(szTemp, SystemDriveW, strlenW(SystemDriveW)))
         {
+#ifndef __REACTOS__
             GetSystemDirectoryW(szDest, MAX_PATH);
+#else
+            if (!GetSystemDirectoryW(szDest, cchDest))
+                return HRESULT_FROM_WIN32(GetLastError());
+#endif
             if (szDest[1] != ':')
             {
                 FIXME("non-drive system paths unsupported\n");
@@ -1927,9 +2012,17 @@ static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest)
         }
         else
         {
+#ifndef __REACTOS__
             DWORD ret = ExpandEnvironmentStringsW(szSrc, szDest, MAX_PATH);
+#else
+            DWORD ret = SHExpandEnvironmentStringsForUserW(hToken, szSrc, szDest, cchDest);
+#endif
 
+#ifndef __REACTOS__
             if (ret > MAX_PATH)
+#else
+            if (ret > cchDest)
+#endif
                 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
             else if (ret == 0)
                 hr = HRESULT_FROM_WIN32(GetLastError());
@@ -1945,8 +2038,10 @@ static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest)
         }
     }
 end:
+#ifndef __REACTOS__
     if (key)
         RegCloseKey(key);
+#endif
     TRACE("returning 0x%08x (input was %s, output is %s)\n", hr,
      debugstr_w(szSrc), debugstr_w(szDest));
     return hr;
@@ -2122,7 +2217,11 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW(
 
     /* Expand environment strings if necessary */
     if (*szTemp == '%')
+#ifndef __REACTOS__
         hr = _SHExpandEnvironmentStrings(szTemp, szBuildPath);
+#else
+        hr = _SHExpandEnvironmentStrings(hToken, szTemp, szBuildPath, _countof(szBuildPath));
+#endif
     else
         strcpyW(szBuildPath, szTemp);