From 4c1e83d5145c2433a21533e3d098107422bea8b6 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Tue, 21 Feb 2023 09:17:47 +0900 Subject: [PATCH] [SHLWAPI][SHLWAPI_APITEST] Expand string in SHLoadIndirectString (#5084) - shlwapi!SHLoadIndirectString expands the environmental strings if the first character was '@'. - Implement SHLoadRegUIStringA function. CORE-10667 --- dll/win32/shlwapi/ordinal.c | 27 ++++++ dll/win32/shlwapi/shlwapi.spec | 2 +- dll/win32/shlwapi/string.c | 10 ++ .../rostests/apitests/shlwapi/CMakeLists.txt | 3 +- .../apitests/shlwapi/SHLoadRegUIString.c | 96 +++++++++++++++++++ modules/rostests/apitests/shlwapi/testlist.c | 2 + 6 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 modules/rostests/apitests/shlwapi/SHLoadRegUIString.c diff --git a/dll/win32/shlwapi/ordinal.c b/dll/win32/shlwapi/ordinal.c index b8b93a60372..8286fe22e2f 100644 --- a/dll/win32/shlwapi/ordinal.c +++ b/dll/win32/shlwapi/ordinal.c @@ -4121,6 +4121,33 @@ BOOL WINAPI IsOS(DWORD feature) return FALSE; } +#ifdef __REACTOS__ +/************************************************************************* + * @ [SHLWAPI.438] + */ +HRESULT WINAPI SHLoadRegUIStringA(HKEY hkey, LPCSTR value, LPSTR buf, DWORD size) +{ + WCHAR valueW[MAX_PATH], bufferW[MAX_PATH]; + DWORD dwSize = ARRAY_SIZE(bufferW) * sizeof(CHAR); + HRESULT hr; + + MultiByteToWideChar(CP_ACP, 0, value, -1, valueW, ARRAY_SIZE(valueW)); + valueW[ARRAY_SIZE(valueW) - 1] = UNICODE_NULL; /* Avoid buffer overrun */ + + if (RegQueryValueExW(hkey, valueW, NULL, NULL, (LPBYTE)bufferW, &dwSize) != ERROR_SUCCESS) + return E_FAIL; + + hr = SHLoadIndirectString(bufferW, bufferW, ARRAY_SIZE(bufferW), NULL); + if (FAILED(hr)) + return hr; + + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buf, size, NULL, NULL); + if (size > 0) + buf[size - 1] = ANSI_NULL; /* Avoid buffer overrun */ + return S_OK; +} +#endif + /************************************************************************* * @ [SHLWAPI.439] */ diff --git a/dll/win32/shlwapi/shlwapi.spec b/dll/win32/shlwapi/shlwapi.spec index dd1e3cd7d1b..bcd304fda15 100644 --- a/dll/win32/shlwapi/shlwapi.spec +++ b/dll/win32/shlwapi/shlwapi.spec @@ -435,7 +435,7 @@ 435 stdcall -noname CLSIDFromProgIDWrap(wstr ptr) ole32.CLSIDFromProgID 436 stdcall -noname CLSIDFromStringWrap(wstr ptr) 437 stdcall -noname IsOS(long) -438 stub -noname SHLoadRegUIStringA +438 stdcall -noname SHLoadRegUIStringA(ptr str ptr long) 439 stdcall -noname SHLoadRegUIStringW(ptr wstr ptr long) 440 stdcall -noname SHGetWebFolderFilePathA(str ptr long) 441 stdcall -noname SHGetWebFolderFilePathW(wstr ptr long) diff --git a/dll/win32/shlwapi/string.c b/dll/win32/shlwapi/string.c index cb6489b7030..6dc9ff8e59d 100644 --- a/dll/win32/shlwapi/string.c +++ b/dll/win32/shlwapi/string.c @@ -2878,6 +2878,9 @@ HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void WCHAR *dllname = NULL; HMODULE hmod = NULL; HRESULT hr = E_FAIL; +#ifdef __REACTOS__ + WCHAR szExpanded[512]; +#endif TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved); @@ -2886,6 +2889,13 @@ HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void WCHAR *index_str; int index; +#ifdef __REACTOS__ + if (wcschr(src, '%') != NULL) + { + ExpandEnvironmentStringsW(src, szExpanded, ARRAY_SIZE(szExpanded)); + src = szExpanded; + } +#endif dst[0] = 0; dllname = StrDupW(src + 1); index_str = strchrW(dllname, ','); diff --git a/modules/rostests/apitests/shlwapi/CMakeLists.txt b/modules/rostests/apitests/shlwapi/CMakeLists.txt index 9712d77969b..47636a5cae6 100644 --- a/modules/rostests/apitests/shlwapi/CMakeLists.txt +++ b/modules/rostests/apitests/shlwapi/CMakeLists.txt @@ -13,6 +13,7 @@ list(APPEND SOURCE PathUnExpandEnvStringsForUser.c SHAreIconsEqual.c SHLoadIndirectString.c + SHLoadRegUIString.c StrFormatByteSizeW.c testdata.rc testlist.c) @@ -23,6 +24,6 @@ add_rc_deps(testdata.rc ${CMAKE_CURRENT_BINARY_DIR}/shlwapi_resource_dll/shlwapi add_executable(shlwapi_apitest ${SOURCE}) set_module_type(shlwapi_apitest win32cui) target_link_libraries(shlwapi_apitest ${PSEH_LIB}) -add_importlibs(shlwapi_apitest shlwapi user32 msvcrt kernel32) +add_importlibs(shlwapi_apitest shlwapi user32 advapi32 msvcrt kernel32) add_dependencies(shlwapi_apitest shlwapi_resource_dll) add_rostests_file(TARGET shlwapi_apitest) diff --git a/modules/rostests/apitests/shlwapi/SHLoadRegUIString.c b/modules/rostests/apitests/shlwapi/SHLoadRegUIString.c new file mode 100644 index 00000000000..d761853801a --- /dev/null +++ b/modules/rostests/apitests/shlwapi/SHLoadRegUIString.c @@ -0,0 +1,96 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Tests for SHLoadRegUIStringA/W + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#include +#include + +typedef HRESULT (WINAPI *FN_SHLoadRegUIStringA)(HKEY hkey, LPCSTR value, LPSTR buf, DWORD size); +typedef HRESULT (WINAPI *FN_SHLoadRegUIStringW)(HKEY hkey, LPCWSTR value, LPWSTR buf, DWORD size); + +static FN_SHLoadRegUIStringA pSHLoadRegUIStringA = NULL; +static FN_SHLoadRegUIStringW pSHLoadRegUIStringW = NULL; + +static void test_SHLoadRegUIStringA(HKEY hKey) +{ + HRESULT hr; + CHAR szBuff[MAX_PATH]; + + hr = pSHLoadRegUIStringA(hKey, "TestValue1", szBuff, _countof(szBuff)); + ok_long(hr, S_OK); + ok_str(szBuff, "%WINDIR%\\TEST"); + + hr = pSHLoadRegUIStringA(hKey, "TestValue2", szBuff, _countof(szBuff)); + ok_long(hr, S_OK); + ok_str(szBuff, "Test string one."); +} + +static void test_SHLoadRegUIStringW(HKEY hKey) +{ + HRESULT hr; + WCHAR szBuff[MAX_PATH]; + + hr = pSHLoadRegUIStringW(hKey, L"TestValue1", szBuff, _countof(szBuff)); + ok_long(hr, S_OK); + ok_wstr(szBuff, L"%WINDIR%\\TEST"); + + hr = pSHLoadRegUIStringW(hKey, L"TestValue2", szBuff, _countof(szBuff)); + ok_long(hr, S_OK); + ok_wstr(szBuff, L"Test string one."); +} + +BOOL extract_resource(const WCHAR* Filename, LPCWSTR ResourceName); + +START_TEST(SHLoadRegUIString) +{ + LONG error; + HKEY hKey; + DWORD cbValue; + static const WCHAR s_szTestValue1[] = L"%WINDIR%\\TEST"; + static const WCHAR s_szTestValue2[] = L"@SHLoadRegUIString.dll%EmptyEnvVar%,-3"; + HMODULE hSHLWAPI; + + SetEnvironmentVariableW(L"EmptyEnvVar", L""); + + /* Get procedures */ + hSHLWAPI = GetModuleHandleW(L"shlwapi"); + pSHLoadRegUIStringA = (FN_SHLoadRegUIStringA)GetProcAddress(hSHLWAPI, (LPCSTR)438); + pSHLoadRegUIStringW = (FN_SHLoadRegUIStringW)GetProcAddress(hSHLWAPI, (LPCSTR)439); + if (!pSHLoadRegUIStringA || !pSHLoadRegUIStringW) + { + skip("No procedure found\n"); + return; + } + + if (!extract_resource(L"SHLoadRegUIString.dll", MAKEINTRESOURCEW(101))) + { + skip("File 'SHLoadRegUIString.dll' cannot be extracted\n"); + return; + } + + /* Open registry key and write some test values */ + error = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software", 0, KEY_READ | KEY_WRITE, &hKey); + ok_long(error, ERROR_SUCCESS); + + cbValue = (lstrlenW(s_szTestValue1) + 1) * sizeof(WCHAR); + error = RegSetValueExW(hKey, L"TestValue1", 0, REG_SZ, (LPBYTE)s_szTestValue1, cbValue); + ok_long(error, ERROR_SUCCESS); + + cbValue = (lstrlenW(s_szTestValue2) + 1) * sizeof(WCHAR); + error = RegSetValueExW(hKey, L"TestValue2", 0, REG_SZ, (LPBYTE)s_szTestValue2, cbValue); + ok_long(error, ERROR_SUCCESS); + + /* The main dish */ + test_SHLoadRegUIStringA(hKey); + test_SHLoadRegUIStringW(hKey); + + /* Delete the test values and close the key */ + RegDeleteValueW(hKey, L"TestValue1"); + RegDeleteValueW(hKey, L"TestValue2"); + RegCloseKey(hKey); + + DeleteFileW(L"SHLoadRegUIString.dll"); +} diff --git a/modules/rostests/apitests/shlwapi/testlist.c b/modules/rostests/apitests/shlwapi/testlist.c index 6bf3fe27892..ea30af72bee 100644 --- a/modules/rostests/apitests/shlwapi/testlist.c +++ b/modules/rostests/apitests/shlwapi/testlist.c @@ -9,6 +9,7 @@ extern void func_PathUnExpandEnvStrings(void); extern void func_PathUnExpandEnvStringsForUser(void); extern void func_SHAreIconsEqual(void); extern void func_SHLoadIndirectString(void); +extern void func_SHLoadRegUIString(void); extern void func_StrFormatByteSizeW(void); const struct test winetest_testlist[] = @@ -21,6 +22,7 @@ const struct test winetest_testlist[] = { "PathUnExpandEnvStringsForUser", func_PathUnExpandEnvStringsForUser }, { "SHAreIconsEqual", func_SHAreIconsEqual }, { "SHLoadIndirectString", func_SHLoadIndirectString }, + { "SHLoadRegUIString", func_SHLoadRegUIString }, { "StrFormatByteSizeW", func_StrFormatByteSizeW }, { 0, 0 } };