mscoree: Invoke installed win32 mono runtime or exec mono native for .NET executables (try 4)

Paul Chitescu paulc at voip.null.ro
Mon Oct 9 15:30:08 CDT 2006


Changelog: mscoree: Invoke installed win32 mono runtime or exec mono native 
for .NET executables.

The code is inspired by the one in winebrowser.

Several alternatives can be provided in Registry, separated by commas. For 
each an attempt to execute it (spawnvp with OVERLAY flag set). The exception 
is the keyword MONOEMBED that will try to locate and dynamically load an 
installed Win32 mono.

The Registry key used is:

[HKCU\Software\Wine\mscoree]
"Runtimes"="MONOEMBED,/usr/bin/mono,mono"

Setting the "Runtimes" value to an empty string will disable this feature and 
render .NET executables unrunable.

By default MONOEMBED is preferred as it seems to provide best compatibility 
and integration with Wine. It requires a proper installation of mono Win32 
and finds its location from Registry.

This is the 4th version of the patch. Thanks Hans Leidekker for pointing out 
some bugs.

Paul
-------------- next part --------------
--- ./dlls/mscoree/mscoree_main.c.orig	2006-10-06 21:38:15.000000000 +0300
+++ ./dlls/mscoree/mscoree_main.c	2006-10-09 21:42:12.000000000 +0300
@@ -19,15 +19,101 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <stdarg.h>
+#include "config.h"
+#include "wine/port.h"
+#include "wine/library.h"
+#include "wine/debug.h"
 
 #include "windef.h"
 #include "winbase.h"
+#include "winreg.h"
 
-#include "wine/debug.h"
+#include <stdarg.h>
+#include <errno.h>
+
+#include "mscoree_priv.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
 
