From: Craig Schulstad <craigaschulstad@gmail.com> When an application relies upon language specific resources, search for an associated language specific subfolder and subsequent mui file. --- dlls/kernelbase/loader.c | 183 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 173 insertions(+), 10 deletions(-) diff --git a/dlls/kernelbase/loader.c b/dlls/kernelbase/loader.c index f4e1ca2e23a..d5fc62385c6 100644 --- a/dlls/kernelbase/loader.c +++ b/dlls/kernelbase/loader.c @@ -46,6 +46,11 @@ struct exclusive_datafile }; static struct list exclusive_datafile_list = LIST_INIT( exclusive_datafile_list ); +static WCHAR mui_locale[LOCALE_NAME_MAX_LENGTH]; +static BOOL locale_found = FALSE; +static BOOL recursion_flag = FALSE; +static HMODULE module_mui = NULL; + static CRITICAL_SECTION exclusive_datafile_list_section; static CRITICAL_SECTION_DEBUG critsect_debug = { @@ -1056,10 +1061,115 @@ BOOL WINAPI DECLSPEC_HOTPATCH EnumResourceTypesExW( HMODULE module, ENUMRESTYPEP } -/********************************************************************** - * FindResourceExW (kernelbase.@) - */ -HRSRC WINAPI DECLSPEC_HOTPATCH FindResourceExW( HMODULE module, LPCWSTR type, LPCWSTR name, WORD lang ) +/***********************************************************************/ +/* get_mui - Acquire an MUI module for the associated resource */ +/***********************************************************************/ + +HMODULE get_mui(HMODULE module) +{ + WCHAR module_name[MAX_PATH], mui_name[MAX_PATH]; + HMODULE mui_module = NULL; + INT i, j = 0, k = 0, l = 0; + LONG save_error = GetLastError(); + + /* Initialize the work strings */ + + for (i = 0; i < MAX_PATH; i++) { + module_name[i] = 0; + mui_name[i] = 0; + } + + /* Acquire the base resource file name */ + + if (!(GetModuleFileNameW(module, module_name, MAX_PATH))) { + TRACE ("Module file name was not found - returning with source module\n"); + SetLastError(save_error); + return module; + } + + /* Stay with the original module reference if this file is not an executable file. */ + + if (!(wcsstr(module_name, L".exe"))) + return module; + + 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. */ + + 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. */ + + 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); + + SetLastError(save_error); + + if (mui_module != NULL) { + module_mui = mui_module; + return mui_module; + } else { + module_mui = NULL; + return module; + } + +} + +/***********************************************************************/ +/* get_res_handle - Isolated call of the LdrFindResource function */ +/***********************************************************************/ + +HRSRC get_res_handle(HMODULE module, LPCWSTR type, LPCWSTR name, WORD lang) + { NTSTATUS status; UNICODE_STRING nameW, typeW; @@ -1068,7 +1178,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 @@ -1077,10 +1186,11 @@ HRSRC WINAPI DECLSPEC_HOTPATCH FindResourceExW( HMODULE module, LPCWSTR type, LP if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS) goto done; info.Type = (ULONG_PTR)typeW.Buffer; info.Name = (ULONG_PTR)nameW.Buffer; - info.Language = lang; + info.Language = lang; status = LdrFindResource_U( module, &info, 3, &entry ); done: - if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) ); + if (status != STATUS_SUCCESS) + SetLastError( RtlNtStatusToDosError(status) ); } __EXCEPT_PAGE_FAULT { @@ -1090,10 +1200,49 @@ 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; + HMODULE work_module = NULL, test_module = NULL; + + if (!module) module = GetModuleHandleW( 0 ); + + work_module = GetModuleHandleW( 0 ); + + if (module != work_module) { + rsrc = get_res_handle(module, type, name, lang); + module_mui = NULL; + } else { + test_module = get_mui(module); + if (test_module == module) { + rsrc = get_res_handle(module, type, name, lang); + module_mui = NULL; + } else { + rsrc = get_res_handle(test_module, type, name, lang); + + if (!rsrc) { + TRACE("Fallback from MUI to base module: %p %p %s %s\n", test_module, module, debugstr_w(type), debugstr_w(name)); + rsrc = get_res_handle(module, type, name, lang); + module_mui = NULL; + } + } + } + + return rsrc; + +} + + + /********************************************************************** * FindResourceW (kernelbase.@) */ @@ -1118,14 +1267,28 @@ BOOL WINAPI DECLSPEC_HOTPATCH FreeResource( HGLOBAL handle ) HGLOBAL WINAPI DECLSPEC_HOTPATCH LoadResource( HINSTANCE module, HRSRC rsrc ) { void *ret; - - TRACE( "%p %p\n", module, rsrc ); + HMODULE work_module = NULL; if (!rsrc) return 0; if (!module) module = GetModuleHandleW( 0 ); - if (!set_ntstatus( LdrAccessResource( module, (IMAGE_RESOURCE_DATA_ENTRY *)rsrc, &ret, NULL ))) + work_module = module; + + /* Check for and use a MUI module */ + + if (module_mui != NULL) { + if (((HMODULE)rsrc < module) || ((module_mui > module) && ((HMODULE)rsrc > module_mui))) + work_module = module_mui; + } + + /* Ready this handle for next resource retrieval */ + + module_mui= NULL; + + if (!set_ntstatus( LdrAccessResource( work_module, (IMAGE_RESOURCE_DATA_ENTRY *)rsrc, &ret, NULL ))) return 0; + return ret; + } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10365