Vincent Povirk : regsvr32: Re-exec as 32-bit or 64-bit if necessary.

Alexandre Julliard julliard at winehq.org
Mon Oct 21 15:28:39 CDT 2019


Module: wine
Branch: master
Commit: e90cca8e7a429c58076262626b8bb4d3f4f2c5c5
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=e90cca8e7a429c58076262626b8bb4d3f4f2c5c5

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Fri Oct 18 15:46:34 2019 -0500

regsvr32: Re-exec as 32-bit or 64-bit if necessary.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47075
Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 programs/regsvr32/regsvr32.c | 122 +++++++++++++++++++++++++++++++++++++++----
 1 file changed, 111 insertions(+), 11 deletions(-)

diff --git a/programs/regsvr32/regsvr32.c b/programs/regsvr32/regsvr32.c
index 4aa3f7d5c1..a7fb12e0fc 100644
--- a/programs/regsvr32/regsvr32.c
+++ b/programs/regsvr32/regsvr32.c
@@ -83,6 +83,97 @@ static void WINAPIV output_write(UINT id, ...)
     LocalFree(str);
 }
 
+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(void)
+{
+    /* restart current process as 32-bit or 64-bit with same command line */
+    static const WCHAR exe_name[] = {'\\','r','e','g','s','v','r','3','2','.','e','x','e',0};
+#ifndef _WIN64
+    static const WCHAR sysnative[] = {'\\','S','y','s','N','a','t','i','v','e',0};
+    BOOL wow64;
+#endif
+    WCHAR systemdir[MAX_PATH];
+    LPCWSTR args;
+    WCHAR *cmdline;
+    STARTUPINFOW si = {0};
+    PROCESS_INFORMATION pi;
+
+#ifdef _WIN64
+    TRACE("restarting as 32-bit\n");
+    GetSystemWow64DirectoryW(systemdir, MAX_PATH);
+#else
+    TRACE("restarting as 64-bit\n");
+
+    if (!IsWow64Process(GetCurrentProcess(), &wow64) || !wow64)
+    {
+        TRACE("not running in wow64, can't restart as 64-bit\n");
+        return;
+    }
+
+    GetWindowsDirectoryW(systemdir, MAX_PATH);
+    wcscat(systemdir, sysnative);
+#endif
+
+    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);
+}
+
+#ifdef _WIN64
+# define ALT_BINARY_TYPE SCS_32BIT_BINARY
+#else
+# define ALT_BINARY_TYPE SCS_64BIT_BINARY
+#endif
+
 /**
  * Loads procedure.
  *
@@ -90,14 +181,22 @@ static void WINAPIV output_write(UINT id, ...)
  * strDll - name of the dll.
  * procName - name of the procedure to load from the dll.
  * DllHandle - a variable that receives the handle of the loaded dll.
+ * firstDll - true if this is the first dll in the command line.
  */
-static VOID *LoadProc(const WCHAR* strDll, const char* procName, HMODULE* DllHandle)
+static VOID *LoadProc(const WCHAR* strDll, const char* procName, HMODULE* DllHandle, BOOL firstDll)
 {
     VOID* (*proc)(void);
 
     *DllHandle = LoadLibraryExW(strDll, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
     if(!*DllHandle)
     {
+        DWORD binary_type;
+        if (firstDll && GetLastError() == ERROR_BAD_EXE_FORMAT &&
+            GetBinaryTypeW(strDll, &binary_type) &&
+            binary_type == ALT_BINARY_TYPE)
+        {
+            reexec_self();
+        }
         output_write(STRING_DLL_LOAD_FAILED, strDll);
         ExitProcess(LOADLIBRARY_FAILED);
     }
@@ -111,13 +210,13 @@ static VOID *LoadProc(const WCHAR* strDll, const char* procName, HMODULE* DllHan
     return proc;
 }
 
-static int RegisterDll(const WCHAR* strDll)
+static int RegisterDll(const WCHAR* strDll, BOOL firstDll)
 {
     HRESULT hr;
     DLLREGISTER pfRegister;
     HMODULE DllHandle = NULL;
 
-    pfRegister = LoadProc(strDll, "DllRegisterServer", &DllHandle);
+    pfRegister = LoadProc(strDll, "DllRegisterServer", &DllHandle, firstDll);
     if (!pfRegister)
         return GETPROCADDRESS_FAILED;
 
@@ -134,13 +233,13 @@ static int RegisterDll(const WCHAR* strDll)
     return 0;
 }
 
-static int UnregisterDll(const WCHAR* strDll)
+static int UnregisterDll(const WCHAR* strDll, BOOL firstDll)
 {
     HRESULT hr;
     DLLUNREGISTER pfUnregister;
     HMODULE DllHandle = NULL;
 
-    pfUnregister = LoadProc(strDll, "DllUnregisterServer", &DllHandle);
+    pfUnregister = LoadProc(strDll, "DllUnregisterServer", &DllHandle, firstDll);
     if (!pfUnregister)
         return GETPROCADDRESS_FAILED;
 
@@ -157,13 +256,13 @@ static int UnregisterDll(const WCHAR* strDll)
     return 0;
 }
 
-static int InstallDll(BOOL install, const WCHAR *strDll, const WCHAR *command_line)
+static int InstallDll(BOOL install, const WCHAR *strDll, const WCHAR *command_line, BOOL firstDll)
 {
     HRESULT hr;
     DLLINSTALL pfInstall;
     HMODULE DllHandle = NULL;
 
-    pfInstall = LoadProc(strDll, "DllInstall", &DllHandle);
+    pfInstall = LoadProc(strDll, "DllInstall", &DllHandle, firstDll);
     if (!pfInstall)
         return GETPROCADDRESS_FAILED;
 
@@ -278,11 +377,12 @@ int __cdecl wmain(int argc, WCHAR* argv[])
         if (argv[i])
         {
             WCHAR *DllName = argv[i];
+            BOOL firstDll = !DllFound;
             res = 0;
 
             DllFound = TRUE;
             if (CallInstall && Unregister)
-                res = InstallDll(!Unregister, DllName, wsCommandLine);
+                res = InstallDll(!Unregister, DllName, wsCommandLine, firstDll);
 
             /* The Windows version stops processing the current file on the first error. */
             if (res)
@@ -294,9 +394,9 @@ int __cdecl wmain(int argc, WCHAR* argv[])
             if (!CallInstall || CallRegister)
             {
                 if(Unregister)
-                    res = UnregisterDll(DllName);
+                    res = UnregisterDll(DllName, firstDll);
                 else
-                    res = RegisterDll(DllName);
+                    res = RegisterDll(DllName, firstDll);
             }
 
             if (res)
@@ -306,7 +406,7 @@ int __cdecl wmain(int argc, WCHAR* argv[])
             }
 
             if (CallInstall && !Unregister)
-                res = InstallDll(!Unregister, DllName, wsCommandLine);
+                res = InstallDll(!Unregister, DllName, wsCommandLine, firstDll);
 
             if (res)
             {




More information about the wine-cvs mailing list