[PATCH] kernelbase: Add rudimentary mui resource support to loader.c

Craig Schulstad craigaschulstad at gmail.com
Mon Jan 18 11:12:14 CST 2021


Signed-off-by: Craig Schulstad <craigaschulstad at gmail.com>
---
 dlls/kernelbase/loader.c | 169 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 164 insertions(+), 5 deletions(-)

diff --git a/dlls/kernelbase/loader.c b/dlls/kernelbase/loader.c
index fc9b0ce0083..0fbe9bcd9e8 100644
--- a/dlls/kernelbase/loader.c
+++ b/dlls/kernelbase/loader.c
@@ -48,6 +48,9 @@ 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 = 0;
+static BOOL recursion_flag = 0;
 
 /***********************************************************************
  * Modules
@@ -1011,11 +1014,122 @@ 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". */
+
+    /* Acquire the base resource file name */
+
+    if (!(GetModuleFileNameW(module, module_name, MAX_PATH))) 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 = 1;
+
+        LCIDToLocaleName( GetUserDefaultLCID(), mui_locale, LOCALE_NAME_MAX_LENGTH, 0 );
+
+        recursion_flag = 0;
+
+        locale_found = 1;
+
+    }
+
+    /* 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;
@@ -1024,7 +1138,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
@@ -1046,7 +1159,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;
+
+    }
 }
 
 
@@ -1074,11 +1221,23 @@ BOOL WINAPI DECLSPEC_HOTPATCH FreeResource( HGLOBAL handle )
 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 );
+
+
+    /* 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;
-- 
2.17.1




More information about the wine-devel mailing list