rfc: mscoree: Use the mono embedding api instead of invoking mono.exe.

Vincent Povirk madewokherd+8cd9 at gmail.com
Fri Apr 2 16:16:53 CDT 2010


This is a patch that has mscoree.dll load mono.dll in-process rather
than starting mono.exe. This is needed so that (among other things),
the running process gets the correct values from GetCommandLine and
GetModuleFileName(0).

The code quality is probably not very good, so I'm sending it to
wine-devel for feedback first.
-------------- next part --------------
From 483da15818d222dc78f5074a7dbfe99882de8228 Mon Sep 17 00:00:00 2001
From: Vincent Povirk <vincent at codeweavers.com>
Date: Fri, 2 Apr 2010 15:33:12 -0500
Subject: [PATCH] mscoree: Use the mono embedding api instead of invoking mono.exe.

---
 dlls/mscoree/Makefile.in       |    2 +-
 dlls/mscoree/mscoree_main.c    |  211 +++++++++++++++++++++++++++++++---------
 dlls/mscoree/mscoree_private.h |   13 +++
 3 files changed, 180 insertions(+), 46 deletions(-)

diff --git a/dlls/mscoree/Makefile.in b/dlls/mscoree/Makefile.in
index 57e9819..c52589e 100644
--- a/dlls/mscoree/Makefile.in
+++ b/dlls/mscoree/Makefile.in
@@ -3,7 +3,7 @@ TOPOBJDIR = ../..
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = mscoree.dll
-IMPORTS   = uuid advapi32 kernel32
+IMPORTS   = uuid advapi32 kernel32 shell32
 
 C_SRCS = \
 	corruntimehost.c \
diff --git a/dlls/mscoree/mscoree_main.c b/dlls/mscoree/mscoree_main.c
index 5b20c85..76fbbe0 100644
--- a/dlls/mscoree/mscoree_main.c
+++ b/dlls/mscoree/mscoree_main.c
@@ -21,11 +21,14 @@
 
 #include <stdarg.h>
 
+#include "wine/unicode.h"
 #include "windef.h"
 #include "winbase.h"
 #include "winuser.h"
+#include "winnls.h"
 #include "winreg.h"
 #include "ole2.h"
+#include "shellapi.h"
 
 #include "initguid.h"
 #include "cor.h"
@@ -36,9 +39,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
 
-static LPWSTR get_mono_exe(void)
+static LPWSTR get_mono_path(DWORD major_version, DWORD minor_version, LPCWSTR subpath)
 {
-    static const WCHAR mono_exe[] = {'b','i','n','\\','m','o','n','o','.','e','x','e',' ',0};
     static const WCHAR mono_key[] = {'S','o','f','t','w','a','r','e','\\','N','o','v','e','l','l','\\','M','o','n','o',0};
     static const WCHAR defaul_clr[] = {'D','e','f','a','u','l','t','C','L','R',0};
     static const WCHAR install_root[] = {'S','d','k','I','n','s','t','a','l','l','R','o','o','t',0};
@@ -74,16 +76,135 @@ static LPWSTR get_mono_exe(void)
     }
     RegCloseKey(key);
 
