diff --git a/dll/win32/shlwapi/shlwapi.spec b/dll/win32/shlwapi/shlwapi.spec index 132b2c7b80f..d5946393494 100644 --- a/dll/win32/shlwapi/shlwapi.spec +++ b/dll/win32/shlwapi/shlwapi.spec @@ -462,8 +462,8 @@ 462 stdcall -noname UrlFixupW(wstr wstr long) 463 stdcall -noname SHExpandEnvironmentStringsForUserA(ptr str ptr long) userenv.ExpandEnvironmentStringsForUserA 464 stdcall -noname SHExpandEnvironmentStringsForUserW(ptr wstr ptr long) userenv.ExpandEnvironmentStringsForUserW -465 stub -noname PathUnExpandEnvStringsForUserA -466 stdcall -stub -noname PathUnExpandEnvStringsForUserW(ptr wstr ptr long) +465 stdcall -noname PathUnExpandEnvStringsForUserA(ptr str ptr long) +466 stdcall -noname PathUnExpandEnvStringsForUserW(ptr wstr ptr long) 467 stdcall -ordinal SHRunIndirectRegClientCommand(ptr wstr) # Exported by name in Vista+ 468 stdcall -noname RunIndirectRegCommand(ptr ptr wstr wstr) 469 stdcall -noname RunRegCommand(ptr ptr wstr) diff --git a/dll/win32/shlwapi/utils.cpp b/dll/win32/shlwapi/utils.cpp index 4fb8cba176f..82d153a544b 100644 --- a/dll/win32/shlwapi/utils.cpp +++ b/dll/win32/shlwapi/utils.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,182 @@ GetVersionMajorMinor() return MAKEWORD(HIBYTE(version), LOBYTE(version)); } +static BOOL +UnExpandEnvironmentStringForUserA( + _In_ HANDLE hUserToken, + _In_ PCSTR lpString, + _In_ PCSTR lpSrc, + _Out_ PSTR pszDest, + _In_ INT cchDest) +{ + CHAR szBuff[MAX_PATH]; + INT cchExpanded; + + if (hUserToken) + { + if (ExpandEnvironmentStringsForUserA(hUserToken, lpSrc, szBuff, _countof(szBuff))) + cchExpanded = lstrlenA(szBuff) + 1; + else + cchExpanded = 0; + } + else + { + cchExpanded = ExpandEnvironmentStringsA(lpSrc, szBuff, _countof(szBuff)); + } + + if (!cchExpanded || cchExpanded > cchDest) + return FALSE; + + INT cchEnvPath = cchExpanded - 1; + if (CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, + szBuff, cchEnvPath, lpString, cchEnvPath) != CSTR_EQUAL) + { + return FALSE; + } + + INT cchSuffix = lstrlenA(lpString) - cchEnvPath; + if (lstrlenA(lpSrc) + cchSuffix >= cchDest) + return FALSE; + + StringCchCopyA(pszDest, cchDest, lpSrc); + StringCchCatA(pszDest, cchDest, &lpString[cchEnvPath]); + return TRUE; +} + +static BOOL +UnExpandEnvironmentStringForUserW( + _In_ HANDLE hUserToken, + _In_ PCWSTR lpString, + _In_ PCWSTR lpSrc, + _Out_ PWSTR pszDest, + _In_ INT cchDest) +{ + WCHAR szBuff[MAX_PATH]; + INT cchExpanded; + + if (hUserToken) + { + if (ExpandEnvironmentStringsForUserW(hUserToken, lpSrc, szBuff, _countof(szBuff))) + cchExpanded = lstrlenW(szBuff) + 1; + else + cchExpanded = 0; + } + else + { + cchExpanded = ExpandEnvironmentStringsW(lpSrc, szBuff, _countof(szBuff)); + } + + if (!cchExpanded || cchExpanded > cchDest) + return FALSE; + + INT cchEnvPath = cchExpanded - 1; + if (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, + szBuff, cchEnvPath, lpString, cchEnvPath) != CSTR_EQUAL) + { + return FALSE; + } + + INT cchSuffix = lstrlenW(lpString) - cchEnvPath; + if (lstrlenW(lpSrc) + cchSuffix >= cchDest) + return FALSE; + + StringCchCopyW(pszDest, cchDest, lpSrc); + StringCchCatW(pszDest, cchDest, &lpString[cchEnvPath]); + return TRUE; +} + +/************************************************************************* + * PathUnExpandEnvStringsForUserA [SHLWAPI.465] + * + * See PathUnExpandEnvStringsForUserW. + */ +EXTERN_C +BOOL WINAPI +PathUnExpandEnvStringsForUserA( + _In_ HANDLE hUserToken, + _In_ PCSTR pszPath, + _Out_writes_(cchBuff) PSTR pszBuff, + _In_ INT cchBuff) +{ + static const PCSTR c_varsA[] = + { + "%APPDATA%", + "%USERPROFILE%", + "%ALLUSERSPROFILE%", + "%ProgramFiles%", + "%SystemRoot%", + "%SystemDrive%", + }; + + if (!pszPath) + { + if (pszBuff && cchBuff) + *pszBuff = ANSI_NULL; + + return FALSE; + } + + if (!pszBuff) + return FALSE; + + for (size_t iVar = 0; iVar < _countof(c_varsA); ++iVar) + { + if (UnExpandEnvironmentStringForUserA(hUserToken, pszPath, c_varsA[iVar], + pszBuff, cchBuff)) + { + return TRUE; + } + } + + return FALSE; +} + +/************************************************************************* + * PathUnExpandEnvStringsForUserW [SHLWAPI.466] + * + * https://undoc.airesoft.co.uk/shlwapi.dll/PathUnExpandEnvStringsForUserW.php + */ +EXTERN_C +BOOL WINAPI +PathUnExpandEnvStringsForUserW( + _In_ HANDLE hUserToken, + _In_ PCWSTR pwszPath, + _Out_writes_(cchBuff) PWSTR pszBuff, + _In_ INT cchBuff) +{ + static const PCWSTR c_varsW[] = + { + L"%APPDATA%", + L"%USERPROFILE%", + L"%ALLUSERSPROFILE%", + L"%ProgramFiles%", + L"%SystemRoot%", + L"%SystemDrive%", + }; + + if (!pwszPath) + { + if (pszBuff && cchBuff) + *pszBuff = UNICODE_NULL; + + return FALSE; + } + + if (!pszBuff) + return FALSE; + + for (size_t iVar = 0; iVar < _countof(c_varsW); ++iVar) + { + if (UnExpandEnvironmentStringForUserW(hUserToken, pwszPath, c_varsW[iVar], + pszBuff, cchBuff)) + { + return TRUE; + } + } + + return FALSE; +} + static BOOL CharLowerNoDBCSAWorker(PSTR lpString, INT cchMax, BOOL bUppercase) { CHAR szBuff[MAX_PATH]; diff --git a/sdk/include/reactos/shlwapi_undoc.h b/sdk/include/reactos/shlwapi_undoc.h index 30eec8317d4..b86de689c6d 100644 --- a/sdk/include/reactos/shlwapi_undoc.h +++ b/sdk/include/reactos/shlwapi_undoc.h @@ -388,6 +388,20 @@ PathFileExistsDefExtAndAttributesW( _In_ DWORD dwWhich, _Out_opt_ LPDWORD pdwFileAttributes); +BOOL WINAPI +PathUnExpandEnvStringsForUserA( + _In_ HANDLE hUserToken, + _In_ PCSTR pszPath, + _Out_writes_(cchBuff) PSTR pszBuff, + _In_ INT cchBuff); + +BOOL WINAPI +PathUnExpandEnvStringsForUserW( + _In_ HANDLE hUserToken, + _In_ PCWSTR pwszPath, + _Out_writes_(cchBuff) PWSTR pszBuff, + _In_ INT cchBuff); + BOOL WINAPI PathFindOnPathExW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs, DWORD dwWhich); VOID WINAPI FixSlashesAndColonA(_Inout_ LPSTR lpstr); VOID WINAPI FixSlashesAndColonW(_Inout_ LPWSTR lpwstr);