[SHELL32] Shell Profile Folders fixes.

- 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__ .
This commit is contained in:
Hermès Bélusca-Maïto 2018-06-30 17:43:08 +02:00
parent 6abc9f5b5a
commit 2afb483a9e
No known key found for this signature in database
GPG Key ID: 3B2539C65E7B93D0

View 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);