-    size = len + sizeof(slash) + sizeof(mono_exe);
+    size = len + sizeof(slash) + (lstrlenW(subpath) + 1) * sizeof(WCHAR);
     if (!(ret = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
 
     lstrcpyW(ret, root);
     lstrcatW(ret, slash);
-    lstrcatW(ret, mono_exe);
+    lstrcatW(ret, subpath);
 
     return ret;
 }
 
+static LPWSTR get_mono_exe(void)
+{
+    static const WCHAR mono_exe[] = {'b','i','n','\\','m','o','n','o','.','e','x','e',' ',0};
+
+    return get_mono_path(0, 0, mono_exe);
+}
+
+static CRITICAL_SECTION mono_lib_cs;
+static CRITICAL_SECTION_DEBUG mono_lib_cs_debug =
+{
+    0, 0, &mono_lib_cs,
+    { &mono_lib_cs_debug.ProcessLocksList, 
+      &mono_lib_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": mono_lib_cs") }
+};
+static CRITICAL_SECTION mono_lib_cs = { &mono_lib_cs_debug, -1, 0, 0, 0, 0 };
+
+HMODULE mono_handle;
+
+void (*mono_config_parse)(const char *filename);
+MonoAssembly* (*mono_domain_assembly_open) (MonoDomain *domain, const char *name);
+void (*mono_jit_cleanup)(MonoDomain *domain);
+int (*mono_jit_exec)(MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[]);
+MonoDomain* (*mono_jit_init)(const char *file);
+int (*mono_jit_set_trace_options)(const char* options);
+void (*mono_set_dirs)(const char *assembly_dir, const char *config_dir);
+
+static void set_environment(LPCWSTR bin_path)
+{
+    WCHAR path_env[MAX_PATH];
+    int len;
+
+    static const WCHAR pathW[] = {'P','A','T','H',0};
+
+    /* We have to modify PATH as Mono loads other DLLs from this directory. */
+    GetEnvironmentVariableW(pathW, path_env, sizeof(path_env)/sizeof(WCHAR));
+    len = strlenW(path_env);
+    path_env[len++] = ';';
+    strcpyW(path_env+len, bin_path);
+    SetEnvironmentVariableW(pathW, path_env);
+}
+
+static HMODULE load_mono(void)
+{
+    static const WCHAR mono_dll[] = {'b','i','n','\\','m','o','n','o','.','d','l','l',0};
+    static const WCHAR libmono_dll[] = {'b','i','n','\\','l','i','b','m','o','n','o','.','d','l','l',0};
+    static const WCHAR bin[] = {'b','i','n',0};
+    static const WCHAR lib[] = {'l','i','b',0};
+    static const WCHAR etc[] = {'e','t','c',0};
+    HMODULE result;
+    LPWSTR mono_dll_path=NULL, mono_bin_path=NULL, mono_lib_path=NULL, mono_etc_path=NULL;
+    char mono_lib_path_a[MAX_PATH], mono_etc_path_a[MAX_PATH];
+
+    EnterCriticalSection(&mono_lib_cs);
+
+    if (!mono_handle)
+    {
+        mono_dll_path = get_mono_path(0, 0, mono_dll);
+        if (!mono_dll_path) goto end;
+
+        mono_bin_path = get_mono_path(0, 0, bin);
+        set_environment(mono_bin_path);
+
+        mono_lib_path = get_mono_path(0, 0, lib);
+        mono_etc_path = get_mono_path(0, 0, etc);
+
+        WideCharToMultiByte(CP_UTF8, 0, mono_lib_path, -1, mono_lib_path_a, MAX_PATH, NULL, NULL);
+        WideCharToMultiByte(CP_UTF8, 0, mono_etc_path, -1, mono_etc_path_a, MAX_PATH, NULL, NULL);
+
+        mono_handle = LoadLibraryW(mono_dll_path);
+
+        if (!mono_handle)
+        {
+            HeapFree(GetProcessHeap(), 0, mono_dll_path);
+            mono_dll_path = get_mono_path(0, 0, libmono_dll);
+            mono_handle = LoadLibraryW(mono_dll_path);
+        }
+
+        if (!mono_handle) goto end;
+
+#define LOAD_MONO_FUNCTION(x) do { \
+    x = (void*)GetProcAddress(mono_handle, #x); \
+    if (!x) { \
+        mono_handle = NULL; \
+        goto end; \
+    } \
+} while (0);
+
+        LOAD_MONO_FUNCTION(mono_config_parse);
+        LOAD_MONO_FUNCTION(mono_domain_assembly_open);
+        LOAD_MONO_FUNCTION(mono_jit_cleanup);
+        LOAD_MONO_FUNCTION(mono_jit_exec);
+        LOAD_MONO_FUNCTION(mono_jit_init);
+        LOAD_MONO_FUNCTION(mono_jit_set_trace_options);
+        LOAD_MONO_FUNCTION(mono_set_dirs);
+
+#undef LOAD_MONO_FUNCTION
+
+        mono_set_dirs(mono_lib_path_a, mono_etc_path_a);
+
+        mono_config_parse(NULL);
+    }
+
+end:
+    HeapFree(GetProcessHeap(), 0, mono_dll_path);
+    HeapFree(GetProcessHeap(), 0, mono_bin_path);
+    HeapFree(GetProcessHeap(), 0, mono_lib_path);
+    HeapFree(GetProcessHeap(), 0, mono_etc_path);
+
+    result = mono_handle;
+
+    LeaveCriticalSection(&mono_lib_cs);
+
+    if (!result)
+        MESSAGE("wine: Install the Windows version of Mono to run .NET executables\n");
+
+    return result;
+}
+
 HRESULT WINAPI CorBindToRuntimeHost(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor,
                                     LPCWSTR pwszHostConfigFile, VOID *pReserved,
                                     DWORD startupFlags, REFCLSID rclsid,
@@ -138,68 +259,68 @@ BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
     return TRUE;
 }
 
