[PATCH 0/1] MR10090: kernelbase/loader.c: Include rudimentary support for multilanguage resource inclusion.
For programs that rely on language specific data for resources such as menus and text, attempt to search for and associated "mui" file. For example, if program "myapp.exe" is executed and resources are not found, and the user's language ID is "ENU", search for file "myapp.ENU", and if found, utilize that file for the source of resource data. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10090
From: Craig Schulstad <craigaschulstad@gmail.com> For programs that rely on language specific data for resources such as menus and text, attempt to search for and associated "mui" file. For example, if program "myapp.exe" is executed and resources are not found, and the user's language ID is "ENU", search for file "myapp.ENU", and if found, utilize that file for the source of resource data. --- dlls/kernelbase/loader.c | 179 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 172 insertions(+), 7 deletions(-) mode change 100644 => 100755 dlls/kernelbase/loader.c diff --git a/dlls/kernelbase/loader.c b/dlls/kernelbase/loader.c old mode 100644 new mode 100755 index 34767ab4a7b..f6bc614ea65 --- a/dlls/kernelbase/loader.c +++ b/dlls/kernelbase/loader.c @@ -56,6 +56,10 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION exclusive_datafile_list_section = { &critsect_debug, -1, 0, 0, 0, 0 }; +static WCHAR mui_locale[LOCALE_NAME_MAX_LENGTH]; /* MUI work variables */ +static BOOL locale_found = FALSE; +static BOOL recursion_flag = FALSE; + /*********************************************************************** * Modules ***********************************************************************/ @@ -1056,11 +1060,125 @@ BOOL WINAPI DECLSPEC_HOTPATCH EnumResourceTypesExW( HMODULE module, ENUMRESTYPEP return ret; } +/***********************************************************************/ +/* get_mui - Acquire an MUI module for the associated resource */ +/***********************************************************************/ + +HMODULE get_mui(HMODULE module) + +{ + HMODULE mui_module = NULL; + + WCHAR module_name[MAX_PATH], mui_name[MAX_PATH]; + + INT i, j, k, l; + + /* Initialize the work strings */ + + for (i = 0; i < MAX_PATH; i++) { + module_name[i] = 0; + mui_name[i] = 0; + } + + /* Note - the reference to the Windows file name for an "MUI" file has a structure such as */ + /* "C:\Program Files\Application Directory\xx-XX\Application.exe.mui"; however, in testing */ + /* out the usage of the "GetModuleFileNameW" function, it was determined that it works with */ + /* a relative Linux file structure such as "xx-XX/Application.exe.mui". */ + + if (!(GetModuleFileNameW(module, module_name, MAX_PATH))) /* Acquire the base resource file name */ + return module; + + /* Stay with the original module reference if this file is not an executable file. */ + + if (!(wcsstr(module_name, L".exe"))) + return module; + + /* Acquire the locale name using LCIDToLocaleName. Since this function utilizes the FindResourceExW function, this */ + /* sets up a recursive call to this function. In order to avoid a stack overflow condition that would be caused by */ + /* repeated calls, a flag will be set on to return back to the FindResourceExW function without again calling the */ + /* locale acquisition function. */ + + if (!(locale_found)) { + + if (recursion_flag) + return module; + + recursion_flag = TRUE; + + LCIDToLocaleName( GetUserDefaultLCID(), mui_locale, LOCALE_NAME_MAX_LENGTH, 0 ); + + recursion_flag = FALSE; + + locale_found = TRUE; + + } + + /* Locate the position of the final backslash in the retrieved executable file. */ + + j = 0; + + for (i = 0; i < MAX_PATH; i++) { + + if (module_name[i] == 0) + break; + + if (module_name[i] == '\\') + j = i; + } + + /* Set up the work index that will be used to extract just the executable file from the fully qualified file name. */ + + k = 0; + + for (i = 0; i < MAX_PATH; i++) { + + if (module_name[i] == 0) + break; + + /* If work index "j" has been set to -1, then the file portion of the qualified name has been reached and will */ + /* be copied to the "MUI" file reference. */ + + if (j < 0) { + mui_name[k] = module_name[i]; + k++; + } + + /* When the position of the final backslash has been reached, add the locale name as the folder/directory */ + /* containing the "MUI" file and reset work index "j" to -1. */ + + if (i >= j && j > 0) { + for (l = 0; l < 5; l++) { + mui_name[k] = mui_locale[l]; + k++; + } + mui_name[k] = '/'; + k++; + j = -1; + } + } + + /* Finally, append the literal ".mui" onto the file reference. */ + + wcscat(mui_name, L".mui"); + + /* Now, see if there is an associated "MUI" file and if so use its handle for the module handle. */ + + mui_module = LoadLibraryExW(mui_name, 0, 0); + + if (mui_module) { + return mui_module; + } else { + return module; + } + +} + +/***********************************************************************/ +/* get_res_handle - Isolated call of the LdrFindResource function */ +/***********************************************************************/ + +HRSRC get_res_handle(HMODULE module, LPCWSTR type, LPCWSTR name, WORD lang) -/********************************************************************** - * FindResourceExW (kernelbase.@) - */ -HRSRC WINAPI DECLSPEC_HOTPATCH FindResourceExW( HMODULE module, LPCWSTR type, LPCWSTR name, WORD lang ) { NTSTATUS status; UNICODE_STRING nameW, typeW; @@ -1069,7 +1187,6 @@ HRSRC WINAPI DECLSPEC_HOTPATCH FindResourceExW( HMODULE module, LPCWSTR type, LP TRACE( "%p %s %s %04x\n", module, debugstr_w(type), debugstr_w(name), lang ); - if (!module) module = GetModuleHandleW( 0 ); nameW.Buffer = typeW.Buffer = NULL; __TRY @@ -1091,9 +1208,41 @@ HRSRC WINAPI DECLSPEC_HOTPATCH FindResourceExW( HMODULE module, LPCWSTR type, LP if (!IS_INTRESOURCE(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer ); if (!IS_INTRESOURCE(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer ); + return (HRSRC)entry; + } +/********************************************************************** + * FindResourceExW (kernelbase.@) + */ +HRSRC WINAPI DECLSPEC_HOTPATCH FindResourceExW( HMODULE module, LPCWSTR type, LPCWSTR name, WORD lang ) +{ + HRSRC rsrc; + + TRACE( "%p %s %s %04x\n", module, debugstr_w(type), debugstr_w(name), lang ); + + if (!module) module = GetModuleHandleW( 0 ); + + rsrc = get_res_handle(module, type, name, lang); + + if (rsrc) { + + return rsrc; + + } else { + + /* If a resource retrieval failed using the initial module value, attempt to */ + /* locate an associated MUI file and retry the resource retrieval. */ + + module = get_mui(module); + + rsrc = get_res_handle(module, type, name, lang); + + return rsrc; + + } +} /********************************************************************** * FindResourceW (kernelbase.@) @@ -1120,10 +1269,26 @@ HGLOBAL WINAPI DECLSPEC_HOTPATCH LoadResource( HINSTANCE module, HRSRC rsrc ) { void *ret; + HMODULE mui_module = NULL; + TRACE( "%p %p\n", module, rsrc ); - if (!rsrc) return 0; - if (!module) module = GetModuleHandleW( 0 ); + if (!rsrc) + return 0; + + if (!module) + module = GetModuleHandleW( 0 ); + + /* Only check for an MUI reference if the resource handle value is less than the module value, */ + /* or if an MUI reference was found and the MUI reference and handle value are larger than the */ + /* module value for the executable file. That is a signal that the resource handle is to be */ + /* associated with the MUI file instead of the executable file. */ + + mui_module = get_mui(module); + + if (((HMODULE)rsrc < module) || ((mui_module > module) && ((HMODULE)rsrc > mui_module))) + module = mui_module; + if (!set_ntstatus( LdrAccessResource( module, (IMAGE_RESOURCE_DATA_ENTRY *)rsrc, &ret, NULL ))) return 0; return ret; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10090
participants (2)
-
Craig Schulstad -
Craig Schulstad (@NoDakker)