[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