[PATCH 2/2] regsvr32: Re-exec as 32-bit or 64-bit if necessary.

Vincent Povirk vincent at codeweavers.com
Sun Sep 22 20:06:23 CDT 2019


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47075
Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
---
 programs/regsvr32/Makefile.in |   2 +-
 programs/regsvr32/regsvr32.c  | 158 ++++++++++++++++++++++++++++++++++
 2 files changed, 159 insertions(+), 1 deletion(-)

diff --git a/programs/regsvr32/Makefile.in b/programs/regsvr32/Makefile.in
index d8aee0ea66..51a03bf3a2 100644
--- a/programs/regsvr32/Makefile.in
+++ b/programs/regsvr32/Makefile.in
@@ -1,5 +1,5 @@
 MODULE    = regsvr32.exe
-IMPORTS   = ole32 user32
+IMPORTS   = ole32 shlwapi user32
 
 EXTRADLLFLAGS = -mwindows -municode -mno-cygwin
 
diff --git a/programs/regsvr32/regsvr32.c b/programs/regsvr32/regsvr32.c
index 77a839e475..85c539309a 100644
--- a/programs/regsvr32/regsvr32.c
+++ b/programs/regsvr32/regsvr32.c
@@ -25,6 +25,7 @@
 #include <windows.h>
 #include <ole2.h>
 #include "regsvr32.h"
+#include "shlwapi.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(regsvr32);
@@ -211,6 +212,145 @@ static WCHAR *parse_command_line(WCHAR *command_line)
     return NULL;
 }
 
+static LPCWSTR find_arg_start(LPCWSTR cmdline)
+{
+    LPCWSTR s;
+    BOOL in_quotes;
+    int bcount;
+
+    bcount=0;
+    in_quotes=FALSE;
+    s=cmdline;
+    while (1) {
+        if (*s==0 || ((*s=='\t' || *s==' ') && !in_quotes)) {
+            /* end of this command line argument */
+            break;
+        } else if (*s=='\\') {
+            /* '\', count them */
+            bcount++;
+        } else if ((*s=='"') && ((bcount & 1)==0)) {
+            /* unescaped '"' */
+            in_quotes=!in_quotes;
+            bcount=0;
+        } else {
+            /* a regular character */
+            bcount=0;
+        }
+        s++;
+    }
+    return s;
+}
+
+static void reexec_self(BOOL as_64bit)
+{
+    static const WCHAR exe_name[] = {'\\','r','e','g','s','v','r','3','2','.','e','x','e',0};
+    static const WCHAR sysnative[] = {'\\','S','y','s','N','a','t','i','v','e',0};
+    WCHAR systemdir[MAX_PATH];
+    LPCWSTR args;
+    WCHAR *cmdline;
+    STARTUPINFOW si = {0};
+    PROCESS_INFORMATION pi;
+
+    TRACE("restarting %s\n", as_64bit ? "as 64-bit" : "as 32-bit");
+
+    if (as_64bit)
+    {
+        GetWindowsDirectoryW(systemdir, MAX_PATH);
+        wcscat(systemdir, sysnative);
+    }
+    else
+    {
+        GetSystemWow64DirectoryW(systemdir, MAX_PATH);
+    }
+
+    args = find_arg_start(GetCommandLineW());
+
+    cmdline = HeapAlloc(GetProcessHeap(), 0,
+        (wcslen(systemdir)+wcslen(exe_name)+wcslen(args)+1)*sizeof(WCHAR));
+
+    wcscpy(cmdline, systemdir);
+    wcscat(cmdline, exe_name);
+    wcscat(cmdline, args);
+
+    si.cb = sizeof(si);
+
+    if (CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
+    {
+        DWORD exit_code;
+        WaitForSingleObject(pi.hProcess, INFINITE);
+        GetExitCodeProcess(pi.hProcess, &exit_code);
+        ExitProcess(exit_code);
+    }
+    else
+    {
+        WINE_TRACE("failed to restart, err=%d\n", GetLastError());
+    }
+
+    HeapFree(GetProcessHeap(), 0, cmdline);
+}
+
+static WORD get_image_type(LPCWSTR image_name)
+{
+    HANDLE file;
+    IMAGE_DOS_HEADER dos_header;
+    IMAGE_NT_HEADERS nt_headers;
+    DWORD bytes_read;
+    WORD result;
+
+    if (PathIsRelativeW(image_name))
+    {
+        /* There's no reliable way to find the actual file. */
+        return 0;
+    }
+
+    file = CreateFileW(image_name, GENERIC_READ, FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
+        NULL, OPEN_EXISTING, 0, NULL);
+    if (file == INVALID_HANDLE_VALUE)
+    {
+        WINE_TRACE("unable to open %s for reading, err=%d\n", wine_dbgstr_wn(image_name, -1), GetLastError());
+        return 0;
+    }
+
+    if (!ReadFile(file, &dos_header, sizeof(dos_header), &bytes_read, NULL) ||
+        bytes_read != sizeof(dos_header) ||
+        dos_header.e_magic != IMAGE_DOS_SIGNATURE)
+    {
+        WINE_TRACE("unable to read dos header from %s\n", wine_dbgstr_wn(image_name, -1));
+        CloseHandle(file);
+        return 0;
+    }
+
+    SetFilePointer(file, dos_header.e_lfanew, NULL, FILE_BEGIN);
+
+    if (!ReadFile(file, &nt_headers, sizeof(nt_headers), &bytes_read, NULL) ||
+        bytes_read < 6) /* enough to read magic and machine architecture */
+    {
+        WINE_TRACE("unable to read extended header from %s\n", wine_dbgstr_wn(image_name, -1));
+        CloseHandle(file);
+        return 0;
+    }
+
+    if (((IMAGE_OS2_HEADER*)&nt_headers)->ne_magic == IMAGE_OS2_SIGNATURE)
+    {
+        WINE_TRACE("%s is an NE (16-bit) image\n", wine_dbgstr_wn(image_name, -1));
+        result = IMAGE_OS2_SIGNATURE;
+    }
+    else if (nt_headers.Signature == IMAGE_NT_SIGNATURE)
+    {
+        result = nt_headers.FileHeader.Machine;
+        WINE_TRACE("%s is a PE image with machine 0x%x\n", wine_dbgstr_wn(image_name, -1), result);
+    }
+    else
+    {
+        WINE_TRACE("%s is an image with an unrecognized extended header\n", wine_dbgstr_wn(image_name, -1));
+        result = 0;
+    }
+
+    CloseHandle(file);
+
+    return result;
+}
+
 int wmain(int argc, WCHAR* argv[])
 {
     int             i, res, ret = 0;
@@ -280,6 +420,24 @@ int wmain(int argc, WCHAR* argv[])
             WCHAR *DllName = argv[i];
             res = 0;
 
+            if (!DllFound)
+            {
+                /* Re-exec with another architecture if necessary. */
+                WORD dll_type = get_image_type(DllName);
+
+#ifdef __i386__
+                if (dll_type == IMAGE_FILE_MACHINE_AMD64) {
+                    BOOL is_wow64;
+                    if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)
+                        reexec_self(TRUE);
+                }
+#endif
+#ifdef __x86_64__
+                if (dll_type == IMAGE_FILE_MACHINE_I386)
+                    reexec_self(FALSE);
+#endif
+            }
+
             DllFound = TRUE;
             if (CallInstall && Unregister)
                 res = InstallDll(!Unregister, DllName, wsCommandLine);
-- 
2.20.1




More information about the wine-devel mailing list