Vincent Povirk : regsvr32: Re-exec as 32-bit or 64-bit if necessary.
Alexandre Julliard
julliard at winehq.org
Mon Apr 20 15:01:49 CDT 2020
Module: wine
Branch: oldstable
Commit: b9ded7e8710e469728c70e113e606fbed487bf34
URL: https://source.winehq.org/git/wine.git/?a=commit;h=b9ded7e8710e469728c70e113e606fbed487bf34
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>
(cherry picked from commit e90cca8e7a429c58076262626b8bb4d3f4f2c5c5)
Conflicts:
programs/regsvr32/regsvr32.c
Signed-off-by: Michael Stefaniuc <mstefani 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 cfbb80d465..5adf21976b 100644
--- a/programs/regsvr32/regsvr32.c
+++ b/programs/regsvr32/regsvr32.c
@@ -88,6 +88,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);
+ lstrcatW(systemdir, sysnative);
+#endif
+
+ args = find_arg_start(GetCommandLineW());
+
+ cmdline = HeapAlloc(GetProcessHeap(), 0,
+ (lstrlenW(systemdir)+lstrlenW(exe_name)+lstrlenW(args)+1)*sizeof(WCHAR));
+
+ lstrcpyW(cmdline, systemdir);
+ lstrcatW(cmdline, exe_name);
+ lstrcatW(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.
*
@@ -95,14 +186,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);
}
@@ -116,13 +215,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;
@@ -139,13 +238,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;
@@ -162,13 +261,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;
@@ -283,11 +382,12 @@ int 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)
@@ -299,9 +399,9 @@ int 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)
@@ -311,7 +411,7 @@ int 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