-__int32 WINAPI _CorExeMain(void)
+static void get_utf8_args(int *argc, char ***argv)
 {
-    STARTUPINFOW si;
-    PROCESS_INFORMATION pi;
-    WCHAR *mono_exe, *cmd_line;
-    DWORD size, exit_code;
-    static const WCHAR WINE_MONO_TRACE[]={'W','I','N','E','_','M','O','N','O','_','T','R','A','C','E',0};
-    static const WCHAR trace_switch_start[]={'"','-','-','t','r','a','c','e','=',0};
-    static const WCHAR trace_switch_end[]={'"',' ',0};
-    int trace_size;
-    WCHAR trace_setting[256];
+    WCHAR **argvw;
+    int size=0, i;
+    char *current_arg;
 
-    if (!(mono_exe = get_mono_exe()))
+    argvw = CommandLineToArgvW(GetCommandLineW(), argc);
+
+    for (i=0; i<*argc; i++)
     {
-        MESSAGE("install the Windows version of Mono to run .NET executables\n");
-        return -1;
+        size += sizeof(char*);
+        size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
     }
+    size += sizeof(char*);
 
-    trace_size = GetEnvironmentVariableW(WINE_MONO_TRACE, trace_setting, sizeof(trace_setting)/sizeof(WCHAR));
+    *argv = HeapAlloc(GetProcessHeap(), 0, size);
+    current_arg = (char*)(*argv + *argc + 1);
 
-    size = (lstrlenW(mono_exe) + lstrlenW(GetCommandLineW()) + 1) * sizeof(WCHAR);
+    for (i=0; i<*argc; i++)
+    {
+        (*argv)[i] = current_arg;
+        current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
+    }
 
-    if (trace_size)
-        size += (trace_size + lstrlenW(trace_switch_start) + lstrlenW(trace_switch_end)) * sizeof(WCHAR);
+    (*argv)[*argc] = NULL;
+
+    HeapFree(GetProcessHeap(), 0, argvw);
+}
 
-    if (!(cmd_line = HeapAlloc(GetProcessHeap(), 0, size)))
+__int32 WINAPI _CorExeMain(void)
+{
+    int exit_code;
+    int trace_size;
+    char trace_setting[256];
+    int argc;
+    char **argv;
+    MonoDomain *domain;
+    MonoAssembly *assembly;
+
+    if (!load_mono())
     {
-        HeapFree(GetProcessHeap(), 0, mono_exe);
         return -1;
     }
 
-    lstrcpyW(cmd_line, mono_exe);
-    HeapFree(GetProcessHeap(), 0, mono_exe);
+    get_utf8_args(&argc, &argv);
+
+    trace_size = GetEnvironmentVariableA("WINE_MONO_TRACE", trace_setting, sizeof(trace_setting)/sizeof(WCHAR));
 
     if (trace_size)
     {
-        lstrcatW(cmd_line, trace_switch_start);
-        lstrcatW(cmd_line, trace_setting);
-        lstrcatW(cmd_line, trace_switch_end);
+        mono_jit_set_trace_options(trace_setting);
     }
 
-    lstrcatW(cmd_line, GetCommandLineW());
-
-    TRACE("new command line: %s\n", debugstr_w(cmd_line));
+    domain = mono_jit_init(argv[0]);
 
-    memset(&si, 0, sizeof(si));
-    si.cb = sizeof(si);
-    if (!CreateProcessW(NULL, cmd_line, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
-    {
-        HeapFree(GetProcessHeap(), 0, cmd_line);
-        return -1;
-    }
-    HeapFree(GetProcessHeap(), 0, cmd_line);
+    assembly = mono_domain_assembly_open(domain, argv[0]);
 
-    /* wait for the process to exit */
-    WaitForSingleObject(pi.hProcess, INFINITE);
-    GetExitCodeProcess(pi.hProcess, &exit_code);
+    exit_code = mono_jit_exec(domain, assembly, argc, argv);
 
-    CloseHandle(pi.hThread);
-    CloseHandle(pi.hProcess);
+    mono_jit_cleanup(domain);
 
-    return (int)exit_code;
+    return exit_code;
 }
 
 __int32 WINAPI _CorExeMain2(PBYTE ptrMemory, DWORD cntMemory, LPWSTR imageName, LPWSTR loaderName, LPWSTR cmdLine)
diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h
index f329455..f14da1d 100644
--- a/dlls/mscoree/mscoree_private.h
+++ b/dlls/mscoree/mscoree_private.h
@@ -22,5 +22,18 @@
 
 extern IUnknown* create_corruntimehost(void);
 
+/* Mono 2.6 embedding */
+typedef struct _MonoDomain MonoDomain;
+typedef struct _MonoAssembly MonoAssembly;
+
+extern HMODULE mono_handle;
+
+extern void (*mono_config_parse)(const char *filename);
+extern MonoAssembly* (*mono_domain_assembly_open) (MonoDomain *domain, const char *name);
+extern void (*mono_jit_cleanup)(MonoDomain *domain);
+extern int (*mono_jit_exec)(MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[]);
+extern MonoDomain* (*mono_jit_init)(const char *file);
+extern int (*mono_jit_set_trace_options)(const char* options);
+extern void (*mono_set_dirs)(const char *assembly_dir, const char *config_dir);
 
 #endif   /* __MSCOREE_PRIVATE__ */
-- 
1.6.3.3


More information about the wine-devel mailing list