+/* Prefer win32 embedded mono, then native mono from standard dir, then mono from $PATH */
+static const char defaultRuntimes[] = "MONOEMBED,/usr/bin/mono,mono";
+
+static int runMain()
+{
+    char runtimes[256];
+    char* item;
+    int argc, rval, i;
+    const char* *argv;
+    DWORD length;
+    HKEY key = 0;
+
+    /* this code is adapted from winebrowser */
+    length = sizeof(runtimes);
+    /* @@ Wine registry key: HKCU\Software\Wine\mscoree */
+    if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\mscoree", 0, NULL,
+		       REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, NULL) != ERROR_SUCCESS)
+    {
+	WARN("Could not create config Registry key.\n");
+	strcpy(runtimes,defaultRuntimes);
+    }
+    else
+    {
+	DWORD type = 0;
+	if (RegQueryValueExA(key, "Runtimes", 0, &type, (LPBYTE)runtimes, &length) != ERROR_SUCCESS)
+	{
+	    RegSetValueExA(key, "Runtimes", 0, REG_SZ, (LPBYTE)defaultRuntimes,
+			   lstrlenA(defaultRuntimes)+1);
+	    strcpy(runtimes,defaultRuntimes);
+	}
+	RegCloseKey(key);
+    }
+    if (!runtimes[0])
+    {
+	WARN("Runtimes are disabled from Registry.\n");
+	return ENOSYS;
+    }
+    /* allocate an array with space for one extra argument */
+    argc = __wine_main_argc+1;
+    argv = (const char**)HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(char*));
+    if (!argv)
+    {
+	ERR("Could not allocate memory!\n");
+	return ENOMEM;
+    }
+    for (i = 0; i < argc; i++)
+	argv[i+1] = __wine_main_argv[i];
+    argv[argc] = NULL;
+    rval = -1;
+    for (item = strtok(runtimes, ","); item; item = strtok(NULL, ","))
+    {
+	if (!item[0])
+	    continue;
+	TRACE("Attempting to use: %s\n", debugstr_a(item));
+	argv[0] = NULL;
+	if (strcmp(item, "MONOEMBED") == 0)
+	{
+	    /* try to call win32 mono runtime */
+	    rval = MONO_CorExeMain(argc, argv);
+	    if (rval >= 0)
+		break;
+	}
+	else
+	{
+	    argv[0] = item;
+	    spawnvp(_P_OVERLAY, item, argv);
+	    /* if we reach this point exec() failed */
+	    rval = -1;
+	}
+    }
+    HeapFree(GetProcessHeap(), 0, argv);
+    if (rval < 0)
+    {
+	ERR("No suitable runtime could be started.\n");
+	rval = ENOSYS;
+    }
+    return rval;
+}
+
 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 {
     TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
@@ -62,14 +148,13 @@
 
 int WINAPI _CorExeMain(void)
 {
-    FIXME("Directly running .NET applications not supported.\n");
-    return -1;
+    TRACE("\n");
+    return runMain();
 }
 
 int WINAPI _CorExeMain2(PBYTE ptrMemory, DWORD cntMemory, LPCWSTR imageName, LPCWSTR loaderName, LPCWSTR cmdLine)
 {
-    TRACE("(%p, %u, %s, %s, %s)\n", ptrMemory, cntMemory, debugstr_w(imageName), debugstr_w(loaderName), debugstr_w(cmdLine));
-    FIXME("Directly running .NET applications not supported.\n");
+    FIXME("(%p, %u, %s, %s, %s): stub\n", ptrMemory, cntMemory, debugstr_w(imageName), debugstr_w(loaderName), debugstr_w(cmdLine));
     return -1;
 }
 
--- ./dlls/mscoree/mscoree_mono.c.orig	2006-10-07 19:48:18.000000000 +0300
+++ ./dlls/mscoree/mscoree_mono.c	2006-10-09 23:19:31.000000000 +0300
@@ -0,0 +1,161 @@
+/*
+ * Embed installed win32 mono for .NET applications
+ * Copyright 2006 Paul Chitescu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+#include "wine/library.h"
+#include "wine/debug.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+
+#include <stdarg.h>
+
+#include "mscoree_priv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
+
+typedef void (*MonoDirs)(const char*,const char*);
+typedef int (*MonoMain)(int,char*[]);
+
+static const char* monoKey(void)
+{
+    static char buffer[256] = "Software\\Novell\\Mono";
+    static int init = 0;
+    HKEY key = 0;
+    if (init)
+	return buffer[0] ? buffer : NULL;
+    init = 1;
+    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &key) == ERROR_SUCCESS)
+    {
+	DWORD type = 0;
+	int pos = lstrlenA(buffer);
+	DWORD length = sizeof(buffer) - pos - 2;
+	if (RegQueryValueExA(key, "DefaultCLR", 0, &type,
+			     (LPBYTE)(buffer + pos + 1), &length) == ERROR_SUCCESS)
+	    buffer[pos] = '\\';
+	else
+	    buffer[0] = '\0';		
+	RegCloseKey(key);
+    }
+    else
+	buffer[0] = '\0';
+    TRACE("Mono registry path: %s\n", debugstr_a(buffer));
+    return buffer[0] ? buffer : NULL;
+}
+
+int MONO_CorExeMain(int argc,const char* argv[])
+{
+    HINSTANCE lib;
+    int rval = -1;
+    HKEY key = 0;
+    DWORD type = 0;
+
+    char buf1[MAX_PATH], buf2[MAX_PATH];
+    char* p = 0;
+    DWORD length = sizeof(buf1) - 1 - 16;
+
+    const char* keyName = monoKey();
+    if (!keyName)
+	return -1;
+    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key) != ERROR_SUCCESS)
+	return -1;
+    if (RegQueryValueExA(key, "FrameworkAssemblyDirectory", 0, &type,
+			 (LPBYTE)buf1, &length) == ERROR_SUCCESS)
+    {
+	p = strrchr(buf1, '\\');
+	if (!p)
+	    p = strrchr(buf1, '/');
+	if (p) {
+	    const char binPath[] = "\\bin";
+	    strcpy(p, binPath);
+	    /* leave p pointing at the terminating NULL */ 
+	    p += lstrlenA(binPath);
+	}
+    }
+    if (!p)
+    {
+	RegCloseKey(key);
+	return -1;
+    }
+
+    TRACE("Mono lib directory: %s\n", debugstr_a(buf1));
+    /* remember current directory to set it back */
+    length = sizeof(buf2);
+    if (GetCurrentDirectoryA(length, buf2) >= length)
+    {
+	RegCloseKey(key);
+	return -1;
+    }
+    /* set current directory so we can find mono's DLLs */
+    SetCurrentDirectoryA(buf1);
+    strcpy(p, "\\mono.dll");
+    lib = LoadLibraryA(buf1);
+    if (!lib)
+    {
+	strcpy(p, "\\mono-1.dll");
+	lib = LoadLibraryA(buf1);
+    }
+    if (!lib)
+    {
+	strcpy(p, "\\mono-2.dll");
+	lib = LoadLibraryA(buf1);
+    }
+    /* and change it back after we eventually loaded them */
+    SetCurrentDirectoryA(buf2);
+    if (lib)
+    {
+	MonoDirs monoDirs = (MonoDirs)GetProcAddress(lib, "mono_set_dirs");
+	MonoMain monoMain = (MonoMain)GetProcAddress(lib, "mono_main");
+	if (monoDirs && monoMain)
+	{
+	    TRACE("Using runtime: %s\n", debugstr_a(buf1));
+	    length = sizeof(buf1) - 1;
+	    if (RegQueryValueExA(key, "FrameworkAssemblyDirectory", 0, &type,
+				 (LPBYTE)buf1, &length) != ERROR_SUCCESS)
+		buf1[0] = '\0';
+	    length = sizeof(buf2) - 1;
+	    if (RegQueryValueExA(key, "MonoConfigDir", 0, &type,
+				 (LPBYTE)buf2, &length) != ERROR_SUCCESS)
+		buf2[0] = '\0';
+	    RegCloseKey(key);
+	    if (buf1[0] && buf2[0])
+	    {
+		TRACE("Calling mono with lib=%s cfg=%s\n",
+		      debugstr_a(buf1), debugstr_a(buf2));
+		argv[0] = argv[1];
+		monoDirs(buf1, buf2);
+		rval = monoMain(argc, (char**)argv);
+	    }
+	    else
+		ERR("Mono configuration is incomplete!\n");
+	}
+	else
+	{
+	    ERR("Could not locate mono entry points in %s\n", debugstr_a(buf1));
+	    RegCloseKey(key);
+	}
+	FreeLibrary(lib);
+    }
+    else
+	RegCloseKey(key);
+
+    return rval;
+}
--- ./dlls/mscoree/Makefile.in.orig	2006-10-06 21:38:15.000000000 +0300
+++ ./dlls/mscoree/Makefile.in	2006-10-09 21:41:26.000000000 +0300
@@ -3,10 +3,11 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = mscoree.dll
-IMPORTS   = kernel32
+IMPORTS   = kernel32 advapi32
 
 C_SRCS = \
-	mscoree_main.c
+	mscoree_main.c \
+	mscoree_mono.c
 
 @MAKE_DLL_RULES@
 
--- ./dlls/mscoree/mscoree_priv.h.orig	2006-10-07 20:02:22.000000000 +0300
+++ ./dlls/mscoree/mscoree_priv.h	2006-10-08 04:18:12.000000000 +0300
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2006 Paul Chitescu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+extern int MONO_CorExeMain(int argc,const char* argv[]);


More information about the wine-patches mailing list