From 6f8cb05cad142a8679872e695f317dc1f9728d55 Mon Sep 17 00:00:00 2001 From: Joachim Henze Date: Mon, 17 Dec 2018 22:01:49 +0100 Subject: [PATCH] [DESK][SHELL32] Allow Desk.cpl to run standalone on WinXP/2003 again CORE-15412 addendum to 0.4.10-dev-502-g d559ca9c982f9766acc5db3ea887ef2bc27acdff That copy-paste was done once intentionally to keep our imports similar to 2003. It's worth reading the conversation in PR #748: Getequ seems to be ok with this. The ideal solution most likely would be to instead *statically* link against RegLoadMUIStringW() from advapi32_vista when WINNT=0x502. For now the stuff runs again at least. I left the func existing in advapi32_vista.dll. --- dll/cpl/desk/CMakeLists.txt | 6 +- dll/cpl/desk/desk.h | 9 ++ dll/cpl/desk/muireg.c | 144 ++++++++++++++++++++ dll/win32/shell32/CMakeLists.txt | 3 +- dll/win32/shell32/vista.c | 218 +++++++++++++++++++++++++++++++ 5 files changed, 375 insertions(+), 5 deletions(-) create mode 100644 dll/cpl/desk/muireg.c create mode 100644 dll/win32/shell32/vista.c diff --git a/dll/cpl/desk/CMakeLists.txt b/dll/cpl/desk/CMakeLists.txt index 24d9bb1e604..ae7fb83825a 100644 --- a/dll/cpl/desk/CMakeLists.txt +++ b/dll/cpl/desk/CMakeLists.txt @@ -2,9 +2,6 @@ add_definitions(-D_WIN32) spec2def(desk.cpl desk.spec) -remove_definitions(-D_WIN32_WINNT=0x502) -add_definitions(-D_WIN32_WINNT=0x600) - list(APPEND SOURCE advmon.c appearance.c @@ -23,6 +20,7 @@ list(APPEND SOURCE general.c draw.c theme.c + muireg.c desk.h) file(GLOB desk_rc_deps resources/*.*) @@ -36,6 +34,6 @@ add_library(desk SHARED set_module_type(desk cpl UNICODE) target_link_libraries(desk uuid) -add_importlibs(desk user32 advapi32 advapi32_vista gdi32 comctl32 comdlg32 ole32 setupapi shell32 shlwapi uxtheme gdiplus msvcrt kernel32 ntdll) +add_importlibs(desk user32 advapi32 gdi32 comctl32 comdlg32 ole32 setupapi shell32 shlwapi uxtheme gdiplus msvcrt kernel32 ntdll) add_pch(desk desk.h SOURCE) add_cd_file(TARGET desk DESTINATION reactos/system32 FOR all) diff --git a/dll/cpl/desk/desk.h b/dll/cpl/desk/desk.h index 3bb02f3a743..3c479251cfe 100644 --- a/dll/cpl/desk/desk.h +++ b/dll/cpl/desk/desk.h @@ -122,4 +122,13 @@ HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY,LPCWSTR,UINT,IDataObject*); INT_PTR CALLBACK AdvGeneralPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +LONG +RegLoadMUIStringW(IN HKEY hKey, + IN LPCWSTR pszValue OPTIONAL, + OUT LPWSTR pszOutBuf, + IN DWORD cbOutBuf, + OUT LPDWORD pcbData OPTIONAL, + IN DWORD Flags, + IN LPCWSTR pszDirectory OPTIONAL); + #endif /* _DESK_H */ diff --git a/dll/cpl/desk/muireg.c b/dll/cpl/desk/muireg.c new file mode 100644 index 00000000000..8754b43655b --- /dev/null +++ b/dll/cpl/desk/muireg.c @@ -0,0 +1,144 @@ +#include "desk.h" + +/****************************************************************************** + * load_string [Internal] + * + * This is basically a copy of user32/resource.c's LoadStringW. Necessary to + * avoid importing user32, which is higher level than advapi32. Helper for + * RegLoadMUIString. + */ +static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars) +{ + HGLOBAL hMemory; + HRSRC hResource; + WCHAR *pString; + int idxString; + + /* Negative values have to be inverted. */ + if (HIWORD(resId) == 0xffff) + resId = (UINT)(-((INT)resId)); + + /* Load the resource into memory and get a pointer to it. */ + hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING); + if (!hResource) return 0; + hMemory = LoadResource(hModule, hResource); + if (!hMemory) return 0; + pString = LockResource(hMemory); + + /* Strings are length-prefixed. Lowest nibble of resId is an index. */ + idxString = resId & 0xf; + while (idxString--) pString += *pString + 1; + + /* If no buffer is given, return length of the string. */ + if (!pwszBuffer) return *pString; + + /* Else copy over the string, respecting the buffer size. */ + cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1); + if (cMaxChars >= 0) + { + memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR)); + pwszBuffer[cMaxChars] = L'\0'; + } + + return cMaxChars; +} + + +/************************************************************************ + * RegLoadMUIStringW + * + * @implemented + */ +LONG +RegLoadMUIStringW(IN HKEY hKey, + IN LPCWSTR pszValue OPTIONAL, + OUT LPWSTR pszOutBuf, + IN DWORD cbOutBuf, + OUT LPDWORD pcbData OPTIONAL, + IN DWORD Flags, + IN LPCWSTR pszDirectory OPTIONAL) +{ + DWORD dwValueType, cbData; + LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL; + LONG result; + + /* Parameter sanity checks. */ + if (!hKey || !pszOutBuf) + return ERROR_INVALID_PARAMETER; + + if (pszDirectory && *pszDirectory) + { + //FIXME("BaseDir parameter not yet supported!\n"); + return ERROR_INVALID_PARAMETER; + } + + /* Check for value existence and correctness of it's type, allocate a buffer and load it. */ + result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData); + if (result != ERROR_SUCCESS) goto cleanup; + if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) + { + result = ERROR_FILE_NOT_FOUND; + goto cleanup; + } + pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); + if (!pwszTempBuffer) + { + result = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData); + if (result != ERROR_SUCCESS) goto cleanup; + + /* Expand environment variables, if appropriate, or copy the original string over. */ + if (dwValueType == REG_EXPAND_SZ) + { + cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR); + if (!cbData) goto cleanup; + pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); + if (!pwszExpandedBuffer) + { + result = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData); + } + else + { + pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); + memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData); + } + + /* If the value references a resource based string, parse the value and load the string. + * Else just copy over the original value. */ + result = ERROR_SUCCESS; + if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */ + { + lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR)); + } + else + { + WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L','); + UINT uiStringId; + HMODULE hModule; + + /* Format of the expanded value is 'path_to_dll,-resId' */ + if (!pComma || pComma[1] != L'-') + { + result = ERROR_BADKEY; + goto cleanup; + } + + uiStringId = _wtoi(pComma+2); + *pComma = L'\0'; + + hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE); + if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR))) + result = ERROR_BADKEY; + FreeLibrary(hModule); + } + +cleanup: + HeapFree(GetProcessHeap(), 0, pwszTempBuffer); + HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer); + return result; +} diff --git a/dll/win32/shell32/CMakeLists.txt b/dll/win32/shell32/CMakeLists.txt index 08933dda357..78ee1af5319 100644 --- a/dll/win32/shell32/CMakeLists.txt +++ b/dll/win32/shell32/CMakeLists.txt @@ -102,6 +102,7 @@ add_library(shell32 SHARED wine/shellstring.c wine/shlmenu.c wine/shpolicy.c + vista.c shell32.rc ${CMAKE_CURRENT_BINARY_DIR}/shell32_stubs.c ${CMAKE_CURRENT_BINARY_DIR}/shell32.def) @@ -113,7 +114,7 @@ set_source_files_properties(shell32.rc PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT set_module_type(shell32 win32dll UNICODE) target_link_libraries(shell32 shellmenu shelldesktop atlnew wine uuid recyclebin) add_delay_importlibs(shell32 powrprof shdocvw devmgr winspool.drv winmm mpr uxtheme ole32 oleaut32 userenv browseui version fmifs) -add_importlibs(shell32 advapi32 advapi32_vista gdi32 user32 comctl32 comdlg32 shlwapi msvcrt kernel32 ntdll) +add_importlibs(shell32 advapi32 gdi32 user32 comctl32 comdlg32 shlwapi msvcrt kernel32 ntdll) add_dependencies(shell32 stdole2) # shell32_shldisp.tlb needs stdole2.tlb add_pch(shell32 precomp.h SOURCE) add_cd_file(TARGET shell32 DESTINATION reactos/system32 FOR all) diff --git a/dll/win32/shell32/vista.c b/dll/win32/shell32/vista.c new file mode 100644 index 00000000000..9f1a8335a34 --- /dev/null +++ b/dll/win32/shell32/vista.c @@ -0,0 +1,218 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: Copied from advapi32/reg/reg.c + * PURPOSE: Registry functions + * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) + * Thomas Weidenmueller + * UPDATE HISTORY: + * Created 01/11/98 + * 19990309 EA Stubs + * 20050502 Fireball imported some stuff from WINE + */ + +#include + +#define WIN32_NO_STATUS +#define _INC_WINDOWS +#define COM_NO_WINDOWS_H + +#include +#include +#include +#include +#define NTOS_MODE_USER +#include + +#include +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/****************************************************************************** + * load_string [Internal] + * + * This is basically a copy of user32/resource.c's LoadStringW. Necessary to + * avoid importing user32, which is higher level than advapi32. Helper for + * RegLoadMUIString. + */ +static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars) +{ + HGLOBAL hMemory; + HRSRC hResource; + WCHAR *pString; + int idxString; + + /* Negative values have to be inverted. */ + if (HIWORD(resId) == 0xffff) + resId = (UINT)(-((INT)resId)); + + /* Load the resource into memory and get a pointer to it. */ + hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING); + if (!hResource) return 0; + hMemory = LoadResource(hModule, hResource); + if (!hMemory) return 0; + pString = LockResource(hMemory); + + /* Strings are length-prefixed. Lowest nibble of resId is an index. */ + idxString = resId & 0xf; + while (idxString--) pString += *pString + 1; + + /* If no buffer is given, return length of the string. */ + if (!pwszBuffer) return *pString; + + /* Else copy over the string, respecting the buffer size. */ + cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1); + if (cMaxChars >= 0) + { + memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR)); + pwszBuffer[cMaxChars] = L'\0'; + } + + return cMaxChars; +} + +/************************************************************************ + * RegLoadMUIStringW + * + * @implemented + */ +LONG WINAPI +RegLoadMUIStringW(IN HKEY hKey, + IN LPCWSTR pszValue OPTIONAL, + OUT LPWSTR pszOutBuf, + IN DWORD cbOutBuf, + OUT LPDWORD pcbData OPTIONAL, + IN DWORD Flags, + IN LPCWSTR pszDirectory OPTIONAL) +{ + DWORD dwValueType, cbData; + LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL; + LONG result; + + /* Parameter sanity checks. */ + if (!hKey || !pszOutBuf) + return ERROR_INVALID_PARAMETER; + + if (pszDirectory && *pszDirectory) + { + FIXME("BaseDir parameter not yet supported!\n"); + return ERROR_INVALID_PARAMETER; + } + + /* Check for value existence and correctness of it's type, allocate a buffer and load it. */ + result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData); + if (result != ERROR_SUCCESS) goto cleanup; + if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) + { + result = ERROR_FILE_NOT_FOUND; + goto cleanup; + } + pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); + if (!pwszTempBuffer) + { + result = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData); + if (result != ERROR_SUCCESS) goto cleanup; + + /* Expand environment variables, if appropriate, or copy the original string over. */ + if (dwValueType == REG_EXPAND_SZ) + { + cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR); + if (!cbData) goto cleanup; + pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); + if (!pwszExpandedBuffer) + { + result = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData); + } + else + { + pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); + memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData); + } + + /* If the value references a resource based string, parse the value and load the string. + * Else just copy over the original value. */ + result = ERROR_SUCCESS; + if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */ + { + lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR)); + } + else + { + WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L','); + UINT uiStringId; + HMODULE hModule; + + /* Format of the expanded value is 'path_to_dll,-resId' */ + if (!pComma || pComma[1] != L'-') + { + result = ERROR_BADKEY; + goto cleanup; + } + + uiStringId = _wtoi(pComma+2); + *pComma = L'\0'; + + hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE); + if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR))) + result = ERROR_BADKEY; + FreeLibrary(hModule); + } + +cleanup: + HeapFree(GetProcessHeap(), 0, pwszTempBuffer); + HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer); + return result; +} + +/************************************************************************ + * RegLoadMUIStringA + * + * @implemented + */ +LONG WINAPI +RegLoadMUIStringA(IN HKEY hKey, + IN LPCSTR pszValue OPTIONAL, + OUT LPSTR pszOutBuf, + IN DWORD cbOutBuf, + OUT LPDWORD pcbData OPTIONAL, + IN DWORD Flags, + IN LPCSTR pszDirectory OPTIONAL) +{ + UNICODE_STRING valueW, baseDirW; + WCHAR *pwszBuffer; + DWORD cbData = cbOutBuf * sizeof(WCHAR); + LONG result; + + valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL; + if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) || + !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) || + !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData))) + { + result = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + + result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags, + baseDirW.Buffer); + + if (result == ERROR_SUCCESS) + { + cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL); + if (pcbData) + *pcbData = cbData; + } + +cleanup: + HeapFree(GetProcessHeap(), 0, pwszBuffer); + RtlFreeUnicodeString(&baseDirW); + RtlFreeUnicodeString(&valueW); + + return result; +}