[MSCOREE]
authorAmine Khaldi <amine.khaldi@reactos.org>
Sat, 28 Jan 2012 17:34:24 +0000 (17:34 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sat, 28 Jan 2012 17:34:24 +0000 (17:34 +0000)
* Sync to Wine 1.3.37.

svn path=/trunk/; revision=55276

15 files changed:
reactos/dll/win32/mscoree/CMakeLists.txt
reactos/dll/win32/mscoree/assembly.c [new file with mode: 0644]
reactos/dll/win32/mscoree/config.c [new file with mode: 0644]
reactos/dll/win32/mscoree/cordebug.c [new file with mode: 0644]
reactos/dll/win32/mscoree/corruntimehost.c
reactos/dll/win32/mscoree/metadata.c [new file with mode: 0644]
reactos/dll/win32/mscoree/metahost.c [new file with mode: 0644]
reactos/dll/win32/mscoree/mscoree.rbuild
reactos/dll/win32/mscoree/mscoree.rc [new file with mode: 0644]
reactos/dll/win32/mscoree/mscoree.rgs [new file with mode: 0644]
reactos/dll/win32/mscoree/mscoree.spec
reactos/dll/win32/mscoree/mscoree_main.c
reactos/dll/win32/mscoree/mscoree_private.h
reactos/lib/sdk/uuid/CMakeLists.txt
reactos/media/doc/README.WINE

index 75d41f6..1aab2a6 100644 (file)
@@ -2,11 +2,18 @@
 add_definitions(-D__WINESRC__)
 include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine)
 
+set_rc_compiler()
 spec2def(mscoree.dll mscoree.spec)
 
 list(APPEND SOURCE
+    assembly.c
+    config.c
+    cordebug.c
     corruntimehost.c
+    metadata.c
+    metahost.c
     mscoree_main.c
+    mscoree.rc
     ${CMAKE_CURRENT_BINARY_DIR}/mscoree_stubs.c
     ${CMAKE_CURRENT_BINARY_DIR}/mscoree.def)
 
@@ -14,5 +21,10 @@ add_library(mscoree SHARED ${SOURCE})
 
 set_module_type(mscoree win32dll)
 target_link_libraries(mscoree wine uuid)
-add_importlibs(mscoree advapi32 shell32 msvcrt kernel32 ntdll)
+
+if(MSVC)
+    target_link_libraries(mscoree xml_uuids)
+endif()
+
+add_importlibs(mscoree dbghelp advapi32 shell32 ole32 shlwapi msvcrt kernel32 ntdll)
 add_cd_file(TARGET mscoree DESTINATION reactos/system32 FOR all)
diff --git a/reactos/dll/win32/mscoree/assembly.c b/reactos/dll/win32/mscoree/assembly.c
new file mode 100644 (file)
index 0000000..07723f9
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * assembly parser
+ *
+ * Copyright 2008 James Hawkins
+ *
+ * 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 <stdarg.h>
+#include <stdio.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winver.h"
+#include "dbghelp.h"
+#include "ole2.h"
+#include "mscoree.h"
+#include "corhdr.h"
+#include "metahost.h"
+#include "cordebug.h"
+#include "wine/list.h"
+#include "mscoree_private.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+typedef struct
+{
+    ULONG Signature;
+    USHORT MajorVersion;
+    USHORT MinorVersion;
+    ULONG Reserved;
+    ULONG VersionLength;
+    LPSTR Version;
+    BYTE Flags;
+    WORD Streams;
+} METADATAHDR;
+
+typedef struct
+{
+    DWORD Offset;
+    DWORD Size;
+} METADATASTREAMHDR;
+
+typedef struct tagCLRTABLE
+{
+    INT rows;
+    DWORD offset;
+} CLRTABLE;
+
+struct tagASSEMBLY
+{
+    LPWSTR path;
+
+    HANDLE hfile;
+    HANDLE hmap;
+    BYTE *data;
+
+    IMAGE_NT_HEADERS *nthdr;
+    IMAGE_COR20_HEADER *corhdr;
+
+    METADATAHDR *metadatahdr;
+};
+
+static inline LPWSTR strdupW(LPCWSTR src)
+{
+    LPWSTR dest;
+
+    if (!src)
+        return NULL;
+
+    dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src) + 1) * sizeof(WCHAR));
+    if (dest)
+        lstrcpyW(dest, src);
+
+    return dest;
+}
+
+static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz)
+{
+    METADATAHDR *metadatahdr;
+    BYTE *ptr, *dest;
+    DWORD size, ofs;
+    ULONG rva;
+
+    rva = assembly->corhdr->MetaData.VirtualAddress;
+    ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL);
+    if (!ptr)
+        return E_FAIL;
+
+    metadatahdr = (METADATAHDR *)ptr;
+
+    assembly->metadatahdr = HeapAlloc(GetProcessHeap(), 0, sizeof(METADATAHDR));
+    if (!assembly->metadatahdr)
+        return E_OUTOFMEMORY;
+
+    size = FIELD_OFFSET(METADATAHDR, Version);
+    memcpy(assembly->metadatahdr, metadatahdr, size);
+
+    assembly->metadatahdr->Version = (LPSTR)&metadatahdr->Version;
+
+    ofs = FIELD_OFFSET(METADATAHDR, Flags);
+    ptr += FIELD_OFFSET(METADATAHDR, Version) + metadatahdr->VersionLength + 1;
+    dest = (BYTE *)assembly->metadatahdr + ofs;
+    memcpy(dest, ptr, sizeof(METADATAHDR) - ofs);
+
+    *hdrsz = sizeof(METADATAHDR) - sizeof(LPSTR) + metadatahdr->VersionLength + 1;
+
+    return S_OK;
+}
+
+static HRESULT parse_clr_metadata(ASSEMBLY *assembly)
+{
+    HRESULT hr;
+    DWORD hdrsz;
+
+    hr = parse_metadata_header(assembly, &hdrsz);
+    if (FAILED(hr))
+        return hr;
+
+    return S_OK;
+}
+
+static HRESULT parse_pe_header(ASSEMBLY *assembly)
+{
+    IMAGE_DATA_DIRECTORY *datadirs;
+
+    assembly->nthdr = ImageNtHeader(assembly->data);
+    if (!assembly->nthdr)
+        return E_FAIL;
+
+    if (assembly->nthdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+    {
+        IMAGE_OPTIONAL_HEADER64 *opthdr =
+                (IMAGE_OPTIONAL_HEADER64 *)&assembly->nthdr->OptionalHeader;
+        datadirs = opthdr->DataDirectory;
+    }
+    else
+    {
+        IMAGE_OPTIONAL_HEADER32 *opthdr =
+                (IMAGE_OPTIONAL_HEADER32 *)&assembly->nthdr->OptionalHeader;
+        datadirs = opthdr->DataDirectory;
+    }
+
+    if (!datadirs)
+        return E_FAIL;
+
+    if (!datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress ||
+        !datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
+    {
+        return E_FAIL;
+    }
+
+    assembly->corhdr = ImageRvaToVa(assembly->nthdr, assembly->data,
+        datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress, NULL);
+    if (!assembly->corhdr)
+        return E_FAIL;
+
+    return S_OK;
+}
+
+HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file)
+{
+    ASSEMBLY *assembly;
+    HRESULT hr;
+
+    *out = NULL;
+
+    assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY));
+    if (!assembly)
+        return E_OUTOFMEMORY;
+
+    assembly->path = strdupW(file);
+    if (!assembly->path)
+    {
+        hr = E_OUTOFMEMORY;
+        goto failed;
+    }
+
+    assembly->hfile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ,
+                                  NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (assembly->hfile == INVALID_HANDLE_VALUE)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto failed;
+    }
+
+    assembly->hmap = CreateFileMappingW(assembly->hfile, NULL, PAGE_READONLY,
+                                        0, 0, NULL);
+    if (!assembly->hmap)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto failed;
+    }
+
+    assembly->data = MapViewOfFile(assembly->hmap, FILE_MAP_READ, 0, 0, 0);
+    if (!assembly->data)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto failed;
+    }
+
+    hr = parse_pe_header(assembly);
+    if (FAILED(hr)) goto failed;
+
+    hr = parse_clr_metadata(assembly);
+    if (FAILED(hr)) goto failed;
+
+    *out = assembly;
+    return S_OK;
+
+failed:
+    assembly_release(assembly);
+    return hr;
+}
+
+HRESULT assembly_release(ASSEMBLY *assembly)
+{
+    if (!assembly)
+        return S_OK;
+
+    HeapFree(GetProcessHeap(), 0, assembly->metadatahdr);
+    HeapFree(GetProcessHeap(), 0, assembly->path);
+    UnmapViewOfFile(assembly->data);
+    CloseHandle(assembly->hmap);
+    CloseHandle(assembly->hfile);
+    HeapFree(GetProcessHeap(), 0, assembly);
+
+    return S_OK;
+}
+
+HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version)
+{
+    *version = assembly->metadatahdr->Version;
+
+    return S_OK;
+}
diff --git a/reactos/dll/win32/mscoree/config.c b/reactos/dll/win32/mscoree/config.c
new file mode 100644 (file)
index 0000000..02c11b1
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * Configuration file parsing
+ *
+ * Copyright 2010 Vincent Povirk
+ *
+ * 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
+ */
+
+#define COBJMACROS
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "ole2.h"
+#include "msxml2.h"
+#include "mscoree.h"
+#include "corhdr.h"
+#include "metahost.h"
+#include "cordebug.h"
+#include "wine/list.h"
+#include "mscoree_private.h"
+#include "shlwapi.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
+
+enum parse_state
+{
+    STATE_ROOT,
+    STATE_CONFIGURATION,
+    STATE_STARTUP,
+    STATE_UNKNOWN
+};
+
+typedef struct ConfigFileHandler
+{
+    ISAXContentHandler ISAXContentHandler_iface;
+    ISAXErrorHandler ISAXErrorHandler_iface;
+    LONG ref;
+    enum parse_state states[16];
+    int statenum;
+    parsed_config_file *result;
+} ConfigFileHandler;
+
+static inline ConfigFileHandler *impl_from_ISAXContentHandler(ISAXContentHandler *iface)
+{
+    return CONTAINING_RECORD(iface, ConfigFileHandler, ISAXContentHandler_iface);
+}
+
+static inline ConfigFileHandler *impl_from_ISAXErrorHandler(ISAXErrorHandler *iface)
+{
+    return CONTAINING_RECORD(iface, ConfigFileHandler, ISAXErrorHandler_iface);
+}
+
+static HRESULT WINAPI ConfigFileHandler_QueryInterface(ISAXContentHandler *iface,
+    REFIID riid, void **ppvObject)
+{
+    if (IsEqualGUID(riid, &IID_ISAXContentHandler) ||
+        IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *ppvObject = iface;
+    }
+    else
+    {
+        WARN("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    ISAXContentHandler_AddRef(iface);
+
+    return S_OK;
+}
+
+static ULONG WINAPI ConfigFileHandler_AddRef(ISAXContentHandler *iface)
+{
+    ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI ConfigFileHandler_Release(ISAXContentHandler *iface)
+{
+    ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    if (ref == 0)
+        HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+static HRESULT WINAPI ConfigFileHandler_putDocumentLocator(ISAXContentHandler *iface,
+    ISAXLocator *pLocator)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_startDocument(ISAXContentHandler *iface)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_endDocument(ISAXContentHandler *iface)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_startPrefixMapping(ISAXContentHandler *iface,
+    const WCHAR *pPrefix, int nPrefix, const WCHAR *pUri, int nUri)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_endPrefixMapping(ISAXContentHandler *iface,
+    const WCHAR *pPrefix, int nPrefix)
+{
+    return S_OK;
+}
+
+static HRESULT parse_startup(ConfigFileHandler *This, ISAXAttributes *pAttr)
+{
+    static const WCHAR legacy[] = {'u','s','e','L','e','g','a','c','y','V','2','R','u','n','t','i','m','e','A','c','t','i','v','a','t','i','o','n','P','o','l','i','c','y',0};
+    static const WCHAR empty[] = {0};
+    LPCWSTR value;
+    int value_size;
+    HRESULT hr;
+
+    hr = ISAXAttributes_getValueFromName(pAttr, empty, 0, legacy, lstrlenW(legacy), &value, &value_size);
+    if (SUCCEEDED(hr))
+        FIXME("useLegacyV2RuntimeActivationPolicy=%s not implemented\n", debugstr_wn(value, value_size));
+    hr = S_OK;
+
+    return hr;
+}
+
+static HRESULT parse_supported_runtime(ConfigFileHandler *This, ISAXAttributes *pAttr)
+{
+    static const WCHAR version[] = {'v','e','r','s','i','o','n',0};
+    static const WCHAR sku[] = {'s','k','u',0};
+    static const WCHAR empty[] = {0};
+    LPCWSTR value;
+    int value_size;
+    HRESULT hr;
+    supported_runtime *entry;
+
+    hr = ISAXAttributes_getValueFromName(pAttr, empty, 0, version, lstrlenW(version), &value, &value_size);
+    if (SUCCEEDED(hr))
+    {
+        TRACE("%s\n", debugstr_wn(value, value_size));
+        entry = HeapAlloc(GetProcessHeap(), 0, sizeof(supported_runtime));
+        if (entry)
+        {
+            entry->version = HeapAlloc(GetProcessHeap(), 0, (value_size + 1) * sizeof(WCHAR));
+            if (entry->version)
+            {
+                lstrcpyW(entry->version, value);
+                list_add_tail(&This->result->supported_runtimes, &entry->entry);
+            }
+            else
+            {
+                HeapFree(GetProcessHeap(), 0, entry);
+                hr = E_OUTOFMEMORY;
+            }
+        }
+        else
+            hr = E_OUTOFMEMORY;
+    }
+    else
+        WARN("Missing version attribute\n");
+
+    if (SUCCEEDED(hr))
+    {
+        hr = ISAXAttributes_getValueFromName(pAttr, empty, 0, sku, lstrlenW(sku), &value, &value_size);
+        if (SUCCEEDED(hr))
+            FIXME("sku=%s not implemented\n", debugstr_wn(value, value_size));
+        hr = S_OK;
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI ConfigFileHandler_startElement(ISAXContentHandler *iface,
+    const WCHAR *pNamespaceUri, int nNamespaceUri, const WCHAR *pLocalName,
+    int nLocalName, const WCHAR *pQName, int nQName, ISAXAttributes *pAttr)
+{
+    ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
+    static const WCHAR configuration[] = {'c','o','n','f','i','g','u','r','a','t','i','o','n',0};
+    static const WCHAR startup[] = {'s','t','a','r','t','u','p',0};
+    static const WCHAR supportedRuntime[] = {'s','u','p','p','o','r','t','e','d','R','u','n','t','i','m','e',0};
+    HRESULT hr = S_OK;
+
+    TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri,nNamespaceUri),
+        debugstr_wn(pLocalName,nLocalName), debugstr_wn(pQName,nQName));
+
+    if (This->statenum == sizeof(This->states) / sizeof(This->states[0]) - 1)
+    {
+        ERR("file has too much nesting\n");
+        return E_FAIL;
+    }
+
+    switch (This->states[This->statenum])
+    {
+    case STATE_ROOT:
+        if (nLocalName == sizeof(configuration)/sizeof(WCHAR)-1 &&
+            lstrcmpW(pLocalName, configuration) == 0)
+        {
+            This->states[++This->statenum] = STATE_CONFIGURATION;
+            break;
+        }
+        else
+            goto unknown;
+    case STATE_CONFIGURATION:
+        if (nLocalName == sizeof(startup)/sizeof(WCHAR)-1 &&
+            lstrcmpW(pLocalName, startup) == 0)
+        {
+            hr = parse_startup(This, pAttr);
+            This->states[++This->statenum] = STATE_STARTUP;
+            break;
+        }
+        else
+            goto unknown;
+    case STATE_STARTUP:
+        if (nLocalName == sizeof(supportedRuntime)/sizeof(WCHAR)-1 &&
+            lstrcmpW(pLocalName, supportedRuntime) == 0)
+        {
+            hr = parse_supported_runtime(This, pAttr);
+            This->states[++This->statenum] = STATE_UNKNOWN;
+            break;
+        }
+        else
+            goto unknown;
+    default:
+        goto unknown;
+    }
+
+    return hr;
+
+unknown:
+    FIXME("Unknown element %s in state %u\n", debugstr_wn(pLocalName,nLocalName),
+        This->states[This->statenum]);
+
+    This->states[++This->statenum] = STATE_UNKNOWN;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_endElement(ISAXContentHandler *iface,
+    const WCHAR *pNamespaceUri, int nNamespaceUri, const WCHAR *pLocalName,
+    int nLocalName, const WCHAR *pQName, int nQName)
+{
+    ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
+
+    TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri,nNamespaceUri),
+        debugstr_wn(pLocalName,nLocalName), debugstr_wn(pQName,nQName));
+
+    if (This->statenum > 0)
+    {
+        This->statenum--;
+    }
+    else
+    {
+        ERR("element end does not match a start\n");
+        return E_FAIL;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_characters(ISAXContentHandler *iface,
+    const WCHAR *pChars, int nChars)
+{
+    TRACE("%s\n", debugstr_wn(pChars,nChars));
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_ignorableWhitespace(ISAXContentHandler *iface,
+    const WCHAR *pChars, int nChars)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_processingInstruction(ISAXContentHandler *iface,
+    const WCHAR *pTarget, int nTarget, const WCHAR *pData, int nData)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_skippedEntity(ISAXContentHandler *iface,
+    const WCHAR * pName, int nName)
+{
+    TRACE("%s\n", debugstr_wn(pName,nName));
+    return S_OK;
+}
+
+static const struct ISAXContentHandlerVtbl ConfigFileHandlerVtbl =
+{
+    ConfigFileHandler_QueryInterface,
+    ConfigFileHandler_AddRef,
+    ConfigFileHandler_Release,
+    ConfigFileHandler_putDocumentLocator,
+    ConfigFileHandler_startDocument,
+    ConfigFileHandler_endDocument,
+    ConfigFileHandler_startPrefixMapping,
+    ConfigFileHandler_endPrefixMapping,
+    ConfigFileHandler_startElement,
+    ConfigFileHandler_endElement,
+    ConfigFileHandler_characters,
+    ConfigFileHandler_ignorableWhitespace,
+    ConfigFileHandler_processingInstruction,
+    ConfigFileHandler_skippedEntity
+};
+
+static HRESULT WINAPI ConfigFileHandler_Error_QueryInterface(ISAXErrorHandler *iface,
+    REFIID riid, void **ppvObject)
+{
+    if (IsEqualGUID(riid, &IID_ISAXErrorHandler) ||
+        IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *ppvObject = iface;
+    }
+    else
+    {
+        WARN("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    ISAXErrorHandler_AddRef(iface);
+
+    return S_OK;
+}
+
+static ULONG WINAPI ConfigFileHandler_Error_AddRef(ISAXErrorHandler *iface)
+{
+    ConfigFileHandler *This = impl_from_ISAXErrorHandler(iface);
+    return IUnknown_AddRef((IUnknown*)This);
+}
+
+static ULONG WINAPI ConfigFileHandler_Error_Release(ISAXErrorHandler *iface)
+{
+    ConfigFileHandler *This = impl_from_ISAXErrorHandler(iface);
+    return IUnknown_Release((IUnknown*)This);
+}
+
+static HRESULT WINAPI ConfigFileHandler_error(ISAXErrorHandler *iface,
+    ISAXLocator * pLocator, const WCHAR * pErrorMessage, HRESULT hrErrorCode)
+{
+    WARN("%s,%x\n", debugstr_w(pErrorMessage), hrErrorCode);
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_fatalError(ISAXErrorHandler *iface,
+    ISAXLocator * pLocator, const WCHAR * pErrorMessage, HRESULT hrErrorCode)
+{
+    WARN("%s,%x\n", debugstr_w(pErrorMessage), hrErrorCode);
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_ignorableWarning(ISAXErrorHandler *iface,
+    ISAXLocator * pLocator, const WCHAR * pErrorMessage, HRESULT hrErrorCode)
+{
+    WARN("%s,%x\n", debugstr_w(pErrorMessage), hrErrorCode);
+    return S_OK;
+}
+
+static const struct ISAXErrorHandlerVtbl ConfigFileHandlerErrorVtbl =
+{
+    ConfigFileHandler_Error_QueryInterface,
+    ConfigFileHandler_Error_AddRef,
+    ConfigFileHandler_Error_Release,
+    ConfigFileHandler_error,
+    ConfigFileHandler_fatalError,
+    ConfigFileHandler_ignorableWarning
+};
+
+static void init_config(parsed_config_file *config)
+{
+    list_init(&config->supported_runtimes);
+}
+
+static HRESULT parse_config(VARIANT input, parsed_config_file *result)
+{
+    ISAXXMLReader *reader;
+    ConfigFileHandler *handler;
+    HRESULT hr;
+
+    handler = HeapAlloc(GetProcessHeap(), 0, sizeof(ConfigFileHandler));
+    if (!handler)
+        return E_OUTOFMEMORY;
+
+    handler->ISAXContentHandler_iface.lpVtbl = &ConfigFileHandlerVtbl;
+    handler->ISAXErrorHandler_iface.lpVtbl = &ConfigFileHandlerErrorVtbl;
+    handler->ref = 1;
+    handler->states[0] = STATE_ROOT;
+    handler->statenum = 0;
+    handler->result = result;
+
+    hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
+        &IID_ISAXXMLReader, (LPVOID*)&reader);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = ISAXXMLReader_putContentHandler(reader, &handler->ISAXContentHandler_iface);
+
+        if (SUCCEEDED(hr))
+            hr = ISAXXMLReader_putErrorHandler(reader, &handler->ISAXErrorHandler_iface);
+
+        if (SUCCEEDED(hr))
+            hr = ISAXXMLReader_parse(reader, input);
+
+        ISAXXMLReader_Release(reader);
+    }
+
+    IUnknown_Release((IUnknown*)handler);
+
+    return S_OK;
+}
+
+HRESULT parse_config_file(LPCWSTR filename, parsed_config_file *result)
+{
+    IStream *stream;
+    VARIANT var;
+    HRESULT hr;
+    HRESULT initresult;
+
+    init_config(result);
+
+    initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+    hr = SHCreateStreamOnFileW(filename, STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE, &stream);
+
+    if (SUCCEEDED(hr))
+    {
+        V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
+        V_UNKNOWN(&var) = (IUnknown*)stream;
+
+        hr = parse_config(var, result);
+
+        IStream_Release(stream);
+    }
+
+    if (SUCCEEDED(initresult))
+        CoUninitialize();
+
+    return hr;
+}
+
+void free_parsed_config_file(parsed_config_file *file)
+{
+    supported_runtime *cursor, *cursor2;
+
+    LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &file->supported_runtimes, supported_runtime, entry)
+    {
+        HeapFree(GetProcessHeap(), 0, cursor->version);
+        list_remove(&cursor->entry);
+        HeapFree(GetProcessHeap(), 0, cursor);
+    }
+}
diff --git a/reactos/dll/win32/mscoree/cordebug.c b/reactos/dll/win32/mscoree/cordebug.c
new file mode 100644 (file)
index 0000000..da06f49
--- /dev/null
@@ -0,0 +1,786 @@
+/*
+ *
+ * Copyright 2011 Alistair Leslie-Hughes
+ *
+ * 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
+ */
+
+#define COBJMACROS
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+
+#include "winuser.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "ole2.h"
+#include "shellapi.h"
+#include "mscoree.h"
+#include "corhdr.h"
+#include "metahost.h"
+#include "cordebug.h"
+#include "wine/list.h"
+#include "mscoree_private.h"
+#include "wine/debug.h"
+
+
+WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
+
+typedef struct DebugProcess
+{
+    ICorDebugProcess ICorDebugProcess_iface;
+
+    CorDebug *cordebug;
+
+    DWORD dwProcessID;
+    HANDLE handle;
+    HANDLE thread;
+
+    LONG ref;
+} DebugProcess;
+
+static inline CorDebug *impl_from_ICorDebug( ICorDebug *iface )
+{
+    return CONTAINING_RECORD(iface, CorDebug, ICorDebug_iface);
+}
+
+static inline CorDebug *impl_from_ICorDebugProcessEnum( ICorDebugProcessEnum *iface )
+{
+    return CONTAINING_RECORD(iface, CorDebug, ICorDebugProcessEnum_iface);
+}
+
+static inline DebugProcess *impl_from_ICorDebugProcess( ICorDebugProcess *iface )
+{
+    return CONTAINING_RECORD(iface, DebugProcess, ICorDebugProcess_iface);
+}
+
+/* ICorDebugProcess Interface */
+static HRESULT WINAPI cordebugprocess_QueryInterface(ICorDebugProcess *iface,
+                REFIID riid, void **ppvObject)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+
+    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
+
+    if ( IsEqualGUID( riid, &IID_ICorDebugProcess ) ||
+         IsEqualGUID( riid, &IID_ICorDebugController ) ||
+         IsEqualGUID( riid, &IID_IUnknown ) )
+    {
+        *ppvObject = &This->ICorDebugProcess_iface;
+    }
+    else
+    {
+        FIXME("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    ICorDebug_AddRef(iface);
+
+    return S_OK;
+}
+
+static ULONG WINAPI cordebugprocess_AddRef(ICorDebugProcess *iface)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("%p ref=%u\n", This, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI cordebugprocess_Release(ICorDebugProcess *iface)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("%p ref=%u\n", This, ref);
+
+    if (ref == 0)
+    {
+        if(This->handle)
+            CloseHandle(This->handle);
+
+        if(This->thread)
+            CloseHandle(This->thread);
+
+        if(This->cordebug)
+            ICorDebug_Release(&This->cordebug->ICorDebug_iface);
+
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI cordebugprocess_Stop(ICorDebugProcess *iface, DWORD dwTimeoutIgnored)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_Continue(ICorDebugProcess *iface, BOOL fIsOutOfBand)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    TRACE("%p\n", This);
+
+    if(This->thread)
+        ResumeThread(This->thread);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI cordebugprocess_IsRunning(ICorDebugProcess *iface, BOOL *pbRunning)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_HasQueuedCallbacks(ICorDebugProcess *iface,
+                ICorDebugThread *pThread, BOOL *pbQueued)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_EnumerateThreads(ICorDebugProcess *iface,
+                ICorDebugThreadEnum **ppThreads)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_SetAllThreadsDebugState(ICorDebugProcess *iface,
+                CorDebugThreadState state, ICorDebugThread *pExceptThisThread)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_Detach(ICorDebugProcess *iface)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_Terminate(ICorDebugProcess *iface, UINT exitCode)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    BOOL ret = TRUE;
+
+    TRACE("%p\n", This);
+
+    if(This->handle)
+    {
+        ret = TerminateProcess(This->handle, exitCode);
+        CloseHandle(This->handle);
+        This->handle = NULL;
+    }
+    return ret ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI cordebugprocess_CanCommitChanges(ICorDebugProcess *iface,
+                ULONG cSnapshots, ICorDebugEditAndContinueSnapshot * pSnapshots[],
+                ICorDebugErrorInfoEnum **pError)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_CommitChanges(ICorDebugProcess *iface,
+                ULONG cSnapshots, ICorDebugEditAndContinueSnapshot * pSnapshots[],
+                ICorDebugErrorInfoEnum **pError)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_GetID(ICorDebugProcess *iface, DWORD *pdwProcessId)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    TRACE("%p\n", This);
+
+    if(!pdwProcessId)
+        return E_INVALIDARG;
+
+    *pdwProcessId = This->dwProcessID;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI cordebugprocess_GetHandle(ICorDebugProcess *iface, HPROCESS *phProcessHandle)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    TRACE("%p\n", This);
+
+    if(!phProcessHandle)
+        return E_INVALIDARG;
+
+    *phProcessHandle = This->handle;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI cordebugprocess_GetThread(ICorDebugProcess *iface, DWORD dwThreadId,
+                ICorDebugThread **ppThread)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_EnumerateObjects(ICorDebugProcess *iface,
+                ICorDebugObjectEnum **ppObjects)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_IsTransitionStub(ICorDebugProcess *iface,
+                CORDB_ADDRESS address, BOOL *pbTransitionStub)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_IsOSSuspended(ICorDebugProcess *iface,
+                DWORD threadID, BOOL *pbSuspended)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_GetThreadContext(ICorDebugProcess *iface,
+                DWORD threadID, ULONG32 contextSize, BYTE context[])
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_SetThreadContext(ICorDebugProcess *iface,
+                DWORD threadID, ULONG32 contextSize, BYTE context[])
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_ReadMemory(ICorDebugProcess *iface,
+                CORDB_ADDRESS address, DWORD size, BYTE buffer[],
+                SIZE_T *read)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_WriteMemory(ICorDebugProcess *iface,
+                CORDB_ADDRESS address, DWORD size, BYTE buffer[],
+                SIZE_T *written)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_ClearCurrentException(ICorDebugProcess *iface,
+                DWORD threadID)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_EnableLogMessages(ICorDebugProcess *iface,
+                BOOL fOnOff)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_ModifyLogSwitch(ICorDebugProcess *iface,
+                WCHAR *pLogSwitchName, LONG lLevel)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_EnumerateAppDomains(ICorDebugProcess *iface,
+                ICorDebugAppDomainEnum **ppAppDomains)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_GetObject(ICorDebugProcess *iface,
+                ICorDebugValue **ppObject)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_ThreadForFiberCookie(ICorDebugProcess *iface,
+                DWORD fiberCookie, ICorDebugThread **ppThread)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_GetHelperThreadID(ICorDebugProcess *iface,
+                DWORD *pThreadID)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+
+/***************************************/
+static const ICorDebugProcessVtbl cordebugprocessVtbl = {
+    cordebugprocess_QueryInterface,
+    cordebugprocess_AddRef,
+    cordebugprocess_Release,
+    cordebugprocess_Stop,
+    cordebugprocess_Continue,
+    cordebugprocess_IsRunning,
+    cordebugprocess_HasQueuedCallbacks,
+    cordebugprocess_EnumerateThreads,
+    cordebugprocess_SetAllThreadsDebugState,
+    cordebugprocess_Detach,
+    cordebugprocess_Terminate,
+    cordebugprocess_CanCommitChanges,
+    cordebugprocess_CommitChanges,
+    cordebugprocess_GetID,
+    cordebugprocess_GetHandle,
+    cordebugprocess_GetThread,
+    cordebugprocess_EnumerateObjects,
+    cordebugprocess_IsTransitionStub,
+    cordebugprocess_IsOSSuspended,
+    cordebugprocess_GetThreadContext,
+    cordebugprocess_SetThreadContext,
+    cordebugprocess_ReadMemory,
+    cordebugprocess_WriteMemory,
+    cordebugprocess_ClearCurrentException,
+    cordebugprocess_EnableLogMessages,
+    cordebugprocess_ModifyLogSwitch,
+    cordebugprocess_EnumerateAppDomains,
+    cordebugprocess_GetObject,
+    cordebugprocess_ThreadForFiberCookie,
+    cordebugprocess_GetHelperThreadID
+};
+
+
+static HRESULT CorDebugProcess_Create(CorDebug *cordebug, IUnknown** ppUnk, LPPROCESS_INFORMATION lpProcessInformation)
+{
+    DebugProcess *This;
+
+    This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
+    if ( !This )
+        return E_OUTOFMEMORY;
+
+    if(!DuplicateHandle(GetCurrentProcess(), lpProcessInformation->hProcess,
+                    GetCurrentProcess(), &This->handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
+    {
+        ERR("Failed to duplicate process handle\n");
+        HeapFree(GetProcessHeap(), 0, This);
+        return E_FAIL;
+    }
+    if(!DuplicateHandle(GetCurrentProcess(), lpProcessInformation->hThread,
+                    GetCurrentProcess(), &This->thread, 0, FALSE, DUPLICATE_SAME_ACCESS))
+    {
+        CloseHandle(This->handle);
+
+        ERR("Failed to duplicate thread handle\n");
+        HeapFree(GetProcessHeap(), 0, This);
+        return E_FAIL;
+    }
+
+    This->ICorDebugProcess_iface.lpVtbl = &cordebugprocessVtbl;
+    This->ref = 1;
+    This->cordebug = cordebug;
+    This->dwProcessID = lpProcessInformation->dwProcessId;
+
+    if(This->cordebug)
+        ICorDebug_AddRef(&This->cordebug->ICorDebug_iface);
+
+    *ppUnk = (IUnknown*)This;
+
+    return S_OK;
+}
+
+/* ICorDebugProcessEnum Interface */
+static HRESULT WINAPI process_enum_QueryInterface(ICorDebugProcessEnum *iface, REFIID riid, void **ppvObject)
+{
+    CorDebug *This = impl_from_ICorDebugProcessEnum(iface);
+
+    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
+
+    if ( IsEqualGUID( riid, &IID_ICorDebugProcessEnum ) ||
+         IsEqualGUID( riid, &IID_ICorDebugEnum ) ||
+         IsEqualGUID( riid, &IID_IUnknown ) )
+    {
+        *ppvObject = &This->ICorDebugProcessEnum_iface;
+    }
+    else
+    {
+        FIXME("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    ICorDebug_AddRef(iface);
+
+    return S_OK;
+}
+
+static ULONG WINAPI process_enum_AddRef(ICorDebugProcessEnum *iface)
+{
+    CorDebug *This = impl_from_ICorDebugProcessEnum(iface);
+    TRACE("%p ref=%u\n", This, This->ref);
+
+    return ICorDebug_AddRef(&This->ICorDebug_iface);
+}
+
+static ULONG WINAPI process_enum_Release(ICorDebugProcessEnum *iface)
+{
+    CorDebug *This = impl_from_ICorDebugProcessEnum(iface);
+    TRACE("%p ref=%u\n", This, This->ref);
+
+    return ICorDebug_Release(&This->ICorDebug_iface);
+}
+
+static HRESULT WINAPI process_enum_Skip(ICorDebugProcessEnum *iface, ULONG celt)
+{
+    CorDebug *This = impl_from_ICorDebugProcessEnum(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI process_enum_Reset(ICorDebugProcessEnum *iface)
+{
+    CorDebug *This = impl_from_ICorDebugProcessEnum(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI process_enum_Clone(ICorDebugProcessEnum *iface, ICorDebugEnum **ppEnum)
+{
+    CorDebug *This = impl_from_ICorDebugProcessEnum(iface);
+    FIXME("stub %p %p\n", This, ppEnum);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI process_enum_GetCount(ICorDebugProcessEnum *iface, ULONG *pcelt)
+{
+    CorDebug *This = impl_from_ICorDebugProcessEnum(iface);
+    TRACE("stub %p %p\n", This, pcelt);
+
+    if(!pcelt)
+        return E_INVALIDARG;
+
+    *pcelt = list_count(&This->processes);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI process_enum_Next(ICorDebugProcessEnum *iface, ULONG celt,
+            ICorDebugProcess * processes[], ULONG *pceltFetched)
+{
+    CorDebug *This = impl_from_ICorDebugProcessEnum(iface);
+    FIXME("stub %p %d %p %p\n", This, celt, processes, pceltFetched);
+    return E_NOTIMPL;
+}
+
+static const struct ICorDebugProcessEnumVtbl processenum_vtbl =
+{
+    process_enum_QueryInterface,
+    process_enum_AddRef,
+    process_enum_Release,
+    process_enum_Skip,
+    process_enum_Reset,
+    process_enum_Clone,
+    process_enum_GetCount,
+    process_enum_Next
+};
+
+/*** IUnknown methods ***/
+static HRESULT WINAPI CorDebug_QueryInterface(ICorDebug *iface, REFIID riid, void **ppvObject)
+{
+    CorDebug *This = impl_from_ICorDebug( iface );
+
+    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
+
+    if ( IsEqualGUID( riid, &IID_ICorDebug ) ||
+         IsEqualGUID( riid, &IID_IUnknown ) )
+    {
+        *ppvObject = &This->ICorDebug_iface;
+    }
+    else
+    {
+        FIXME("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    ICorDebug_AddRef( iface );
+
+    return S_OK;
+}
+
+static ULONG WINAPI CorDebug_AddRef(ICorDebug *iface)
+{
+    CorDebug *This = impl_from_ICorDebug( iface );
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("%p ref=%u\n", This, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI CorDebug_Release(ICorDebug *iface)
+{
+    CorDebug *This = impl_from_ICorDebug( iface );
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("%p ref=%u\n", This, ref);
+
+    if (ref == 0)
+    {
+        if(!list_empty(&This->processes))
+            ERR("Processes haven't been removed Correctly\n");
+
+        if(This->runtimehost)
+            ICLRRuntimeHost_Release(This->runtimehost);
+
+        if(This->pCallback)
+            ICorDebugManagedCallback2_Release(This->pCallback2);
+
+        if(This->pCallback)
+            ICorDebugManagedCallback_Release(This->pCallback);
+
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+/*** ICorDebug methods ***/
+static HRESULT WINAPI CorDebug_Initialize(ICorDebug *iface)
+{
+    CorDebug *This = impl_from_ICorDebug( iface );
+    FIXME("stub %p\n", This);
+    return S_OK;
+}
+
+static HRESULT WINAPI CorDebug_Terminate(ICorDebug *iface)
+{
+    struct CorProcess *cursor, *cursor2;
+    CorDebug *This = impl_from_ICorDebug( iface );
+    TRACE("stub %p\n", This);
+
+    LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->processes, struct CorProcess, entry)
+    {
+        if(cursor->pProcess)
+        {
+            ICorDebugProcess_Terminate(cursor->pProcess, 0);
+            ICorDebugProcess_Release(cursor->pProcess);
+        }
+
+        list_remove(&cursor->entry);
+        HeapFree(GetProcessHeap(), 0, cursor);
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI CorDebug_SetManagedHandler(ICorDebug *iface, ICorDebugManagedCallback *pCallback)
+{
+    CorDebug *This = impl_from_ICorDebug( iface );
+    HRESULT hr;
+    ICorDebugManagedCallback2 *pCallback2;
+
+    TRACE("%p (%p)\n", This, pCallback);
+
+    if(!pCallback)
+        return E_INVALIDARG;
+
+    hr = ICorDebugManagedCallback_QueryInterface(pCallback, &IID_ICorDebugManagedCallback2, (void**)&pCallback2);
+    if(hr == S_OK)
+    {
+        if(This->pCallback2)
+            ICorDebugManagedCallback2_Release(This->pCallback2);
+
+        if(This->pCallback)
+            ICorDebugManagedCallback_Release(This->pCallback);
+
+        This->pCallback = pCallback;
+        This->pCallback2 = pCallback2;
+
+        ICorDebugManagedCallback_AddRef(This->pCallback);
+    }
+    else
+    {
+        WARN("Debugging without interface ICorDebugManagedCallback2 is currently not supported.\n");
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI CorDebug_SetUnmanagedHandler(ICorDebug *iface, ICorDebugUnmanagedCallback *pCallback)
+{
+    CorDebug *This = impl_from_ICorDebug( iface );
+    FIXME("stub %p %p\n", This, pCallback);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CorDebug_CreateProcess(ICorDebug *iface, LPCWSTR lpApplicationName,
+            LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
+            LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
+            DWORD dwCreationFlags, PVOID lpEnvironment,LPCWSTR lpCurrentDirectory,
+            LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation,
+            CorDebugCreateProcessFlags debuggingFlags, ICorDebugProcess **ppProcess)
+{
+    CorDebug *This = impl_from_ICorDebug( iface );
+    ICorDebugProcess *pDebugProcess;
+    HRESULT hr;
+
+    TRACE("stub %p %s %s %p %p %d %d %p %s %p %p %d %p\n", This, debugstr_w(lpApplicationName),
+            debugstr_w(lpCommandLine), lpProcessAttributes, lpThreadAttributes,
+            bInheritHandles, dwCreationFlags, lpEnvironment, debugstr_w(lpCurrentDirectory),
+            lpStartupInfo, lpProcessInformation, debuggingFlags, ppProcess);
+
+    if(CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes,
+            bInheritHandles, dwCreationFlags | CREATE_SUSPENDED, lpEnvironment, lpCurrentDirectory,
+            lpStartupInfo, lpProcessInformation))
+    {
+        hr = CorDebugProcess_Create(This, (IUnknown**)&pDebugProcess, lpProcessInformation);
+        if(hr == S_OK)
+        {
+            struct CorProcess *new_process = HeapAlloc( GetProcessHeap(), 0, sizeof(CorProcess) );
+
+            new_process->pProcess = pDebugProcess;
+            list_add_tail(&This->processes, &new_process->entry);
+
+            ICorDebugProcess_AddRef(pDebugProcess);
+            *ppProcess = pDebugProcess;
+
+            if(This->pCallback)
+                ICorDebugManagedCallback_CreateProcess(This->pCallback, pDebugProcess);
+        }
+        else
+        {
+            TerminateProcess(lpProcessInformation->hProcess, 0);
+        }
+    }
+    else
+        hr = E_FAIL;
+
+    return hr;
+}
+
+static HRESULT WINAPI CorDebug_DebugActiveProcess(ICorDebug *iface, DWORD id, BOOL win32Attach,
+            ICorDebugProcess **ppProcess)
+{
+    CorDebug *This = impl_from_ICorDebug( iface );
+    FIXME("stub %p %d %d %p\n", This, id, win32Attach, ppProcess);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CorDebug_EnumerateProcesses( ICorDebug *iface, ICorDebugProcessEnum **ppProcess)
+{
+    CorDebug *This = impl_from_ICorDebug( iface );
+    TRACE("stub %p %p\n", This, ppProcess);
+
+    if(!ppProcess)
+        return E_INVALIDARG;
+
+    *ppProcess = &This->ICorDebugProcessEnum_iface;
+    ICorDebugProcessEnum_AddRef(*ppProcess);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI CorDebug_GetProcess(ICorDebug *iface, DWORD dwProcessId, ICorDebugProcess **ppProcess)
+{
+    CorDebug *This = impl_from_ICorDebug( iface );
+    FIXME("stub %p %d %p\n", This, dwProcessId, ppProcess);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CorDebug_CanLaunchOrAttach(ICorDebug *iface, DWORD dwProcessId,
+            BOOL win32DebuggingEnabled)
+{
+    CorDebug *This = impl_from_ICorDebug( iface );
+    FIXME("stub %p %d %d\n", This, dwProcessId, win32DebuggingEnabled);
+    return S_OK;
+}
+
+static const struct ICorDebugVtbl cordebug_vtbl =
+{
+    CorDebug_QueryInterface,
+    CorDebug_AddRef,
+    CorDebug_Release,
+    CorDebug_Initialize,
+    CorDebug_Terminate,
+    CorDebug_SetManagedHandler,
+    CorDebug_SetUnmanagedHandler,
+    CorDebug_CreateProcess,
+    CorDebug_DebugActiveProcess,
+    CorDebug_EnumerateProcesses,
+    CorDebug_GetProcess,
+    CorDebug_CanLaunchOrAttach
+};
+
+HRESULT CorDebug_Create(ICLRRuntimeHost *runtimehost, IUnknown** ppUnk)
+{
+    CorDebug *This;
+
+    This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
+    if ( !This )
+        return E_OUTOFMEMORY;
+
+    This->ICorDebug_iface.lpVtbl = &cordebug_vtbl;
+    This->ICorDebugProcessEnum_iface.lpVtbl = &processenum_vtbl;
+    This->ref = 1;
+    This->pCallback = NULL;
+    This->pCallback2 = NULL;
+    This->runtimehost = runtimehost;
+
+    list_init(&This->processes);
+
+    if(This->runtimehost)
+        ICLRRuntimeHost_AddRef(This->runtimehost);
+
+    *ppUnk = (IUnknown*)This;
+
+    return S_OK;
+}
index 9de9bf5..5042f20 100644 (file)
 #include "windef.h"
 #include "winbase.h"
 #include "winuser.h"
+#include "winnls.h"
 #include "winreg.h"
 #include "ole2.h"
+#include "shellapi.h"
 
 #include "cor.h"
 #include "mscoree.h"
+#include "metahost.h"
+#include "corhdr.h"
+#include "cordebug.h"
+#include "wine/list.h"
+#include "mscoree_private.h"
 
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
 
-typedef struct _corruntimehost
+#include "initguid.h"
+
+DEFINE_GUID(IID__AppDomain, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13);
+
+struct DomainEntry
+{
+    struct list entry;
+    MonoDomain *domain;
+};
+
+static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, MonoDomain **result)
 {
-    const struct ICorRuntimeHostVtbl *lpVtbl;
-    LONG ref;
-} corruntimehost;
+    struct DomainEntry *entry;
+    char *mscorlib_path;
+    HRESULT res=S_OK;
+
+    EnterCriticalSection(&This->lock);
+
+    entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
+    if (!entry)
+    {
+        res = E_OUTOFMEMORY;
+        goto end;
+    }
+
+    mscorlib_path = WtoA(This->version->mscorlib_path);
+    if (!mscorlib_path)
+    {
+        HeapFree(GetProcessHeap(), 0, entry);
+        res = E_OUTOFMEMORY;
+        goto end;
+    }
+
+    entry->domain = This->mono->mono_jit_init(mscorlib_path);
+
+    HeapFree(GetProcessHeap(), 0, mscorlib_path);
+
+    if (!entry->domain)
+    {
+        HeapFree(GetProcessHeap(), 0, entry);
+        res = E_FAIL;
+        goto end;
+    }
 
-static inline corruntimehost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
+    This->mono->is_started = TRUE;
+
+    list_add_tail(&This->domains, &entry->entry);
+
+    *result = entry->domain;
+
+end:
+    LeaveCriticalSection(&This->lock);
+
+    return res;
+}
+
+static HRESULT RuntimeHost_GetDefaultDomain(RuntimeHost *This, MonoDomain **result)
 {
-    return (corruntimehost *)((char*)iface - FIELD_OFFSET(corruntimehost, lpVtbl));
+    HRESULT res=S_OK;
+
+    EnterCriticalSection(&This->lock);
+
+    if (This->default_domain) goto end;
+
+    res = RuntimeHost_AddDomain(This, &This->default_domain);
+
+end:
+    *result = This->default_domain;
+
+    LeaveCriticalSection(&This->lock);
+
+    return res;
+}
+
+static void RuntimeHost_DeleteDomain(RuntimeHost *This, MonoDomain *domain)
+{
+    struct DomainEntry *entry;
+
+    EnterCriticalSection(&This->lock);
+
+    LIST_FOR_EACH_ENTRY(entry, &This->domains, struct DomainEntry, entry)
+    {
+        if (entry->domain == domain)
+        {
+            list_remove(&entry->entry);
+            if (This->default_domain == domain)
+                This->default_domain = NULL;
+            HeapFree(GetProcessHeap(), 0, entry);
+            break;
+        }
+    }
+
+    LeaveCriticalSection(&This->lock);
+}
+
+static HRESULT RuntimeHost_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *domain, IUnknown **punk)
+{
+    HRESULT hr;
+    void *args[1];
+    MonoAssembly *assembly;
+    MonoImage *image;
+    MonoClass *klass;
+    MonoMethod *method;
+    MonoObject *appdomain_object;
+    IUnknown *unk;
+
+    assembly = This->mono->mono_domain_assembly_open(domain, "mscorlib");
+    if (!assembly)
+    {
+        ERR("Cannot load mscorlib\n");
+        return E_FAIL;
+    }
+
+    image = This->mono->mono_assembly_get_image(assembly);
+    if (!image)
+    {
+        ERR("Couldn't get assembly image\n");
+        return E_FAIL;
+    }
+
+    klass = This->mono->mono_class_from_name(image, "System", "AppDomain");
+    if (!klass)
+    {
+        ERR("Couldn't get class from image\n");
+        return E_FAIL;
+    }
+
+    method = This->mono->mono_class_get_method_from_name(klass, "get_CurrentDomain", 0);
+    if (!method)
+    {
+        ERR("Couldn't get method from class\n");
+        return E_FAIL;
+    }
+
+    args[0] = NULL;
+    appdomain_object = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
+    if (!appdomain_object)
+    {
+        ERR("Couldn't get result pointer\n");
+        return E_FAIL;
+    }
+
+    hr = RuntimeHost_GetIUnknownForObject(This, appdomain_object, &unk);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = IUnknown_QueryInterface(unk, &IID__AppDomain, (void**)punk);
+
+        IUnknown_Release(unk);
+    }
+
+    return hr;
+}
+
+static inline RuntimeHost *impl_from_ICLRRuntimeHost( ICLRRuntimeHost *iface )
+{
+    return CONTAINING_RECORD(iface, RuntimeHost, ICLRRuntimeHost_iface);
+}
+
+static inline RuntimeHost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
+{
+    return CONTAINING_RECORD(iface, RuntimeHost, ICorRuntimeHost_iface);
 }
 
 /*** IUnknown methods ***/
@@ -50,7 +210,7 @@ static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
         REFIID riid,
         void **ppvObject)
 {
-    corruntimehost *This = impl_from_ICorRuntimeHost( iface );
+    RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
 
     if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) ||
@@ -71,20 +231,17 @@ static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
 
 static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface)
 {
-    corruntimehost *This = impl_from_ICorRuntimeHost( iface );
+    RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
+
     return InterlockedIncrement( &This->ref );
 }
 
 static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface)
 {
-    corruntimehost *This = impl_from_ICorRuntimeHost( iface );
+    RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
     ULONG ref;
 
     ref = InterlockedDecrement( &This->ref );
-    if ( ref == 0 )
-    {
-        HeapFree( GetProcessHeap(), 0, This );
-    }
 
     return ref;
 }
@@ -149,7 +306,7 @@ static HRESULT WINAPI corruntimehost_Start(
     ICorRuntimeHost* iface)
 {
     FIXME("stub %p\n", iface);
-    return E_NOTIMPL;
+    return S_OK;
 }
 
 static HRESULT WINAPI corruntimehost_Stop(
@@ -173,8 +330,20 @@ static HRESULT WINAPI corruntimehost_GetDefaultDomain(
     ICorRuntimeHost* iface,
     IUnknown **pAppDomain)
 {
-    FIXME("stub %p\n", iface);
-    return E_NOTIMPL;
+    RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
+    HRESULT hr;
+    MonoDomain *domain;
+
+    TRACE("(%p)\n", iface);
+
+    hr = RuntimeHost_GetDefaultDomain(This, &domain);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = RuntimeHost_GetIUnknownForDomain(This, domain, pAppDomain);
+    }
+
+    return hr;
 }
 
 static HRESULT WINAPI corruntimehost_EnumDomains(
@@ -271,18 +440,506 @@ static const struct ICorRuntimeHostVtbl corruntimehost_vtbl =
     corruntimehost_CurrentDomain
 };
 
-IUnknown* create_corruntimehost(void)
+static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface,
+        REFIID riid,
+        void **ppvObject)
+{
+    RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
+    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
+
+    if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) ||
+         IsEqualGUID( riid, &IID_IUnknown ) )
+    {
+        *ppvObject = iface;
+    }
+    else
+    {
+        FIXME("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    ICLRRuntimeHost_AddRef( iface );
+
+    return S_OK;
+}
+
+static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface)
+{
+    RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
+    return ICorRuntimeHost_AddRef(&This->ICorRuntimeHost_iface);
+}
+
+static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface)
 {
-    corruntimehost *This;
+    RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
+    return ICorRuntimeHost_Release(&This->ICorRuntimeHost_iface);
+}
+
+static HRESULT WINAPI CLRRuntimeHost_Start(ICLRRuntimeHost* iface)
+{
+    FIXME("(%p)\n", iface);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
+{
+    FIXME("(%p)\n", iface);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
+    IHostControl *pHostControl)
+{
+    FIXME("(%p,%p)\n", iface, pHostControl);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
+    ICLRControl **pCLRControl)
+{
+    FIXME("(%p,%p)\n", iface, pCLRControl);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
+    DWORD dwAppDomainId, BOOL fWaitUntilDone)
+{
+    FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost* iface,
+    DWORD dwAppDomainId, FExecuteInAppDomainCallback pCallback, void *cookie)
+{
+    FIXME("(%p,%u,%p,%p)\n", iface, dwAppDomainId, pCallback, cookie);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
+    DWORD *pdwAppDomainId)
+{
+    FIXME("(%p,%p)\n", iface, pdwAppDomainId);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost* iface,
+    LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR *ppwzManifestPaths,
+    DWORD dwActivationData, LPCWSTR *ppwzActivationData, int *pReturnValue)
+{
+    FIXME("(%p,%s,%u,%u)\n", iface, debugstr_w(pwzAppFullName), dwManifestPaths, dwActivationData);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* iface,
+    LPCWSTR pwzAssemblyPath, LPCWSTR pwzTypeName, LPCWSTR pwzMethodName,
+    LPCWSTR pwzArgument, DWORD *pReturnValue)
+{
+    RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
+    HRESULT hr;
+    MonoDomain *domain;
+    MonoAssembly *assembly;
+    MonoImage *image;
+    MonoClass *klass;
+    MonoMethod *method;
+    MonoObject *result;
+    MonoString *str;
+    void *args[2];
+    char *filenameA = NULL, *classA = NULL, *methodA = NULL;
+    char *argsA = NULL, *ns;
+
+    TRACE("(%p,%s,%s,%s,%s)\n", iface, debugstr_w(pwzAssemblyPath),
+        debugstr_w(pwzTypeName), debugstr_w(pwzMethodName), debugstr_w(pwzArgument));
+
+    hr = RuntimeHost_GetDefaultDomain(This, &domain);
+    if(hr != S_OK)
+    {
+        ERR("Couldn't get Default Domain\n");
+        return hr;
+    }
+
+    hr = E_FAIL;
+
+    filenameA = WtoA(pwzAssemblyPath);
+    assembly = This->mono->mono_domain_assembly_open(domain, filenameA);
+    if (!assembly)
+    {
+        ERR("Cannot open assembly %s\n", filenameA);
+        goto cleanup;
+    }
+
+    image = This->mono->mono_assembly_get_image(assembly);
+    if (!image)
+    {
+        ERR("Couldn't get assembly image\n");
+        goto cleanup;
+    }
+
+    classA = WtoA(pwzTypeName);
+    ns = strrchr(classA, '.');
+    *ns = '\0';
+    klass = This->mono->mono_class_from_name(image, classA, ns+1);
+    if (!klass)
+    {
+        ERR("Couldn't get class from image\n");
+        goto cleanup;
+    }
+
+    methodA = WtoA(pwzMethodName);
+    method = This->mono->mono_class_get_method_from_name(klass, methodA, 1);
+    if (!method)
+    {
+        ERR("Couldn't get method from class\n");
+        goto cleanup;
+    }
+
+    /* The .NET function we are calling has the following declaration
+     *   public static int functionName(String param)
+     */
+    argsA = WtoA(pwzArgument);
+    str = This->mono->mono_string_new(domain, argsA);
+    args[0] = str;
+    args[1] = NULL;
+    result = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
+    if (!result)
+        ERR("Couldn't get result pointer\n");
+    else
+    {
+        *pReturnValue = *(DWORD*)This->mono->mono_object_unbox(result);
+        hr = S_OK;
+    }
+
+cleanup:
+    if(filenameA)
+        HeapFree(GetProcessHeap(), 0, filenameA);
+    if(classA)
+        HeapFree(GetProcessHeap(), 0, classA);
+    if(argsA)
+        HeapFree(GetProcessHeap(), 0, argsA);
+    if(methodA)
+        HeapFree(GetProcessHeap(), 0, methodA);
+
+    return hr;
+}
+
+static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
+{
+    CLRRuntimeHost_QueryInterface,
+    CLRRuntimeHost_AddRef,
+    CLRRuntimeHost_Release,
+    CLRRuntimeHost_Start,
+    CLRRuntimeHost_Stop,
+    CLRRuntimeHost_SetHostControl,
+    CLRRuntimeHost_GetCLRControl,
+    CLRRuntimeHost_UnloadAppDomain,
+    CLRRuntimeHost_ExecuteInAppDomain,
+    CLRRuntimeHost_GetCurrentAppDomainId,
+    CLRRuntimeHost_ExecuteApplication,
+    CLRRuntimeHost_ExecuteInDefaultAppDomain
+};
+
+/* Create an instance of a type given its name, by calling its constructor with
+ * no arguments. Note that result MUST be in the stack, or the garbage
+ * collector may free it prematurely. */
+HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
+    MonoDomain *domain, MonoObject **result)
+{
+    HRESULT hr=S_OK;
+    char *nameA=NULL;
+    MonoType *type;
+    MonoClass *klass;
+    MonoObject *obj;
+
+    if (!domain)
+        hr = RuntimeHost_GetDefaultDomain(This, &domain);
+
+    if (SUCCEEDED(hr))
+    {
+        nameA = WtoA(name);
+        if (!nameA)
+            hr = E_OUTOFMEMORY;
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        type = This->mono->mono_reflection_type_from_name(nameA, NULL);
+        if (!type)
+        {
+            ERR("Cannot find type %s\n", debugstr_w(name));
+            hr = E_FAIL;
+        }
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        klass = This->mono->mono_class_from_mono_type(type);
+        if (!klass)
+        {
+            ERR("Cannot convert type %s to a class\n", debugstr_w(name));
+            hr = E_FAIL;
+        }
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        obj = This->mono->mono_object_new(domain, klass);
+        if (!obj)
+        {
+            ERR("Cannot allocate object of type %s\n", debugstr_w(name));
+            hr = E_FAIL;
+        }
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        /* FIXME: Detect exceptions from the constructor? */
+        This->mono->mono_runtime_object_init(obj);
+        *result = obj;
+    }
+
+    HeapFree(GetProcessHeap(), 0, nameA);
+
+    return hr;
+}
+
+/* Get an IUnknown pointer for a Mono object.
+ *
+ * This is just a "light" wrapper around
+ * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
+ *
+ * NOTE: The IUnknown* is created with a reference to the object.
+ * Until they have a reference, objects must be in the stack to prevent the
+ * garbage collector from freeing them. */
+HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj,
+    IUnknown **ppUnk)
+{
+    MonoDomain *domain;
+    MonoAssembly *assembly;
+    MonoImage *image;
+    MonoClass *klass;
+    MonoMethod *method;
+    MonoObject *result;
+    void *args[2];
+
+    domain = This->mono->mono_object_get_domain(obj);
+
+    assembly = This->mono->mono_domain_assembly_open(domain, "mscorlib");
+    if (!assembly)
+    {
+        ERR("Cannot load mscorlib\n");
+        return E_FAIL;
+    }
+
+    image = This->mono->mono_assembly_get_image(assembly);
+    if (!image)
+    {
+        ERR("Couldn't get assembly image\n");
+        return E_FAIL;
+    }
+
+    klass = This->mono->mono_class_from_name(image, "System.Runtime.InteropServices", "Marshal");
+    if (!klass)
+    {
+        ERR("Couldn't get class from image\n");
+        return E_FAIL;
+    }
+
+    method = This->mono->mono_class_get_method_from_name(klass, "GetIUnknownForObject", 1);
+    if (!method)
+    {
+        ERR("Couldn't get method from class\n");
+        return E_FAIL;
+    }
+
+    args[0] = obj;
+    args[1] = NULL;
+    result = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
+    if (!result)
+    {
+        ERR("Couldn't get result pointer\n");
+        return E_FAIL;
+    }
+
+    *ppUnk = *(IUnknown**)This->mono->mono_object_unbox(result);
+    if (!*ppUnk)
+    {
+        ERR("GetIUnknownForObject returned 0\n");
+        return E_FAIL;
+    }
+
+    return S_OK;
+}
+
+static void get_utf8_args(int *argc, char ***argv)
+{
+    WCHAR **argvw;
+    int size=0, i;
+    char *current_arg;
+
+    argvw = CommandLineToArgvW(GetCommandLineW(), argc);
+
+    for (i=0; i<*argc; i++)
+    {
+        size += sizeof(char*);
+        size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
+    }
+    size += sizeof(char*);
+
+    *argv = HeapAlloc(GetProcessHeap(), 0, size);
+    current_arg = (char*)(*argv + *argc + 1);
+
+    for (i=0; i<*argc; i++)
+    {
+        (*argv)[i] = current_arg;
+        current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
+    }
+
+    (*argv)[*argc] = NULL;
+
+    HeapFree(GetProcessHeap(), 0, argvw);
+}
+
+__int32 WINAPI _CorExeMain(void)
+{
+    int exit_code;
+    int argc;
+    char **argv;
+    MonoDomain *domain;
+    MonoAssembly *assembly;
+    WCHAR filename[MAX_PATH];
+    char *filenameA;
+    ICLRRuntimeInfo *info;
+    RuntimeHost *host;
+    HRESULT hr;
+    int i;
+
+    get_utf8_args(&argc, &argv);
+
+    GetModuleFileNameW(NULL, filename, MAX_PATH);
+
+    TRACE("%s", debugstr_w(filename));
+    for (i=0; i<argc; i++)
+        TRACE(" %s", debugstr_a(argv[i]));
+    TRACE("\n");
+
+    filenameA = WtoA(filename);
+    if (!filenameA)
+        return -1;
+
+    hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
+
+        if (SUCCEEDED(hr))
+            hr = RuntimeHost_GetDefaultDomain(host, &domain);
+
+        if (SUCCEEDED(hr))
+        {
+            assembly = host->mono->mono_domain_assembly_open(domain, filenameA);
+
+            exit_code = host->mono->mono_jit_exec(domain, assembly, argc, argv);
+
+            RuntimeHost_DeleteDomain(host, domain);
+        }
+        else
+            exit_code = -1;
+
+        ICLRRuntimeInfo_Release(info);
+    }
+    else
+        exit_code = -1;
+
+    HeapFree(GetProcessHeap(), 0, argv);
+
+    unload_all_runtimes();
+
+    return exit_code;
+}
+
+HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version,
+    loaded_mono *loaded_mono, RuntimeHost** result)
+{
+    RuntimeHost *This;
 
     This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
     if ( !This )
-        return NULL;
+        return E_OUTOFMEMORY;
+
+    This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
+    This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
 
-    This->lpVtbl = &corruntimehost_vtbl;
     This->ref = 1;
+    This->version = runtime_version;
+    This->mono = loaded_mono;
+    list_init(&This->domains);
+    This->default_domain = NULL;
+    InitializeCriticalSection(&This->lock);
+    This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
 
-    FIXME("return iface %p\n", This);
+    *result = This;
 
-    return (IUnknown*) &This->lpVtbl;
+    return S_OK;
+}
+
+HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
+{
+    IUnknown *unk;
+    HRESULT hr;
+
+    if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
+    {
+        unk = (IUnknown*)&This->ICorRuntimeHost_iface;
+        IUnknown_AddRef(unk);
+    }
+    else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
+    {
+        unk = (IUnknown*)&This->ICLRRuntimeHost_iface;
+        IUnknown_AddRef(unk);
+    }
+    else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
+             IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
+    {
+        hr = MetaDataDispenser_CreateInstance(&unk);
+        if (FAILED(hr))
+            return hr;
+    }
+    else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
+    {
+        hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
+        if (FAILED(hr))
+            return hr;
+    }
+    else
+        unk = NULL;
+
+    if (unk)
+    {
+        hr = IUnknown_QueryInterface(unk, riid, ppv);
+
+        IUnknown_Release(unk);
+
+        return hr;
+    }
+    else
+        FIXME("not implemented for class %s\n", debugstr_guid(clsid));
+
+    return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+HRESULT RuntimeHost_Destroy(RuntimeHost *This)
+{
+    struct DomainEntry *cursor, *cursor2;
+
+    This->lock.DebugInfo->Spare[0] = 0;
+    DeleteCriticalSection(&This->lock);
+
+    LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->domains, struct DomainEntry, entry)
+    {
+        list_remove(&cursor->entry);
+        HeapFree(GetProcessHeap(), 0, cursor);
+    }
+
+    HeapFree( GetProcessHeap(), 0, This );
+    return S_OK;
 }
diff --git a/reactos/dll/win32/mscoree/metadata.c b/reactos/dll/win32/mscoree/metadata.c
new file mode 100644 (file)
index 0000000..9ca0d93
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * IMetaDataDispenserEx - dynamic creation/editing of assemblies
+ *
+ * Copyright 2010 Vincent Povirk for CodeWeavers
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#define COBJMACROS
+
+#include "wine/library.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "ole2.h"
+#include "cor.h"
+#include "mscoree.h"
+#include "corhdr.h"
+#include "cordebug.h"
+#include "metahost.h"
+#include "wine/list.h"
+#include "mscoree_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
+
+typedef struct MetaDataDispenser
+{
+    IMetaDataDispenserEx IMetaDataDispenserEx_iface;
+    LONG ref;
+} MetaDataDispenser;
+
+static inline MetaDataDispenser *impl_from_IMetaDataDispenserEx(IMetaDataDispenserEx *iface)
+{
+    return CONTAINING_RECORD(iface, MetaDataDispenser, IMetaDataDispenserEx_iface);
+}
+
+static HRESULT WINAPI MetaDataDispenser_QueryInterface(IMetaDataDispenserEx* iface,
+    REFIID riid, void **ppvObject)
+{
+    TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
+
+    if (IsEqualGUID(riid, &IID_IMetaDataDispenserEx) ||
+        IsEqualGUID(riid, &IID_IMetaDataDispenser) ||
+        IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *ppvObject = iface;
+    }
+    else
+    {
+        FIXME("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IMetaDataDispenserEx_AddRef( iface );
+
+    return S_OK;
+}
+
+static ULONG WINAPI MetaDataDispenser_AddRef(IMetaDataDispenserEx* iface)
+{
+    MetaDataDispenser *This = impl_from_IMetaDataDispenserEx(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("%p ref=%u\n", This, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI MetaDataDispenser_Release(IMetaDataDispenserEx* iface)
+{
+    MetaDataDispenser *This = impl_from_IMetaDataDispenserEx(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("%p ref=%u\n", This, ref);
+
+    if (ref == 0)
+    {
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI MetaDataDispenser_DefineScope(IMetaDataDispenserEx* iface,
+    REFCLSID rclsid, DWORD dwCreateFlags, REFIID riid, IUnknown **ppIUnk)
+{
+    FIXME("%p %s %x %s %p\n", iface, debugstr_guid(rclsid), dwCreateFlags,
+        debugstr_guid(riid), ppIUnk);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MetaDataDispenser_OpenScope(IMetaDataDispenserEx* iface,
+    LPCWSTR szScope, DWORD dwOpenFlags, REFIID riid, IUnknown **ppIUnk)
+{
+    FIXME("%p %s %x %s %p\n", iface, debugstr_w(szScope), dwOpenFlags,
+        debugstr_guid(riid), ppIUnk);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MetaDataDispenser_OpenScopeOnMemory(IMetaDataDispenserEx* iface,
+    const void *pData, ULONG cbData, DWORD dwOpenFlags, REFIID riid, IUnknown **ppIUnk)
+{
+    FIXME("%p %p %u %x %s %p\n", iface, pData, cbData, dwOpenFlags,
+        debugstr_guid(riid), ppIUnk);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MetaDataDispenser_SetOption(IMetaDataDispenserEx* iface,
+    REFGUID optionid, const VARIANT *value)
+{
+    FIXME("%p %s\n", iface, debugstr_guid(optionid));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MetaDataDispenser_GetOption(IMetaDataDispenserEx* iface,
+    REFGUID optionid, VARIANT *pvalue)
+{
+    FIXME("%p %s\n", iface, debugstr_guid(optionid));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MetaDataDispenser_OpenScopeOnITypeInfo(IMetaDataDispenserEx* iface,
+    ITypeInfo *pITI, DWORD dwOpenFlags, REFIID riid, IUnknown **ppIUnk)
+{
+    FIXME("%p %p %u %s %p\n", iface, pITI, dwOpenFlags, debugstr_guid(riid), ppIUnk);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MetaDataDispenser_GetCORSystemDirectory(IMetaDataDispenserEx* iface,
+    LPWSTR szBuffer, DWORD cchBuffer, DWORD *pchBuffer)
+{
+    FIXME("%p %p %u %p\n", iface, szBuffer, cchBuffer, pchBuffer);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MetaDataDispenser_FindAssembly(IMetaDataDispenserEx* iface,
+    LPCWSTR szAppBase, LPCWSTR szPrivateBin, LPCWSTR szGlobalBin, LPCWSTR szAssemblyName,
+    LPWSTR szName, ULONG cchName, ULONG *pcName)
+{
+    FIXME("%p %s %s %s %s %p %u %p\n", iface, debugstr_w(szAppBase),
+        debugstr_w(szPrivateBin), debugstr_w(szGlobalBin),
+        debugstr_w(szAssemblyName), szName, cchName, pcName);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MetaDataDispenser_FindAssemblyModule(IMetaDataDispenserEx* iface,
+    LPCWSTR szAppBase, LPCWSTR szPrivateBin, LPCWSTR szGlobalBin, LPCWSTR szAssemblyName,
+    LPCWSTR szModuleName, LPWSTR szName, ULONG cchName, ULONG *pcName)
+{
+    FIXME("%p %s %s %s %s %s %p %u %p\n", iface, debugstr_w(szAppBase),
+        debugstr_w(szPrivateBin), debugstr_w(szGlobalBin), debugstr_w(szAssemblyName),
+        debugstr_w(szModuleName), szName, cchName, pcName);
+    return E_NOTIMPL;
+}
+
+static const struct IMetaDataDispenserExVtbl MetaDataDispenserVtbl =
+{
+    MetaDataDispenser_QueryInterface,
+    MetaDataDispenser_AddRef,
+    MetaDataDispenser_Release,
+    MetaDataDispenser_DefineScope,
+    MetaDataDispenser_OpenScope,
+    MetaDataDispenser_OpenScopeOnMemory,
+    MetaDataDispenser_SetOption,
+    MetaDataDispenser_GetOption,
+    MetaDataDispenser_OpenScopeOnITypeInfo,
+    MetaDataDispenser_GetCORSystemDirectory,
+    MetaDataDispenser_FindAssembly,
+    MetaDataDispenser_FindAssemblyModule
+};
+
+HRESULT MetaDataDispenser_CreateInstance(IUnknown **ppUnk)
+{
+    MetaDataDispenser *This;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(MetaDataDispenser));
+
+    if (!This)
+        return E_OUTOFMEMORY;
+
+    This->IMetaDataDispenserEx_iface.lpVtbl = &MetaDataDispenserVtbl;
+    This->ref = 1;
+
+    *ppUnk = (IUnknown*)This;
+
+    return S_OK;
+}
diff --git a/reactos/dll/win32/mscoree/metahost.c b/reactos/dll/win32/mscoree/metahost.c
new file mode 100644 (file)
index 0000000..49fb0ee
--- /dev/null
@@ -0,0 +1,1341 @@
+/*
+ * ICLRMetaHost - discovery and management of available .NET runtimes
+ *
+ * Copyright 2010 Vincent Povirk for CodeWeavers
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#define COBJMACROS
+
+#include "wine/unicode.h"
+#include "wine/library.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "ole2.h"
+
+#include "corerror.h"
+#include "cor.h"
+#include "mscoree.h"
+#include "corhdr.h"
+#include "cordebug.h"
+#include "metahost.h"
+#include "fusion.h"
+#include "wine/list.h"
+#include "mscoree_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
+
+static const WCHAR net_11_subdir[] = {'1','.','0',0};
+static const WCHAR net_20_subdir[] = {'2','.','0',0};
+static const WCHAR net_40_subdir[] = {'4','.','0',0};
+
+static const struct ICLRRuntimeInfoVtbl CLRRuntimeInfoVtbl;
+
+#define NUM_RUNTIMES 3
+
+static struct CLRRuntimeInfo runtimes[NUM_RUNTIMES] = {
+    {{&CLRRuntimeInfoVtbl}, net_11_subdir, 1, 1, 4322, 0},
+    {{&CLRRuntimeInfoVtbl}, net_20_subdir, 2, 0, 50727, 0},
+    {{&CLRRuntimeInfoVtbl}, net_40_subdir, 4, 0, 30319, 0}
+};
+
+static int runtimes_initialized;
+
+static CRITICAL_SECTION runtime_list_cs;
+static CRITICAL_SECTION_DEBUG runtime_list_cs_debug =
+{
+    0, 0, &runtime_list_cs,
+    { &runtime_list_cs_debug.ProcessLocksList,
+      &runtime_list_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": runtime_list_cs") }
+};
+static CRITICAL_SECTION runtime_list_cs = { &runtime_list_cs_debug, -1, 0, 0, 0, 0 };
+
+#define NUM_ABI_VERSIONS 2
+
+static loaded_mono loaded_monos[NUM_ABI_VERSIONS];
+
+static BOOL find_mono_dll(LPCWSTR path, LPWSTR dll_path, int abi_version);
+
+static MonoAssembly* mono_assembly_search_hook_fn(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
+
+static void mono_shutdown_callback_fn(MonoProfiler *prof);
+
+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 void CDECL do_nothing(void)
+{
+}
+
+static void missing_runtime_message(const CLRRuntimeInfo *This)
+{
+    if (This->major == 1)
+        MESSAGE("wine: Install Mono 2.6 for Windows to run .NET 1.1 applications.\n");
+    else if (This->major == 2)
+        MESSAGE("wine: Install Mono for Windows to run .NET 2.0 applications.\n");
+    else if (This->major == 4)
+        MESSAGE("wine: Install Mono 2.8 or greater for Windows to run .NET 4.0 applications.\n");
+}
+
+static HRESULT load_mono(CLRRuntimeInfo *This, loaded_mono **result)
+{
+    static const WCHAR bin[] = {'\\','b','i','n',0};
+    static const WCHAR lib[] = {'\\','l','i','b',0};
+    static const WCHAR etc[] = {'\\','e','t','c',0};
+    static const WCHAR glibdll[] = {'l','i','b','g','l','i','b','-','2','.','0','-','0','.','d','l','l',0};
+    WCHAR mono_dll_path[MAX_PATH+16], mono_bin_path[MAX_PATH+4];
+    WCHAR mono_lib_path[MAX_PATH+4], mono_etc_path[MAX_PATH+4];
+    char mono_lib_path_a[MAX_PATH], mono_etc_path_a[MAX_PATH];
+    int trace_size;
+    char trace_setting[256];
+
+    if (This->mono_abi_version <= 0 || This->mono_abi_version > NUM_ABI_VERSIONS)
+    {
+        missing_runtime_message(This);
+        return E_FAIL;
+    }
+
+    *result = &loaded_monos[This->mono_abi_version-1];
+
+    if ((*result)->is_shutdown)
+    {
+        ERR("Cannot load Mono after it has been shut down.\n");
+        *result = NULL;
+        return E_FAIL;
+    }
+
+    if (!(*result)->mono_handle)
+    {
+        strcpyW(mono_bin_path, This->mono_path);
+        strcatW(mono_bin_path, bin);
+        set_environment(mono_bin_path);
+
+        strcpyW(mono_lib_path, This->mono_path);
+        strcatW(mono_lib_path, lib);
+        WideCharToMultiByte(CP_UTF8, 0, mono_lib_path, -1, mono_lib_path_a, MAX_PATH, NULL, NULL);
+
+        strcpyW(mono_etc_path, This->mono_path);
+        strcatW(mono_etc_path, etc);
+        WideCharToMultiByte(CP_UTF8, 0, mono_etc_path, -1, mono_etc_path_a, MAX_PATH, NULL, NULL);
+
+        if (!find_mono_dll(This->mono_path, mono_dll_path, This->mono_abi_version)) goto fail;
+
+        (*result)->mono_handle = LoadLibraryW(mono_dll_path);
+
+        if (!(*result)->mono_handle) goto fail;
+
+#define LOAD_MONO_FUNCTION(x) do { \
+    (*result)->x = (void*)GetProcAddress((*result)->mono_handle, #x); \
+    if (!(*result)->x) { \
+        goto fail; \
+    } \
+} while (0);
+
+        LOAD_MONO_FUNCTION(mono_assembly_get_image);
+        LOAD_MONO_FUNCTION(mono_assembly_open);
+        LOAD_MONO_FUNCTION(mono_config_parse);
+        LOAD_MONO_FUNCTION(mono_class_from_mono_type);
+        LOAD_MONO_FUNCTION(mono_class_from_name);
+        LOAD_MONO_FUNCTION(mono_class_get_method_from_name);
+        LOAD_MONO_FUNCTION(mono_domain_assembly_open);
+        LOAD_MONO_FUNCTION(mono_install_assembly_preload_hook);
+        LOAD_MONO_FUNCTION(mono_jit_exec);
+        LOAD_MONO_FUNCTION(mono_jit_init);
+        LOAD_MONO_FUNCTION(mono_jit_set_trace_options);
+        LOAD_MONO_FUNCTION(mono_object_get_domain);
+        LOAD_MONO_FUNCTION(mono_object_new);
+        LOAD_MONO_FUNCTION(mono_object_unbox);
+        LOAD_MONO_FUNCTION(mono_profiler_install);
+        LOAD_MONO_FUNCTION(mono_reflection_type_from_name);
+        LOAD_MONO_FUNCTION(mono_runtime_invoke);
+        LOAD_MONO_FUNCTION(mono_runtime_object_init);
+        LOAD_MONO_FUNCTION(mono_runtime_quit);
+        LOAD_MONO_FUNCTION(mono_set_dirs);
+        LOAD_MONO_FUNCTION(mono_stringify_assembly_name);
+        LOAD_MONO_FUNCTION(mono_string_new);
+
+        /* GLib imports obsoleted by the 2.0 ABI */
+        if (This->mono_abi_version == 1)
+        {
+            (*result)->glib_handle = LoadLibraryW(glibdll);
+            if (!(*result)->glib_handle) goto fail;
+
+            (*result)->mono_free = (void*)GetProcAddress((*result)->glib_handle, "g_free");
+            if (!(*result)->mono_free) goto fail;
+        }
+        else
+        {
+            LOAD_MONO_FUNCTION(mono_free);
+        }
+
+#undef LOAD_MONO_FUNCTION
+
+#define LOAD_OPT_VOID_MONO_FUNCTION(x) do { \
+    (*result)->x = (void*)GetProcAddress((*result)->mono_handle, #x); \
+    if (!(*result)->x) { \
+        (*result)->x = do_nothing; \
+    } \
+} while (0);
+
+        LOAD_OPT_VOID_MONO_FUNCTION(mono_runtime_set_shutting_down);
+        LOAD_OPT_VOID_MONO_FUNCTION(mono_thread_pool_cleanup);
+        LOAD_OPT_VOID_MONO_FUNCTION(mono_thread_suspend_all_other_threads);
+        LOAD_OPT_VOID_MONO_FUNCTION(mono_threads_set_shutting_down);
+
+#undef LOAD_OPT_VOID_MONO_FUNCTION
+
+        (*result)->mono_profiler_install((MonoProfiler*)*result, mono_shutdown_callback_fn);
+
+        (*result)->mono_set_dirs(mono_lib_path_a, mono_etc_path_a);
+
+        (*result)->mono_config_parse(NULL);
+
+        (*result)->mono_install_assembly_preload_hook(mono_assembly_search_hook_fn, *result);
+
+        trace_size = GetEnvironmentVariableA("WINE_MONO_TRACE", trace_setting, sizeof(trace_setting));
+
+        if (trace_size)
+        {
+            (*result)->mono_jit_set_trace_options(trace_setting);
+        }
+    }
+
+    return S_OK;
+
+fail:
+    ERR("Could not load Mono into this process\n");
+    FreeLibrary((*result)->mono_handle);
+    FreeLibrary((*result)->glib_handle);
+    (*result)->mono_handle = NULL;
+    (*result)->glib_handle = NULL;
+    return E_FAIL;
+}
+
+static void mono_shutdown_callback_fn(MonoProfiler *prof)
+{
+    loaded_mono *mono = (loaded_mono*)prof;
+
+    mono->is_shutdown = TRUE;
+}
+
+static HRESULT CLRRuntimeInfo_GetRuntimeHost(CLRRuntimeInfo *This, RuntimeHost **result)
+{
+    HRESULT hr = S_OK;
+    loaded_mono *ploaded_mono;
+
+    if (This->loaded_runtime)
+    {
+        *result = This->loaded_runtime;
+        return hr;
+    }
+
+    EnterCriticalSection(&runtime_list_cs);
+
+    hr = load_mono(This, &ploaded_mono);
+
+    if (SUCCEEDED(hr))
+        hr = RuntimeHost_Construct(This, ploaded_mono, &This->loaded_runtime);
+
+    LeaveCriticalSection(&runtime_list_cs);
+
+    if (SUCCEEDED(hr))
+        *result = This->loaded_runtime;
+
+    return hr;
+}
+
+void unload_all_runtimes(void)
+{
+    int i;
+
+    for (i=0; i<NUM_ABI_VERSIONS; i++)
+    {
+        loaded_mono *mono = &loaded_monos[i];
+        if (mono->mono_handle && mono->is_started && !mono->is_shutdown)
+        {
+            /* Copied from Mono's ves_icall_System_Environment_Exit */
+           mono->mono_threads_set_shutting_down();
+           mono->mono_runtime_set_shutting_down();
+           mono->mono_thread_pool_cleanup();
+           mono->mono_thread_suspend_all_other_threads();
+           mono->mono_runtime_quit();
+        }
+    }
+
+    for (i=0; i<NUM_RUNTIMES; i++)
+        if (runtimes[i].loaded_runtime)
+            RuntimeHost_Destroy(runtimes[i].loaded_runtime);
+}
+
+void expect_no_runtimes(void)
+{
+    int i;
+
+    for (i=0; i<NUM_ABI_VERSIONS; i++)
+    {
+        loaded_mono *mono = &loaded_monos[i];
+        if (mono->mono_handle && mono->is_started && !mono->is_shutdown)
+        {
+            ERR("Process exited with a Mono runtime loaded.\n");
+            return;
+        }
+    }
+}
+
+static inline CLRRuntimeInfo *impl_from_ICLRRuntimeInfo(ICLRRuntimeInfo *iface)
+{
+    return CONTAINING_RECORD(iface, CLRRuntimeInfo, ICLRRuntimeInfo_iface);
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_QueryInterface(ICLRRuntimeInfo* iface,
+        REFIID riid,
+        void **ppvObject)
+{
+    TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
+
+    if ( IsEqualGUID( riid, &IID_ICLRRuntimeInfo ) ||
+         IsEqualGUID( riid, &IID_IUnknown ) )
+    {
+        *ppvObject = iface;
+    }
+    else
+    {
+        FIXME("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    ICLRRuntimeInfo_AddRef( iface );
+
+    return S_OK;
+}
+
+static ULONG WINAPI CLRRuntimeInfo_AddRef(ICLRRuntimeInfo* iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI CLRRuntimeInfo_Release(ICLRRuntimeInfo* iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_GetVersionString(ICLRRuntimeInfo* iface,
+    LPWSTR pwzBuffer, DWORD *pcchBuffer)
+{
+    struct CLRRuntimeInfo *This = impl_from_ICLRRuntimeInfo(iface);
+    DWORD buffer_size = *pcchBuffer;
+    HRESULT hr = S_OK;
+    char version[11];
+    DWORD size;
+
+    TRACE("%p %p %p\n", iface, pwzBuffer, pcchBuffer);
+
+    size = snprintf(version, sizeof(version), "v%u.%u.%u", This->major, This->minor, This->build);
+
+    assert(size <= sizeof(version));
+
+    *pcchBuffer = MultiByteToWideChar(CP_UTF8, 0, version, -1, NULL, 0);
+
+    if (pwzBuffer)
+    {
+        if (buffer_size >= *pcchBuffer)
+            MultiByteToWideChar(CP_UTF8, 0, version, -1, pwzBuffer, buffer_size);
+        else
+            hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+    }
+
+    return hr;
+}
+
+static BOOL get_install_root(LPWSTR install_dir)
+{
+    const WCHAR dotnet_key[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\','.','N','E','T','F','r','a','m','e','w','o','r','k','\\',0};
+    const WCHAR install_root[] = {'I','n','s','t','a','l','l','R','o','o','t',0};
+
+    DWORD len;
+    HKEY key;
+
+    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, dotnet_key, 0, KEY_READ, &key))
+        return FALSE;
+
+    len = MAX_PATH;
+    if (RegQueryValueExW(key, install_root, 0, NULL, (LPBYTE)install_dir, &len))
+    {
+        RegCloseKey(key);
+        return FALSE;
+    }
+    RegCloseKey(key);
+
+    return TRUE;
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_GetRuntimeDirectory(ICLRRuntimeInfo* iface,
+    LPWSTR pwzBuffer, DWORD *pcchBuffer)
+{
+    static const WCHAR slash[] = {'\\',0};
+    DWORD buffer_size = *pcchBuffer;
+    WCHAR system_dir[MAX_PATH];
+    WCHAR version[MAX_PATH];
+    DWORD version_size, size;
+    HRESULT hr = S_OK;
+
+    TRACE("%p %p %p\n", iface, pwzBuffer, pcchBuffer);
+
+    if (!get_install_root(system_dir))
+    {
+        ERR("error reading registry key for installroot\n");
+        return E_FAIL;
+    }
+    else
+    {
+        version_size = MAX_PATH;
+        ICLRRuntimeInfo_GetVersionString(iface, version, &version_size);
+        lstrcatW(system_dir, version);
+        lstrcatW(system_dir, slash);
+        size = lstrlenW(system_dir) + 1;
+    }
+
+    *pcchBuffer = size;
+
+    if (pwzBuffer)
+    {
+        if (buffer_size >= size)
+            strcpyW(pwzBuffer, system_dir);
+        else
+            hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_IsLoaded(ICLRRuntimeInfo* iface,
+    HANDLE hndProcess, BOOL *pbLoaded)
+{
+    FIXME("%p %p %p\n", iface, hndProcess, pbLoaded);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_LoadErrorString(ICLRRuntimeInfo* iface,
+    UINT iResourceID, LPWSTR pwzBuffer, DWORD *pcchBuffer, LONG iLocaleid)
+{
+    FIXME("%p %u %p %p %x\n", iface, iResourceID, pwzBuffer, pcchBuffer, iLocaleid);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_LoadLibrary(ICLRRuntimeInfo* iface,
+    LPCWSTR pwzDllName, HMODULE *phndModule)
+{
+    WCHAR version[MAX_PATH];
+    HRESULT hr;
+    DWORD cchBuffer;
+
+    TRACE("%p %s %p\n", iface, debugstr_w(pwzDllName), phndModule);
+
+    cchBuffer = MAX_PATH;
+    hr = ICLRRuntimeInfo_GetVersionString(iface, version, &cchBuffer);
+    if (FAILED(hr)) return hr;
+
+    return LoadLibraryShim(pwzDllName, version, NULL, phndModule);
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_GetProcAddress(ICLRRuntimeInfo* iface,
+    LPCSTR pszProcName, LPVOID *ppProc)
+{
+    FIXME("%p %s %p\n", iface, debugstr_a(pszProcName), ppProc);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_GetInterface(ICLRRuntimeInfo* iface,
+    REFCLSID rclsid, REFIID riid, LPVOID *ppUnk)
+{
+    struct CLRRuntimeInfo *This = impl_from_ICLRRuntimeInfo(iface);
+    RuntimeHost *host;
+    HRESULT hr;
+
+    TRACE("%p %s %s %p\n", iface, debugstr_guid(rclsid), debugstr_guid(riid), ppUnk);
+
+    hr = CLRRuntimeInfo_GetRuntimeHost(This, &host);
+
+    if (SUCCEEDED(hr))
+        hr = RuntimeHost_GetInterface(host, rclsid, riid, ppUnk);
+
+    return hr;
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_IsLoadable(ICLRRuntimeInfo* iface,
+    BOOL *pbLoadable)
+{
+    FIXME("%p %p\n", iface, pbLoadable);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_SetDefaultStartupFlags(ICLRRuntimeInfo* iface,
+    DWORD dwStartupFlags, LPCWSTR pwzHostConfigFile)
+{
+    FIXME("%p %x %s\n", iface, dwStartupFlags, debugstr_w(pwzHostConfigFile));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_GetDefaultStartupFlags(ICLRRuntimeInfo* iface,
+    DWORD *pdwStartupFlags, LPWSTR pwzHostConfigFile, DWORD *pcchHostConfigFile)
+{
+    FIXME("%p %p %p %p\n", iface, pdwStartupFlags, pwzHostConfigFile, pcchHostConfigFile);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_BindAsLegacyV2Runtime(ICLRRuntimeInfo* iface)
+{
+    FIXME("%p\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRRuntimeInfo_IsStarted(ICLRRuntimeInfo* iface,
+    BOOL *pbStarted, DWORD *pdwStartupFlags)
+{
+    FIXME("%p %p %p\n", iface, pbStarted, pdwStartupFlags);
+
+    return E_NOTIMPL;
+}
+
+static const struct ICLRRuntimeInfoVtbl CLRRuntimeInfoVtbl = {
+    CLRRuntimeInfo_QueryInterface,
+    CLRRuntimeInfo_AddRef,
+    CLRRuntimeInfo_Release,
+    CLRRuntimeInfo_GetVersionString,
+    CLRRuntimeInfo_GetRuntimeDirectory,
+    CLRRuntimeInfo_IsLoaded,
+    CLRRuntimeInfo_LoadErrorString,
+    CLRRuntimeInfo_LoadLibrary,
+    CLRRuntimeInfo_GetProcAddress,
+    CLRRuntimeInfo_GetInterface,
+    CLRRuntimeInfo_IsLoadable,
+    CLRRuntimeInfo_SetDefaultStartupFlags,
+    CLRRuntimeInfo_GetDefaultStartupFlags,
+    CLRRuntimeInfo_BindAsLegacyV2Runtime,
+    CLRRuntimeInfo_IsStarted
+};
+
+HRESULT ICLRRuntimeInfo_GetRuntimeHost(ICLRRuntimeInfo *iface, RuntimeHost **result)
+{
+    struct CLRRuntimeInfo *This = impl_from_ICLRRuntimeInfo(iface);
+
+    assert(This->ICLRRuntimeInfo_iface.lpVtbl == &CLRRuntimeInfoVtbl);
+
+    return CLRRuntimeInfo_GetRuntimeHost(This, result);
+}
+
+static BOOL find_mono_dll(LPCWSTR path, LPWSTR dll_path, int abi_version)
+{
+    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 mono2_dll[] = {'\\','b','i','n','\\','m','o','n','o','-','2','.','0','.','d','l','l',0};
+    static const WCHAR libmono2_dll[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','.','d','l','l',0};
+    DWORD attributes=INVALID_FILE_ATTRIBUTES;
+
+    if (abi_version == 1)
+    {
+        strcpyW(dll_path, path);
+        strcatW(dll_path, mono_dll);
+        attributes = GetFileAttributesW(dll_path);
+
+        if (attributes == INVALID_FILE_ATTRIBUTES)
+        {
+            strcpyW(dll_path, path);
+            strcatW(dll_path, libmono_dll);
+            attributes = GetFileAttributesW(dll_path);
+        }
+    }
+    else if (abi_version == 2)
+    {
+        strcpyW(dll_path, path);
+        strcatW(dll_path, mono2_dll);
+        attributes = GetFileAttributesW(dll_path);
+
+        if (attributes == INVALID_FILE_ATTRIBUTES)
+        {
+            strcpyW(dll_path, path);
+            strcatW(dll_path, libmono2_dll);
+            attributes = GetFileAttributesW(dll_path);
+        }
+    }
+
+    return (attributes != INVALID_FILE_ATTRIBUTES);
+}
+
+static BOOL get_mono_path_from_registry(LPWSTR path, int abi_version)
+{
+    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};
+    static const WCHAR slash[] = {'\\',0};
+
+    WCHAR version[64], version_key[MAX_PATH];
+    DWORD len;
+    HKEY key;
+    WCHAR dll_path[MAX_PATH];
+
+    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, mono_key, 0, KEY_READ, &key))
+        return FALSE;
+
+    len = sizeof(version);
+    if (RegQueryValueExW(key, defaul_clr, 0, NULL, (LPBYTE)version, &len))
+    {
+        RegCloseKey(key);
+        return FALSE;
+    }
+    RegCloseKey(key);
+
+    lstrcpyW(version_key, mono_key);
+    lstrcatW(version_key, slash);
+    lstrcatW(version_key, version);
+
+    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, version_key, 0, KEY_READ, &key))
+        return FALSE;
+
+    len = sizeof(WCHAR) * MAX_PATH;
+    if (RegQueryValueExW(key, install_root, 0, NULL, (LPBYTE)path, &len))
+    {
+        RegCloseKey(key);
+        return FALSE;
+    }
+    RegCloseKey(key);
+
+    return find_mono_dll(path, dll_path, abi_version);
+}
+
+static BOOL get_mono_path_from_folder(LPCWSTR folder, LPWSTR mono_path, int abi_version)
+{
+    static const WCHAR mono_one_dot_zero[] = {'\\','m','o','n','o','-','1','.','0', 0};
+    static const WCHAR mono_two_dot_zero[] = {'\\','m','o','n','o','-','2','.','0', 0};
+    WCHAR mono_dll_path[MAX_PATH];
+    BOOL found = FALSE;
+
+    strcpyW(mono_path, folder);
+
+    if (abi_version == 1)
+        strcatW(mono_path, mono_one_dot_zero);
+    else if (abi_version == 2)
+        strcatW(mono_path, mono_two_dot_zero);
+
+    found = find_mono_dll(mono_path, mono_dll_path, abi_version);
+
+    return found;
+}
+
+static BOOL get_mono_path(LPWSTR path, int abi_version)
+{
+    static const WCHAR subdir_mono[] = {'\\','m','o','n','o',0};
+    static const WCHAR sibling_mono[] = {'\\','.','.','\\','m','o','n','o',0};
+    WCHAR base_path[MAX_PATH];
+    const char *unix_data_dir;
+    WCHAR *dos_data_dir;
+    int build_tree=0;
+    static WCHAR* (CDECL *wine_get_dos_file_name)(const char*);
+
+    /* First try c:\windows\mono */
+    GetWindowsDirectoryW(base_path, MAX_PATH);
+    strcatW(base_path, subdir_mono);
+
+    if (get_mono_path_from_folder(base_path, path, abi_version))
+        return TRUE;
+
+    /* Next: /usr/share/wine/mono */
+    unix_data_dir = wine_get_data_dir();
+
+    if (!unix_data_dir)
+    {
+        unix_data_dir = wine_get_build_dir();
+        build_tree = 1;
+    }
+
+    if (unix_data_dir)
+    {
+        if (!wine_get_dos_file_name)
+            wine_get_dos_file_name = (void*)GetProcAddress(GetModuleHandleA("kernel32"), "wine_get_dos_file_name");
+
+        if (wine_get_dos_file_name)
+        {
+            dos_data_dir = wine_get_dos_file_name(unix_data_dir);
+
+            if (dos_data_dir)
+            {
+                strcpyW(base_path, dos_data_dir);
+                strcatW(base_path, build_tree ? sibling_mono : subdir_mono);
+
+                HeapFree(GetProcessHeap(), 0, dos_data_dir);
+
+                if (get_mono_path_from_folder(base_path, path, abi_version))
+                    return TRUE;
+            }
+        }
+    }
+
+    /* Last: the registry */
+    return get_mono_path_from_registry(path, abi_version);
+}
+
+static void find_runtimes(void)
+{
+    int abi_version, i;
+    static const WCHAR libmono[] = {'\\','l','i','b','\\','m','o','n','o','\\',0};
+    static const WCHAR mscorlib[] = {'\\','m','s','c','o','r','l','i','b','.','d','l','l',0};
+    WCHAR mono_path[MAX_PATH], lib_path[MAX_PATH];
+    BOOL any_runtimes_found = FALSE;
+
+    if (runtimes_initialized) return;
+
+    EnterCriticalSection(&runtime_list_cs);
+
+    if (runtimes_initialized) goto end;
+
+    for (abi_version=NUM_ABI_VERSIONS; abi_version>0; abi_version--)
+    {
+        if (!get_mono_path(mono_path, abi_version))
+            continue;
+
+        for (i=0; i<NUM_RUNTIMES; i++)
+        {
+            if (runtimes[i].mono_abi_version == 0)
+            {
+                strcpyW(lib_path, mono_path);
+                strcatW(lib_path, libmono);
+                strcatW(lib_path, runtimes[i].mono_libdir);
+                strcatW(lib_path, mscorlib);
+
+                if (GetFileAttributesW(lib_path) != INVALID_FILE_ATTRIBUTES)
+                {
+                    runtimes[i].mono_abi_version = abi_version;
+
+                    strcpyW(runtimes[i].mono_path, mono_path);
+                    strcpyW(runtimes[i].mscorlib_path, lib_path);
+
+                    any_runtimes_found = TRUE;
+                }
+            }
+        }
+    }
+
+    if (!any_runtimes_found)
+    {
+        /* Report all runtimes are available if Mono isn't installed.
+         * FIXME: Remove this when Mono is properly packaged. */
+        for (i=0; i<NUM_RUNTIMES; i++)
+            runtimes[i].mono_abi_version = -1;
+    }
+
+    runtimes_initialized = 1;
+
+end:
+    LeaveCriticalSection(&runtime_list_cs);
+}
+
+struct InstalledRuntimeEnum
+{
+    IEnumUnknown IEnumUnknown_iface;
+    LONG ref;
+    ULONG pos;
+};
+
+static const struct IEnumUnknownVtbl InstalledRuntimeEnum_Vtbl;
+
+static inline struct InstalledRuntimeEnum *impl_from_IEnumUnknown(IEnumUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, struct InstalledRuntimeEnum, IEnumUnknown_iface);
+}
+
+static HRESULT WINAPI InstalledRuntimeEnum_QueryInterface(IEnumUnknown* iface, REFIID riid,
+        void **ppvObject)
+{
+    TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
+
+    if ( IsEqualGUID( riid, &IID_IEnumUnknown ) ||
+         IsEqualGUID( riid, &IID_IUnknown ) )
+    {
+        *ppvObject = iface;
+    }
+    else
+    {
+        FIXME("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IEnumUnknown_AddRef( iface );
+
+    return S_OK;
+}
+
+static ULONG WINAPI InstalledRuntimeEnum_AddRef(IEnumUnknown* iface)
+{
+    struct InstalledRuntimeEnum *This = impl_from_IEnumUnknown(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI InstalledRuntimeEnum_Release(IEnumUnknown* iface)
+{
+    struct InstalledRuntimeEnum *This = impl_from_IEnumUnknown(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI InstalledRuntimeEnum_Next(IEnumUnknown *iface, ULONG celt,
+    IUnknown **rgelt, ULONG *pceltFetched)
+{
+    struct InstalledRuntimeEnum *This = impl_from_IEnumUnknown(iface);
+    int num_fetched = 0;
+    HRESULT hr=S_OK;
+    IUnknown *item;
+
+    TRACE("(%p,%u,%p,%p)\n", iface, celt, rgelt, pceltFetched);
+
+    while (num_fetched < celt)
+    {
+        if (This->pos >= NUM_RUNTIMES)
+        {
+            hr = S_FALSE;
+            break;
+        }
+        if (runtimes[This->pos].mono_abi_version)
+        {
+            item = (IUnknown*)&runtimes[This->pos].ICLRRuntimeInfo_iface;
+            IUnknown_AddRef(item);
+            rgelt[num_fetched] = item;
+            num_fetched++;
+        }
+        This->pos++;
+    }
+
+    if (pceltFetched)
+        *pceltFetched = num_fetched;
+
+    return hr;
+}
+
+static HRESULT WINAPI InstalledRuntimeEnum_Skip(IEnumUnknown *iface, ULONG celt)
+{
+    struct InstalledRuntimeEnum *This = impl_from_IEnumUnknown(iface);
+    int num_fetched = 0;
+    HRESULT hr=S_OK;
+
+    TRACE("(%p,%u)\n", iface, celt);
+
+    while (num_fetched < celt)
+    {
+        if (This->pos >= NUM_RUNTIMES)
+        {
+            hr = S_FALSE;
+            break;
+        }
+        if (runtimes[This->pos].mono_abi_version)
+        {
+            num_fetched++;
+        }
+        This->pos++;
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI InstalledRuntimeEnum_Reset(IEnumUnknown *iface)
+{
+    struct InstalledRuntimeEnum *This = impl_from_IEnumUnknown(iface);
+
+    TRACE("(%p)\n", iface);
+
+    This->pos = 0;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI InstalledRuntimeEnum_Clone(IEnumUnknown *iface, IEnumUnknown **ppenum)
+{
+    struct InstalledRuntimeEnum *This = impl_from_IEnumUnknown(iface);
+    struct InstalledRuntimeEnum *new_enum;
+
+    TRACE("(%p)\n", iface);
+
+    new_enum = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_enum));
+    if (!new_enum)
+        return E_OUTOFMEMORY;
+
+    new_enum->IEnumUnknown_iface.lpVtbl = &InstalledRuntimeEnum_Vtbl;
+    new_enum->ref = 1;
+    new_enum->pos = This->pos;
+
+    *ppenum = &new_enum->IEnumUnknown_iface;
+
+    return S_OK;
+}
+
+static const struct IEnumUnknownVtbl InstalledRuntimeEnum_Vtbl = {
+    InstalledRuntimeEnum_QueryInterface,
+    InstalledRuntimeEnum_AddRef,
+    InstalledRuntimeEnum_Release,
+    InstalledRuntimeEnum_Next,
+    InstalledRuntimeEnum_Skip,
+    InstalledRuntimeEnum_Reset,
+    InstalledRuntimeEnum_Clone
+};
+
+struct CLRMetaHost
+{
+    ICLRMetaHost ICLRMetaHost_iface;
+};
+
+static struct CLRMetaHost GlobalCLRMetaHost;
+
+static HRESULT WINAPI CLRMetaHost_QueryInterface(ICLRMetaHost* iface,
+        REFIID riid,
+        void **ppvObject)
+{
+    TRACE("%s %p\n", debugstr_guid(riid), ppvObject);
+
+    if ( IsEqualGUID( riid, &IID_ICLRMetaHost ) ||
+         IsEqualGUID( riid, &IID_IUnknown ) )
+    {
+        *ppvObject = iface;
+    }
+    else
+    {
+        FIXME("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    ICLRMetaHost_AddRef( iface );
+
+    return S_OK;
+}
+
+static ULONG WINAPI CLRMetaHost_AddRef(ICLRMetaHost* iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI CLRMetaHost_Release(ICLRMetaHost* iface)
+{
+    return 1;
+}
+
+static BOOL parse_runtime_version(LPCWSTR version, DWORD *major, DWORD *minor, DWORD *build)
+{
+    *major = 0;
+    *minor = 0;
+    *build = 0;
+
+    if (version[0] == 'v')
+    {
+        version++;
+        if (!isdigit(*version))
+            return FALSE;
+
+        while (isdigit(*version))
+            *major = *major * 10 + (*version++ - '0');
+
+        if (*version == 0)
+            return TRUE;
+
+        if (*version++ != '.' || !isdigit(*version))
+            return FALSE;
+
+        while (isdigit(*version))
+            *minor = *minor * 10 + (*version++ - '0');
+
+        if (*version == 0)
+            return TRUE;
+
+        if (*version++ != '.' || !isdigit(*version))
+            return FALSE;
+
+        while (isdigit(*version))
+            *build = *build * 10 + (*version++ - '0');
+
+        return *version == 0;
+    }
+    else
+        return FALSE;
+}
+
+HRESULT WINAPI CLRMetaHost_GetRuntime(ICLRMetaHost* iface,
+    LPCWSTR pwzVersion, REFIID iid, LPVOID *ppRuntime)
+{
+    int i;
+    DWORD major, minor, build;
+
+    TRACE("%s %s %p\n", debugstr_w(pwzVersion), debugstr_guid(iid), ppRuntime);
+
+    if (!pwzVersion)
+        return E_POINTER;
+
+    if (!parse_runtime_version(pwzVersion, &major, &minor, &build))
+    {
+        ERR("Cannot parse %s\n", debugstr_w(pwzVersion));
+        return CLR_E_SHIM_RUNTIME;
+    }
+
+    find_runtimes();
+
+    for (i=0; i<NUM_RUNTIMES; i++)
+    {
+        if (runtimes[i].major == major && runtimes[i].minor == minor &&
+            runtimes[i].build == build)
+        {
+            if (runtimes[i].mono_abi_version)
+                return ICLRRuntimeInfo_QueryInterface(&runtimes[i].ICLRRuntimeInfo_iface, iid,
+                        ppRuntime);
+            else
+            {
+                missing_runtime_message(&runtimes[i]);
+                return CLR_E_SHIM_RUNTIME;
+            }
+        }
+    }
+
+    FIXME("Unrecognized version %s\n", debugstr_w(pwzVersion));
+    return CLR_E_SHIM_RUNTIME;
+}
+
+HRESULT WINAPI CLRMetaHost_GetVersionFromFile(ICLRMetaHost* iface,
+    LPCWSTR pwzFilePath, LPWSTR pwzBuffer, DWORD *pcchBuffer)
+{
+    ASSEMBLY *assembly;
+    HRESULT hr;
+    LPSTR version;
+    ULONG buffer_size=*pcchBuffer;
+
+    TRACE("%s %p %p\n", debugstr_w(pwzFilePath), pwzBuffer, pcchBuffer);
+
+    hr = assembly_create(&assembly, pwzFilePath);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = assembly_get_runtime_version(assembly, &version);
+
+        if (SUCCEEDED(hr))
+        {
+            *pcchBuffer = MultiByteToWideChar(CP_UTF8, 0, version, -1, NULL, 0);
+
+            if (pwzBuffer)
+            {
+                if (buffer_size >= *pcchBuffer)
+                    MultiByteToWideChar(CP_UTF8, 0, version, -1, pwzBuffer, buffer_size);
+                else
+                    hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+            }
+        }
+
+        assembly_release(assembly);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI CLRMetaHost_EnumerateInstalledRuntimes(ICLRMetaHost* iface,
+    IEnumUnknown **ppEnumerator)
+{
+    struct InstalledRuntimeEnum *new_enum;
+
+    TRACE("%p\n", ppEnumerator);
+
+    find_runtimes();
+
+    new_enum = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_enum));
+    if (!new_enum)
+        return E_OUTOFMEMORY;
+
+    new_enum->IEnumUnknown_iface.lpVtbl = &InstalledRuntimeEnum_Vtbl;
+    new_enum->ref = 1;
+    new_enum->pos = 0;
+
+    *ppEnumerator = &new_enum->IEnumUnknown_iface;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI CLRMetaHost_EnumerateLoadedRuntimes(ICLRMetaHost* iface,
+    HANDLE hndProcess, IEnumUnknown **ppEnumerator)
+{
+    FIXME("%p %p\n", hndProcess, ppEnumerator);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRMetaHost_RequestRuntimeLoadedNotification(ICLRMetaHost* iface,
+    RuntimeLoadedCallbackFnPtr pCallbackFunction)
+{
+    FIXME("%p\n", pCallbackFunction);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRMetaHost_QueryLegacyV2RuntimeBinding(ICLRMetaHost* iface,
+    REFIID riid, LPVOID *ppUnk)
+{
+    FIXME("%s %p\n", debugstr_guid(riid), ppUnk);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CLRMetaHost_ExitProcess(ICLRMetaHost* iface, INT32 iExitCode)
+{
+    FIXME("%i: stub\n", iExitCode);
+
+    ExitProcess(iExitCode);
+}
+
+static const struct ICLRMetaHostVtbl CLRMetaHost_vtbl =
+{
+    CLRMetaHost_QueryInterface,
+    CLRMetaHost_AddRef,
+    CLRMetaHost_Release,
+    CLRMetaHost_GetRuntime,
+    CLRMetaHost_GetVersionFromFile,
+    CLRMetaHost_EnumerateInstalledRuntimes,
+    CLRMetaHost_EnumerateLoadedRuntimes,
+    CLRMetaHost_RequestRuntimeLoadedNotification,
+    CLRMetaHost_QueryLegacyV2RuntimeBinding,
+    CLRMetaHost_ExitProcess
+};
+
+static struct CLRMetaHost GlobalCLRMetaHost = {
+    { &CLRMetaHost_vtbl }
+};
+
+HRESULT CLRMetaHost_CreateInstance(REFIID riid, void **ppobj)
+{
+    return ICLRMetaHost_QueryInterface(&GlobalCLRMetaHost.ICLRMetaHost_iface, riid, ppobj);
+}
+
+static MonoAssembly* mono_assembly_search_hook_fn(MonoAssemblyName *aname, char **assemblies_path, void *user_data)
+{
+    loaded_mono *mono = user_data;
+    HRESULT hr=S_OK;
+    MonoAssembly *result=NULL;
+    char *stringname=NULL;
+    LPWSTR stringnameW;
+    int stringnameW_size;
+    IAssemblyCache *asmcache;
+    ASSEMBLY_INFO info;
+    WCHAR path[MAX_PATH];
+    char *pathA;
+    MonoImageOpenStatus stat;
+    static WCHAR fusiondll[] = {'f','u','s','i','o','n',0};
+    HMODULE hfusion=NULL;
+    static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache**,DWORD);
+
+    stringname = mono->mono_stringify_assembly_name(aname);
+
+    TRACE("%s\n", debugstr_a(stringname));
+
+    if (!stringname) return NULL;
+
+    /* FIXME: We should search the given paths before the GAC. */
+
+    if (!pCreateAssemblyCache)
+    {
+        hr = LoadLibraryShim(fusiondll, NULL, NULL, &hfusion);
+
+        if (SUCCEEDED(hr))
+        {
+            pCreateAssemblyCache = (void*)GetProcAddress(hfusion, "CreateAssemblyCache");
+            if (!pCreateAssemblyCache)
+                hr = E_FAIL;
+        }
+    }
+
+    if (SUCCEEDED(hr))
+        hr = pCreateAssemblyCache(&asmcache, 0);
+
+    if (SUCCEEDED(hr))
+    {
+        stringnameW_size = MultiByteToWideChar(CP_UTF8, 0, stringname, -1, NULL, 0);
+
+        stringnameW = HeapAlloc(GetProcessHeap(), 0, stringnameW_size * sizeof(WCHAR));
+        if (stringnameW)
+            MultiByteToWideChar(CP_UTF8, 0, stringname, -1, stringnameW, stringnameW_size);
+        else
+            hr = E_OUTOFMEMORY;
+
+        if (SUCCEEDED(hr))
+        {
+            info.cbAssemblyInfo = sizeof(info);
+            info.pszCurrentAssemblyPathBuf = path;
+            info.cchBuf = MAX_PATH;
+            path[0] = 0;
+
+            hr = IAssemblyCache_QueryAssemblyInfo(asmcache, 0, stringnameW, &info);
+        }
+
+        HeapFree(GetProcessHeap(), 0, stringnameW);
+
+        IAssemblyCache_Release(asmcache);
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        TRACE("found: %s\n", debugstr_w(path));
+
+        pathA = WtoA(path);
+
+        if (pathA)
+        {
+            result = mono->mono_assembly_open(pathA, &stat);
+
+            if (!result)
+                ERR("Failed to load %s, status=%u\n", debugstr_w(path), stat);
+
+            HeapFree(GetProcessHeap(), 0, pathA);
+        }
+    }
+
+    mono->mono_free(stringname);
+
+    return result;
+}
+
+HRESULT get_runtime_info(LPCWSTR exefile, LPCWSTR version, LPCWSTR config_file,
+    DWORD startup_flags, DWORD runtimeinfo_flags, BOOL legacy, ICLRRuntimeInfo **result)
+{
+    static const WCHAR dotconfig[] = {'.','c','o','n','f','i','g',0};
+    static const DWORD supported_startup_flags = 0;
+    static const DWORD supported_runtime_flags = RUNTIME_INFO_UPGRADE_VERSION;
+    int i;
+    WCHAR local_version[MAX_PATH];
+    ULONG local_version_size = MAX_PATH;
+    WCHAR local_config_file[MAX_PATH];
+    HRESULT hr;
+    parsed_config_file parsed_config;
+
+    if (startup_flags & ~supported_startup_flags)
+        FIXME("unsupported startup flags %x\n", startup_flags & ~supported_startup_flags);
+
+    if (runtimeinfo_flags & ~supported_runtime_flags)
+        FIXME("unsupported runtimeinfo flags %x\n", runtimeinfo_flags & ~supported_runtime_flags);
+
+    if (exefile && !config_file)
+    {
+        strcpyW(local_config_file, exefile);
+        strcatW(local_config_file, dotconfig);
+
+        config_file = local_config_file;
+    }
+
+    if (config_file)
+    {
+        int found=0;
+        hr = parse_config_file(config_file, &parsed_config);
+
+        if (SUCCEEDED(hr))
+        {
+            supported_runtime *entry;
+            LIST_FOR_EACH_ENTRY(entry, &parsed_config.supported_runtimes, supported_runtime, entry)
+            {
+                hr = CLRMetaHost_GetRuntime(0, entry->version, &IID_ICLRRuntimeInfo, (void**)result);
+                if (SUCCEEDED(hr))
+                {
+                    found = 1;
+                    break;
+                }
+            }
+        }
+        else
+        {
+            WARN("failed to parse config file %s, hr=%x\n", debugstr_w(config_file), hr);
+        }
+
+        free_parsed_config_file(&parsed_config);
+
+        if (found)
+            return S_OK;
+    }
+
+    if (exefile && !version)
+    {
+        hr = CLRMetaHost_GetVersionFromFile(0, exefile, local_version, &local_version_size);
+
+        version = local_version;
+
+        if (FAILED(hr)) return hr;
+    }
+
+    if (version)
+    {
+        return CLRMetaHost_GetRuntime(0, version, &IID_ICLRRuntimeInfo, (void**)result);
+    }
+
+    if (runtimeinfo_flags & RUNTIME_INFO_UPGRADE_VERSION)
+    {
+        find_runtimes();
+
+        if (legacy)
+            i = 2;
+        else
+            i = NUM_RUNTIMES;
+
+        while (i--)
+        {
+            if (runtimes[i].mono_abi_version)
+                return ICLRRuntimeInfo_QueryInterface(&runtimes[i].ICLRRuntimeInfo_iface,
+                        &IID_ICLRRuntimeInfo, (void **)result);
+        }
+
+        if (legacy)
+            missing_runtime_message(&runtimes[1]);
+        else
+            missing_runtime_message(&runtimes[NUM_RUNTIMES-1]);
+
+        return CLR_E_SHIM_RUNTIME;
+    }
+
+    return CLR_E_SHIM_RUNTIME;
+}
index a014334..1c67d5e 100644 (file)
@@ -4,9 +4,18 @@
        <include base="ReactOS">include/reactos/wine</include>
        <define name="__WINESRC__" />
        <library>wine</library>
+       <library>dbghelp</library>
        <library>advapi32</library>
        <library>shell32</library>
+       <library>ole32</library>
+       <library>shlwapi</library>
        <library>uuid</library>
+       <file>assembly.c</file>
+       <file>config.c</file>
+       <file>cordebug.c</file>
        <file>corruntimehost.c</file>
+       <file>metadata.c</file>
+       <file>metahost.c</file>
        <file>mscoree_main.c</file>
+       <file>mscoree.rc</file>
 </module>
diff --git a/reactos/dll/win32/mscoree/mscoree.rc b/reactos/dll/win32/mscoree/mscoree.rc
new file mode 100644 (file)
index 0000000..8871437
--- /dev/null
@@ -0,0 +1 @@
+1 WINE_REGISTRY mscoree.rgs
diff --git a/reactos/dll/win32/mscoree/mscoree.rgs b/reactos/dll/win32/mscoree/mscoree.rgs
new file mode 100644 (file)
index 0000000..3730c54
--- /dev/null
@@ -0,0 +1,84 @@
+HKCR
+{
+    NoRemove Interface
+    {
+    }
+    NoRemove CLSID
+    {
+        '{90F1A06E-7712-4762-86B5-7A5EBA6BDB01}' = s 'Microsoft Common Language Runtime Host V2'
+        {
+            InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' }
+            ProgId = s 'CLRMetaData.CLRRuntimeHost.1'
+            VersionIndependentProgId = s 'CLRMetaData.CLRRuntimeHost'
+        }
+        '{90F1A06E-7712-4762-86B5-7A5EBA6BDB02}' = s 'Microsoft Common Language Runtime Host V2'
+        {
+            InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' }
+            ProgId = s 'CLRMetaData.CLRRuntimeHost.2'
+            VersionIndependentProgId = s 'CLRMetaData.CLRRuntimeHost'
+        }
+        '{E5CB7A31-7512-11D2-89CE-0080C792E5D8}' = s 'Microsoft Common Language Runtime Meta Data'
+        {
+            InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' }
+            ProgId = s 'CLRMetaData.CorMetaDataDispenser.2'
+            VersionIndependentProgId = s 'CLRMetaData.CorMetaDataDispenser'
+        }
+        '{1EC2DE53-75CC-11D2-9775-00A0C9B4D50C}' = s 'Microsoft Common Language Runtime Meta Data'
+        {
+            InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' }
+            ProgId = s 'CLRMetaData.CorMetaDataDispenserRuntime.2'
+            VersionIndependentProgId = s 'CLRMetaData.CorMetaDataDispenserRuntime'
+        }
+        '{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}' = s 'Microsoft Common Language Runtime Host'
+        {
+            InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' }
+            ProgId = s 'CLRMetaData.CorRuntimeHost.2'
+            VersionIndependentProgId = s 'CLRMetaData.CorRuntimeHost'
+        }
+    }
+    'CLRMetaData.CLRRuntimeHost.1' = s 'Microsoft Common Language Runtime Host V2'
+    {
+        CLSID = s '{90F1A06E-7712-4762-86B5-7A5EBA6BDB01}'
+    }
+    'CLRMetaData.CLRRuntimeHost' = s 'Microsoft Common Language Runtime Host V2'
+    {
+        CLSID = s '{90F1A06E-7712-4762-86B5-7A5EBA6BDB01}'
+        CurVer = s 'CLRMetaData.CLRRuntimeHost.1'
+    }
+    'CLRMetaData.CLRRuntimeHost.2' = s 'Microsoft Common Language Runtime Host V2'
+    {
+        CLSID = s '{90F1A06E-7712-4762-86B5-7A5EBA6BDB02}'
+    }
+    'CLRMetaData.CLRRuntimeHost' = s 'Microsoft Common Language Runtime Host V2'
+    {
+        CLSID = s '{90F1A06E-7712-4762-86B5-7A5EBA6BDB02}'
+        CurVer = s 'CLRMetaData.CLRRuntimeHost.2'
+    }
+    'CLRMetaData.CorMetaDataDispenser.2' = s 'Microsoft Common Language Runtime Meta Data'
+    {
+        CLSID = s '{E5CB7A31-7512-11D2-89CE-0080C792E5D8}'
+    }
+    'CLRMetaData.CorMetaDataDispenser' = s 'Microsoft Common Language Runtime Meta Data'
+    {
+        CLSID = s '{E5CB7A31-7512-11D2-89CE-0080C792E5D8}'
+        CurVer = s 'CLRMetaData.CorMetaDataDispenser.2'
+    }
+    'CLRMetaData.CorMetaDataDispenserRuntime.2' = s 'Microsoft Common Language Runtime Meta Data'
+    {
+        CLSID = s '{1EC2DE53-75CC-11D2-9775-00A0C9B4D50C}'
+    }
+    'CLRMetaData.CorMetaDataDispenserRuntime' = s 'Microsoft Common Language Runtime Meta Data'
+    {
+        CLSID = s '{1EC2DE53-75CC-11D2-9775-00A0C9B4D50C}'
+        CurVer = s 'CLRMetaData.CorMetaDataDispenserRuntime.2'
+    }
+    'CLRMetaData.CorRuntimeHost.2' = s 'Microsoft Common Language Runtime Host'
+    {
+        CLSID = s '{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}'
+    }
+    'CLRMetaData.CorRuntimeHost' = s 'Microsoft Common Language Runtime Host'
+    {
+        CLSID = s '{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}'
+        CurVer = s 'CLRMetaData.CorRuntimeHost.2'
+    }
+}
index 8e25cec..b2f72cd 100644 (file)
@@ -7,6 +7,7 @@
 
 @ stub CallFunctionShim
 @ stub CloseCtrs
+@ stdcall CLRCreateInstance(ptr ptr ptr)
 @ stdcall ClrCreateManagedInstance(wstr ptr ptr)
 @ stub CoEEShutDownCOM
 @ stdcall CoInitializeCor(long)
@@ -27,8 +28,8 @@
 @ stub CorIsLatestSvc
 @ stub CorMarkThreadInThreadPool
 @ stub CorTickleSvc
-@ stub CreateConfigStream
-@ stub CreateDebuggingInterfaceFromVersion
+@ stdcall CreateConfigStream(wstr ptr)
+@ stdcall CreateDebuggingInterfaceFromVersion(long wstr ptr)
 @ stdcall -private DllCanUnloadNow()
 @ stdcall -private DllGetClassObject(ptr ptr ptr)
 @ stdcall -private DllRegisterServer()
@@ -42,7 +43,7 @@
 @ stdcall GetCORSystemDirectory(ptr long ptr)
 @ stdcall GetCORVersion(ptr long ptr)
 @ stub GetCompileInfo
-@ stub GetFileVersion
+@ stdcall GetFileVersion(wstr ptr long ptr)
 @ stub GetHashFromAssemblyFile
 @ stub GetHashFromAssemblyFileW
 @ stub GetHashFromBlob
@@ -56,9 +57,9 @@
 @ stub GetPermissionRequests
 @ stub GetPrivateContextsPerfCounters
 @ stub GetProcessExecutableHeap
-@ stub GetRealProcAddress
+@ stdcall GetRealProcAddress(str ptr)
 @ stdcall GetRequestedRuntimeInfo(wstr wstr wstr long long ptr long ptr ptr long ptr)
-@ stub GetRequestedRuntimeVersion
+@ stdcall GetRequestedRuntimeVersion(wstr ptr long ptr)
 @ stub GetRequestedRuntimeVersionForCLSID
 @ stub GetStartupFlags
 @ stub GetTargetForVTableEntry
index 0e6f252..8b72ec8 100644 (file)
 
 #include <stdarg.h>
 
+#define COBJMACROS
 #include "wine/unicode.h"
+#include "wine/library.h"
 #include "windef.h"
 #include "winbase.h"
 #include "winuser.h"
 #include "winnls.h"
 #include "winreg.h"
 #include "ole2.h"
+#include "ocidl.h"
 #include "shellapi.h"
 
 #include "initguid.h"
+#include "msxml2.h"
+#include "corerror.h"
 #include "cor.h"
 #include "mscoree.h"
+#include "corhdr.h"
+#include "cordebug.h"
+#include "metahost.h"
+#include "fusion.h"
+#include "wine/list.h"
 #include "mscoree_private.h"
+#include "rpcproxy.h"
 
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
 
-static BOOL get_mono_path(LPWSTR path)
+static HINSTANCE MSCOREE_hInstance;
+
+char *WtoA(LPCWSTR wstr)
 {
-    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};
-    static const WCHAR slash[] = {'\\',0};
+    int length;
+    char *result;
 
-    WCHAR version[64], version_key[MAX_PATH];
-    DWORD len;
-    HKEY key;
+    length = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
 
-    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, mono_key, 0, KEY_READ, &key))
-        return FALSE;
+    result = HeapAlloc(GetProcessHeap(), 0, length);
 
-    len = sizeof(version);
-    if (RegQueryValueExW(key, defaul_clr, 0, NULL, (LPBYTE)version, &len))
-    {
-        RegCloseKey(key);
-        return FALSE;
-    }
-    RegCloseKey(key);
+    if (result)
+        WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, length, NULL, NULL);
 
-    lstrcpyW(version_key, mono_key);
-    lstrcatW(version_key, slash);
-    lstrcatW(version_key, version);
+    return result;
+}
 
-    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, version_key, 0, KEY_READ, &key))
+static BOOL get_install_root(LPWSTR install_dir)
+{
+    const WCHAR dotnet_key[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\','.','N','E','T','F','r','a','m','e','w','o','r','k','\\',0};
+    const WCHAR install_root[] = {'I','n','s','t','a','l','l','R','o','o','t',0};
+
+    DWORD len;
+    HKEY key;
+
+    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, dotnet_key, 0, KEY_READ, &key))
         return FALSE;
 
-    len = sizeof(WCHAR) * MAX_PATH;
-    if (RegQueryValueExW(key, install_root, 0, NULL, (LPBYTE)path, &len))
+    len = MAX_PATH;
+    if (RegQueryValueExW(key, install_root, 0, NULL, (LPBYTE)install_dir, &len))
     {
         RegCloseKey(key);
         return FALSE;
@@ -79,140 +89,38 @@ static BOOL get_mono_path(LPWSTR path)
     return TRUE;
 }
 
-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;
-    WCHAR mono_path[MAX_PATH], mono_dll_path[MAX_PATH+16], mono_bin_path[MAX_PATH+4];
-    WCHAR mono_lib_path[MAX_PATH+4], mono_etc_path[MAX_PATH+4];
-    char mono_lib_path_a[MAX_PATH], mono_etc_path_a[MAX_PATH];
-
-    EnterCriticalSection(&mono_lib_cs);
-
-    if (!mono_handle)
-    {
-        if (!get_mono_path(mono_path)) goto end;
-
-        strcpyW(mono_bin_path, mono_path);
-        strcatW(mono_bin_path, bin);
-        set_environment(mono_bin_path);
-
-        strcpyW(mono_lib_path, mono_path);
-        strcatW(mono_lib_path, lib);
-        WideCharToMultiByte(CP_UTF8, 0, mono_lib_path, -1, mono_lib_path_a, MAX_PATH, NULL, NULL);
-
-        strcpyW(mono_etc_path, mono_path);
-        strcatW(mono_etc_path, etc);
-        WideCharToMultiByte(CP_UTF8, 0, mono_etc_path, -1, mono_etc_path_a, MAX_PATH, NULL, NULL);
-
-        strcpyW(mono_dll_path, mono_path);
-        strcatW(mono_dll_path, mono_dll);
-        mono_handle = LoadLibraryW(mono_dll_path);
-
-        if (!mono_handle)
-        {
-            strcpyW(mono_dll_path, mono_path);
-            strcatW(mono_dll_path, 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:
-    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,
                                     REFIID riid, LPVOID *ppv)
 {
-    FIXME("(%s, %s, %s, %p, %d, %s, %s, %p): semi-stub!\n", debugstr_w(pwszVersion),
+    HRESULT ret;
+    ICLRRuntimeInfo *info;
+
+    TRACE("(%s, %s, %s, %p, %d, %s, %s, %p)\n", debugstr_w(pwszVersion),
           debugstr_w(pwszBuildFlavor), debugstr_w(pwszHostConfigFile), pReserved,
           startupFlags, debugstr_guid(rclsid), debugstr_guid(riid), ppv);
 
-    if (!get_mono_path(NULL))
+    *ppv = NULL;
+
+    ret = get_runtime_info(NULL, pwszVersion, pwszHostConfigFile, startupFlags, 0, TRUE, &info);
+
+    if (SUCCEEDED(ret))
     {
-        MESSAGE("wine: Install the Windows version of Mono to run .NET executables\n");
-        return E_FAIL;
+        ret = ICLRRuntimeInfo_GetInterface(info, rclsid, riid, ppv);
+
+        ICLRRuntimeInfo_Release(info);
     }
 
-    return S_OK;
+    return ret;
 }
 
 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 {
     TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
 
+    MSCOREE_hInstance = hinstDLL;
+
     switch (fdwReason)
     {
     case DLL_WINE_PREATTACH:
@@ -221,6 +129,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
         DisableThreadLibraryCalls(hinstDLL);
         break;
     case DLL_PROCESS_DETACH:
+        expect_no_runtimes();
         break;
     }
     return TRUE;
@@ -241,75 +150,6 @@ BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
     return TRUE;
 }
 
-static void get_utf8_args(int *argc, char ***argv)
-{
-    WCHAR **argvw;
-    int size=0, i;
-    char *current_arg;
-
-    argvw = CommandLineToArgvW(GetCommandLineW(), argc);
-
-    for (i=0; i<*argc; i++)
-    {
-        size += sizeof(char*);
-        size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
-    }
-    size += sizeof(char*);
-
-    *argv = HeapAlloc(GetProcessHeap(), 0, size);
-    current_arg = (char*)(*argv + *argc + 1);
-
-    for (i=0; i<*argc; i++)
-    {
-        (*argv)[i] = current_arg;
-        current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
-    }
-
-    (*argv)[*argc] = NULL;
-
-    HeapFree(GetProcessHeap(), 0, argvw);
-}
-
-__int32 WINAPI _CorExeMain(void)
-{
-    int exit_code;
-    int trace_size;
-    char trace_setting[256];
-    int argc;
-    char **argv;
-    MonoDomain *domain;
-    MonoAssembly *assembly;
-    char filename[MAX_PATH];
-
-    if (!load_mono())
-    {
-        return -1;
-    }
-
-    get_utf8_args(&argc, &argv);
-
-    trace_size = GetEnvironmentVariableA("WINE_MONO_TRACE", trace_setting, sizeof(trace_setting));
-
-    if (trace_size)
-    {
-        mono_jit_set_trace_options(trace_setting);
-    }
-
-    GetModuleFileNameA(NULL, filename, MAX_PATH);
-
-    domain = mono_jit_init(filename);
-
-    assembly = mono_domain_assembly_open(domain, filename);
-
-    exit_code = mono_jit_exec(domain, assembly, argc, argv);
-
-    mono_jit_cleanup(domain);
-
-    HeapFree(GetProcessHeap(), 0, argv);
-
-    return exit_code;
-}
-
 __int32 WINAPI _CorExeMain2(PBYTE ptrMemory, DWORD cntMemory, LPWSTR imageName, LPWSTR loaderName, LPWSTR cmdLine)
 {
     TRACE("(%p, %u, %s, %s, %s)\n", ptrMemory, cntMemory, debugstr_w(imageName), debugstr_w(loaderName), debugstr_w(cmdLine));
@@ -319,7 +159,8 @@ __int32 WINAPI _CorExeMain2(PBYTE ptrMemory, DWORD cntMemory, LPWSTR imageName,
 
 void WINAPI CorExitProcess(int exitCode)
 {
-    FIXME("(%x) stub\n", exitCode);
+    TRACE("(%x)\n", exitCode);
+    unload_all_runtimes();
     ExitProcess(exitCode);
 }
 
@@ -336,52 +177,150 @@ HRESULT WINAPI _CorValidateImage(PVOID* imageBase, LPCWSTR imageName)
 
 HRESULT WINAPI GetCORSystemDirectory(LPWSTR pbuffer, DWORD cchBuffer, DWORD *dwLength)
 {
-    FIXME("(%p, %d, %p): stub!\n", pbuffer, cchBuffer, dwLength);
+    ICLRRuntimeInfo *info;
+    HRESULT ret;
+
+    TRACE("(%p, %d, %p)!\n", pbuffer, cchBuffer, dwLength);
 
-    if (!dwLength)
+    if (!dwLength || !pbuffer)
         return E_POINTER;
 
-    *dwLength = 0;
+    ret = get_runtime_info(NULL, NULL, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, TRUE, &info);
 
-    return S_OK;
+    if (SUCCEEDED(ret))
+    {
+        *dwLength = cchBuffer;
+        ret = ICLRRuntimeInfo_GetRuntimeDirectory(info, pbuffer, dwLength);
+
+        ICLRRuntimeInfo_Release(info);
+    }
+
+    return ret;
 }
 
 HRESULT WINAPI GetCORVersion(LPWSTR pbuffer, DWORD cchBuffer, DWORD *dwLength)
 {
-    static const WCHAR version[] = {'v','1','.','1','.','4','3','2','2',0};
+    ICLRRuntimeInfo *info;
+    HRESULT ret;
 
-    FIXME("(%p, %d, %p): semi-stub!\n", pbuffer, cchBuffer, dwLength);
+    TRACE("(%p, %d, %p)!\n", pbuffer, cchBuffer, dwLength);
 
-    if (!dwLength)
+    if (!dwLength || !pbuffer)
         return E_POINTER;
 
-    *dwLength = lstrlenW(version);
+    ret = get_runtime_info(NULL, NULL, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, TRUE, &info);
 
-    if (cchBuffer < *dwLength)
-        return ERROR_INSUFFICIENT_BUFFER;
+    if (SUCCEEDED(ret))
+    {
+        *dwLength = cchBuffer;
+        ret = ICLRRuntimeInfo_GetVersionString(info, pbuffer, dwLength);
 
-    if (pbuffer)
-        lstrcpyW(pbuffer, version);
+        ICLRRuntimeInfo_Release(info);
+    }
 
-    return S_OK;
+    return ret;
 }
 
 HRESULT WINAPI GetRequestedRuntimeInfo(LPCWSTR pExe, LPCWSTR pwszVersion, LPCWSTR pConfigurationFile,
     DWORD startupFlags, DWORD runtimeInfoFlags, LPWSTR pDirectory, DWORD dwDirectory, DWORD *dwDirectoryLength,
     LPWSTR pVersion, DWORD cchBuffer, DWORD *dwlength)
 {
-    FIXME("(%s, %s, %s, 0x%08x, 0x%08x, %p, 0x%08x, %p, %p, 0x%08x, %p) stub\n", debugstr_w(pExe),
+    HRESULT ret;
+    ICLRRuntimeInfo *info;
+    DWORD length_dummy;
+
+    TRACE("(%s, %s, %s, 0x%08x, 0x%08x, %p, 0x%08x, %p, %p, 0x%08x, %p)\n", debugstr_w(pExe),
           debugstr_w(pwszVersion), debugstr_w(pConfigurationFile), startupFlags, runtimeInfoFlags, pDirectory,
           dwDirectory, dwDirectoryLength, pVersion, cchBuffer, dwlength);
-    return GetCORVersion(pVersion, cchBuffer, dwlength);
+
+    if (!dwDirectoryLength) dwDirectoryLength = &length_dummy;
+
+    if (!dwlength) dwlength = &length_dummy;
+
+    ret = get_runtime_info(pExe, pwszVersion, pConfigurationFile, startupFlags, runtimeInfoFlags, TRUE, &info);
+
+    if (SUCCEEDED(ret))
+    {
+        *dwlength = cchBuffer;
+        ret = ICLRRuntimeInfo_GetVersionString(info, pVersion, dwlength);
+
+        if (SUCCEEDED(ret))
+        {
+            *dwDirectoryLength = dwDirectory;
+            ret = ICLRRuntimeInfo_GetRuntimeDirectory(info, pDirectory, dwDirectoryLength);
+        }
+
+        ICLRRuntimeInfo_Release(info);
+    }
+
+    return ret;
+}
+
+HRESULT WINAPI GetRequestedRuntimeVersion(LPWSTR pExe, LPWSTR pVersion, DWORD cchBuffer, DWORD *dwlength)
+{
+    TRACE("(%s, %p, %d, %p)\n", debugstr_w(pExe), debugstr_w(pExe), cchBuffer, dwlength);
+
+    if(!dwlength)
+        return E_POINTER;
+
+    return GetRequestedRuntimeInfo(pExe, NULL, NULL, 0, 0, NULL, 0, NULL, pVersion, cchBuffer, dwlength);
+}
+
+HRESULT WINAPI GetRealProcAddress(LPCSTR procname, void **ppv)
+{
+    FIXME("(%s, %p)\n", debugstr_a(procname), ppv);
+    return CLR_E_SHIM_RUNTIMEEXPORT;
+}
+
+HRESULT WINAPI GetFileVersion(LPCWSTR szFilename, LPWSTR szBuffer, DWORD cchBuffer, DWORD *dwLength)
+{
+    TRACE("(%s, %p, %d, %p)\n", debugstr_w(szFilename), szBuffer, cchBuffer, dwLength);
+
+    if (!szFilename || !dwLength)
+        return E_POINTER;
+
+    *dwLength = cchBuffer;
+    return CLRMetaHost_GetVersionFromFile(0, szFilename, szBuffer, dwLength);
 }
 
 HRESULT WINAPI LoadLibraryShim( LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE * phModDll)
 {
-    FIXME("(%p %s, %p, %p, %p): semi-stub\n", szDllName, debugstr_w(szDllName), szVersion, pvReserved, phModDll);
+    HRESULT ret=S_OK;
+    WCHAR dll_filename[MAX_PATH];
+    WCHAR version[MAX_PATH];
+    static const WCHAR default_version[] = {'v','1','.','1','.','4','3','2','2',0};
+    static const WCHAR slash[] = {'\\',0};
+    DWORD dummy;
 
-    if (phModDll) *phModDll = LoadLibraryW(szDllName);
-    return S_OK;
+    TRACE("(%p %s, %p, %p, %p)\n", szDllName, debugstr_w(szDllName), szVersion, pvReserved, phModDll);
+
+    if (!szDllName || !phModDll)
+        return E_POINTER;
+
+    if (!get_install_root(dll_filename))
+    {
+        ERR("error reading registry key for installroot\n");
+        dll_filename[0] = 0;
+    }
+    else
+    {
+        if (!szVersion)
+        {
+            ret = GetCORVersion(version, MAX_PATH, &dummy);
+            if (SUCCEEDED(ret))
+                szVersion = version;
+            else
+                szVersion = default_version;
+        }
+        strcatW(dll_filename, szVersion);
+        strcatW(dll_filename, slash);
+    }
+
+    strcatW(dll_filename, szDllName);
+
+    *phModDll = LoadLibraryW(dll_filename);
+
+    return *phModDll ? S_OK : E_HANDLE;
 }
 
 HRESULT WINAPI LockClrVersion(FLockClrVersionCallback hostCallback, FLockClrVersionCallback *pBeginHostSetup, FLockClrVersionCallback *pEndHostSetup)
@@ -433,16 +372,24 @@ HRESULT WINAPI LoadStringRC(UINT resId, LPWSTR pBuffer, int iBufLen, int bQuiet)
 HRESULT WINAPI CorBindToRuntimeEx(LPWSTR szVersion, LPWSTR szBuildFlavor, DWORD nflags, REFCLSID rslsid,
                                   REFIID riid, LPVOID *ppv)
 {
-    FIXME("%s %s %d %s %s %p\n", debugstr_w(szVersion), debugstr_w(szBuildFlavor), nflags, debugstr_guid( rslsid ),
+    HRESULT ret;
+    ICLRRuntimeInfo *info;
+
+    TRACE("%s %s %d %s %s %p\n", debugstr_w(szVersion), debugstr_w(szBuildFlavor), nflags, debugstr_guid( rslsid ),
           debugstr_guid( riid ), ppv);
 
-    if(IsEqualGUID( riid, &IID_ICorRuntimeHost ))
+    *ppv = NULL;
+
+    ret = get_runtime_info(NULL, szVersion, NULL, nflags, RUNTIME_INFO_UPGRADE_VERSION, TRUE, &info);
+
+    if (SUCCEEDED(ret))
     {
-        *ppv = create_corruntimehost();
-        return S_OK;
+        ret = ICLRRuntimeInfo_GetInterface(info, rslsid, riid, ppv);
+
+        ICLRRuntimeInfo_Release(info);
     }
-    *ppv = NULL;
-    return E_NOTIMPL;
+
+    return ret;
 }
 
 HRESULT WINAPI CorBindToCurrentRuntime(LPCWSTR filename, REFCLSID rclsid, REFIID riid, LPVOID *ppv)
@@ -453,8 +400,37 @@ HRESULT WINAPI CorBindToCurrentRuntime(LPCWSTR filename, REFCLSID rclsid, REFIID
 
 STDAPI ClrCreateManagedInstance(LPCWSTR pTypeName, REFIID riid, void **ppObject)
 {
-    FIXME("(%s,%s,%p)\n", debugstr_w(pTypeName), debugstr_guid(riid), ppObject);
-    return E_NOTIMPL;
+    HRESULT ret;
+    ICLRRuntimeInfo *info;
+    RuntimeHost *host;
+    MonoObject *obj;
+    IUnknown *unk;
+
+    TRACE("(%s,%s,%p)\n", debugstr_w(pTypeName), debugstr_guid(riid), ppObject);
+
+    /* FIXME: How to determine which runtime version to use? */
+    ret = get_runtime_info(NULL, NULL, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, TRUE, &info);
+
+    if (SUCCEEDED(ret))
+    {
+        ret = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
+
+        ICLRRuntimeInfo_Release(info);
+    }
+
+    if (SUCCEEDED(ret))
+        ret = RuntimeHost_CreateManagedInstance(host, pTypeName, NULL, &obj);
+
+    if (SUCCEEDED(ret))
+        ret = RuntimeHost_GetIUnknownForObject(host, obj, &unk);
+
+    if (SUCCEEDED(ret))
+    {
+        ret = IUnknown_QueryInterface(unk, riid, ppObject);
+        IUnknown_Release(unk);
+    }
+
+    return ret;
 }
 
 BOOL WINAPI StrongNameSignatureVerification(LPCWSTR filename, DWORD inFlags, DWORD* pOutFlags)
@@ -469,6 +445,63 @@ BOOL WINAPI StrongNameSignatureVerificationEx(LPCWSTR filename, BOOL forceVerifi
     return FALSE;
 }
 
+HRESULT WINAPI CreateConfigStream(LPCWSTR filename, IStream **stream)
+{
+    FIXME("(%s, %p): stub\n", debugstr_w(filename), stream);
+    return E_NOTIMPL;
+}
+
+HRESULT WINAPI CreateDebuggingInterfaceFromVersion(int nDebugVersion, LPCWSTR version, IUnknown **ppv)
+{
+    const WCHAR v2_0[] = {'v','2','.','0','.','5','0','7','2','7',0};
+    HRESULT hr = E_FAIL;
+    ICLRRuntimeInfo *runtimeinfo;
+
+    if(nDebugVersion < 1 || nDebugVersion > 4)
+        return E_INVALIDARG;
+
+    TRACE("(%d %s, %p): stub\n", nDebugVersion, debugstr_w(version), ppv);
+
+    if(!ppv)
+        return E_INVALIDARG;
+
+    *ppv = NULL;
+
+    if(strcmpW(version, v2_0) != 0)
+    {
+        FIXME("Currently .NET Version '%s' not support.\n", debugstr_w(version));
+        return E_INVALIDARG;
+    }
+
+    if(nDebugVersion != 3)
+        return E_INVALIDARG;
+
+    hr = CLRMetaHost_GetRuntime(0, version, &IID_ICLRRuntimeInfo, (void**)&runtimeinfo);
+    if(hr == S_OK)
+    {
+        hr = ICLRRuntimeInfo_GetInterface(runtimeinfo, &CLSID_CLRDebuggingLegacy, &IID_ICorDebug, (void**)ppv);
+
+        ICLRRuntimeInfo_Release(runtimeinfo);
+    }
+
+    if(!*ppv)
+        return E_FAIL;
+
+    return hr;
+}
+
+HRESULT WINAPI CLRCreateInstance(REFCLSID clsid, REFIID riid, LPVOID *ppInterface)
+{
+    TRACE("(%s,%s,%p)\n", debugstr_guid(clsid), debugstr_guid(riid), ppInterface);
+
+    if (IsEqualGUID(clsid, &CLSID_CLRMetaHost))
+        return CLRMetaHost_CreateInstance(riid, ppInterface);
+
+    FIXME("not implemented for class %s\n", debugstr_guid(clsid));
+
+    return CLASS_E_CLASSNOTAVAILABLE;
+}
+
 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
 {
     FIXME("(%s, %s, %p): stub\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
@@ -480,19 +513,17 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
 
 HRESULT WINAPI DllRegisterServer(void)
 {
-    FIXME("\n");
-    return S_OK;
+    return __wine_register_resources( MSCOREE_hInstance );
 }
 
 HRESULT WINAPI DllUnregisterServer(void)
 {
-    FIXME("\n");
-    return S_OK;
+    return __wine_unregister_resources( MSCOREE_hInstance );
 }
 
 HRESULT WINAPI DllCanUnloadNow(VOID)
 {
-    return S_OK;
+    return S_FALSE;
 }
 
 INT WINAPI ND_RU1( const void *ptr, INT offset )
index f14da1d..a45a405 100644 (file)
 #ifndef __MSCOREE_PRIVATE__
 #define __MSCOREE_PRIVATE__
 
-extern IUnknown* create_corruntimehost(void);
+extern char *WtoA(LPCWSTR wstr) DECLSPEC_HIDDEN;
 
-/* Mono 2.6 embedding */
+extern HRESULT CLRMetaHost_CreateInstance(REFIID riid, void **ppobj) DECLSPEC_HIDDEN;
+
+extern HRESULT WINAPI CLRMetaHost_GetVersionFromFile(ICLRMetaHost* iface,
+    LPCWSTR pwzFilePath, LPWSTR pwzBuffer, DWORD *pcchBuffer) DECLSPEC_HIDDEN;
+
+typedef struct tagASSEMBLY ASSEMBLY;
+
+HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file) DECLSPEC_HIDDEN;
+HRESULT assembly_release(ASSEMBLY *assembly) DECLSPEC_HIDDEN;
+HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) DECLSPEC_HIDDEN;
+
+/* Mono embedding */
 typedef struct _MonoDomain MonoDomain;
 typedef struct _MonoAssembly MonoAssembly;
+typedef struct _MonoAssemblyName MonoAssemblyName;
+typedef struct _MonoType MonoType;
+typedef struct _MonoImage MonoImage;
+typedef struct _MonoClass MonoClass;
+typedef struct _MonoObject MonoObject;
+typedef struct _MonoString MonoString;
+typedef struct _MonoMethod MonoMethod;
+typedef struct _MonoProfiler MonoProfiler;
+
+typedef struct loaded_mono loaded_mono;
+typedef struct RuntimeHost RuntimeHost;
+
+typedef struct CLRRuntimeInfo
+{
+    ICLRRuntimeInfo ICLRRuntimeInfo_iface;
+    LPCWSTR mono_libdir;
+    DWORD major;
+    DWORD minor;
+    DWORD build;
+    int mono_abi_version;
+    WCHAR mono_path[MAX_PATH];
+    WCHAR mscorlib_path[MAX_PATH];
+    struct RuntimeHost *loaded_runtime;
+} CLRRuntimeInfo;
+
+struct RuntimeHost
+{
+    ICorRuntimeHost ICorRuntimeHost_iface;
+    ICLRRuntimeHost ICLRRuntimeHost_iface;
+    const CLRRuntimeInfo *version;
+    loaded_mono *mono;
+    struct list domains;
+    MonoDomain *default_domain;
+    CRITICAL_SECTION lock;
+    LONG ref;
+};
+
+typedef struct CorProcess
+{
+    struct list entry;
+    ICorDebugProcess *pProcess;
+} CorProcess;
+
+typedef struct CorDebug
+{
+    ICorDebug ICorDebug_iface;
+    ICorDebugProcessEnum ICorDebugProcessEnum_iface;
+    LONG ref;
+
+    ICLRRuntimeHost *runtimehost;
+
+    /* ICorDebug Callback */
+    ICorDebugManagedCallback *pCallback;
+    ICorDebugManagedCallback2 *pCallback2;
+
+    /* Debug Processes */
+    struct list processes;
+} CorDebug;
+
+extern HRESULT get_runtime_info(LPCWSTR exefile, LPCWSTR version, LPCWSTR config_file,
+    DWORD startup_flags, DWORD runtimeinfo_flags, BOOL legacy, ICLRRuntimeInfo **result) DECLSPEC_HIDDEN;
+
+extern HRESULT ICLRRuntimeInfo_GetRuntimeHost(ICLRRuntimeInfo *iface, RuntimeHost **result) DECLSPEC_HIDDEN;
+
+extern HRESULT MetaDataDispenser_CreateInstance(IUnknown **ppUnk) DECLSPEC_HIDDEN;
+
+typedef struct parsed_config_file
+{
+    struct list supported_runtimes;
+} parsed_config_file;
+
+typedef struct supported_runtime
+{
+    struct list entry;
+    LPWSTR version;
+} supported_runtime;
+
+extern HRESULT parse_config_file(LPCWSTR filename, parsed_config_file *result) DECLSPEC_HIDDEN;
+
+extern void free_parsed_config_file(parsed_config_file *file) DECLSPEC_HIDDEN;
+
+typedef enum {
+       MONO_IMAGE_OK,
+       MONO_IMAGE_ERROR_ERRNO,
+       MONO_IMAGE_MISSING_ASSEMBLYREF,
+       MONO_IMAGE_IMAGE_INVALID
+} MonoImageOpenStatus;
+
+typedef MonoAssembly* (*MonoAssemblyPreLoadFunc)(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
+
+typedef void (*MonoProfileFunc)(MonoProfiler *prof);
+
+struct loaded_mono
+{
+    HMODULE mono_handle;
+    HMODULE glib_handle;
+
+    BOOL is_started;
+    BOOL is_shutdown;
+
+    MonoImage* (CDECL *mono_assembly_get_image)(MonoAssembly *assembly);
+    MonoAssembly* (CDECL *mono_assembly_open)(const char *filename, MonoImageOpenStatus *status);
+    MonoClass* (CDECL *mono_class_from_mono_type)(MonoType *type);
+    MonoClass* (CDECL *mono_class_from_name)(MonoImage *image, const char* name_space, const char *name);
+    MonoMethod* (CDECL *mono_class_get_method_from_name)(MonoClass *klass, const char *name, int param_count);
+    void (CDECL *mono_config_parse)(const char *filename);
+    MonoAssembly* (CDECL *mono_domain_assembly_open) (MonoDomain *domain, const char *name);
+    void (CDECL *mono_free)(void *);
+    void (CDECL *mono_install_assembly_preload_hook)(MonoAssemblyPreLoadFunc func, void *user_data);
+    int (CDECL *mono_jit_exec)(MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[]);
+    MonoDomain* (CDECL *mono_jit_init)(const char *file);
+    int (CDECL *mono_jit_set_trace_options)(const char* options);
+    MonoDomain* (CDECL *mono_object_get_domain)(MonoObject *obj);
+    MonoObject* (CDECL *mono_object_new)(MonoDomain *domain, MonoClass *klass);
+    void* (CDECL *mono_object_unbox)(MonoObject *obj);
+    void (CDECL *mono_profiler_install)(MonoProfiler *prof, MonoProfileFunc shutdown_callback);
+    MonoType* (CDECL *mono_reflection_type_from_name)(char *name, MonoImage *image);
+    MonoObject* (CDECL *mono_runtime_invoke)(MonoMethod *method, void *obj, void **params, MonoObject **exc);
+    void (CDECL *mono_runtime_object_init)(MonoObject *this_obj);
+    void (CDECL *mono_runtime_quit)(void);
+    void (CDECL *mono_runtime_set_shutting_down)(void);
+    void (CDECL *mono_set_dirs)(const char *assembly_dir, const char *config_dir);
+    char* (CDECL *mono_stringify_assembly_name)(MonoAssemblyName *aname);
+    void (CDECL *mono_thread_pool_cleanup)(void);
+    void (CDECL *mono_thread_suspend_all_other_threads)(void);
+    void (CDECL *mono_threads_set_shutting_down)(void);
+    MonoString* (CDECL *mono_string_new)(MonoDomain *domain, const char *str);
+};
+
+/* loaded runtime interfaces */
+extern void unload_all_runtimes(void) DECLSPEC_HIDDEN;
+
+extern void expect_no_runtimes(void) DECLSPEC_HIDDEN;
+
+extern HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version,
+    loaded_mono *loaded_mono, RuntimeHost** result) DECLSPEC_HIDDEN;
+
+extern HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv) DECLSPEC_HIDDEN;
+
+extern HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj, IUnknown **ppUnk) DECLSPEC_HIDDEN;
+
+extern HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
+    MonoDomain *domain, MonoObject **result) DECLSPEC_HIDDEN;
+
+extern HRESULT RuntimeHost_Destroy(RuntimeHost *This) DECLSPEC_HIDDEN;
 
-extern HMODULE mono_handle;
+HRESULT WINAPI CLRMetaHost_GetRuntime(ICLRMetaHost* iface, LPCWSTR pwzVersion, REFIID iid, LPVOID *ppRuntime) DECLSPEC_HIDDEN;
 
-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);
+extern HRESULT CorDebug_Create(ICLRRuntimeHost *runtimehost, IUnknown** ppUnk) DECLSPEC_HIDDEN;
 
 #endif   /* __MSCOREE_PRIVATE__ */
index 87bc824..8b2dd88 100644 (file)
@@ -176,7 +176,10 @@ list(APPEND IDL_SOURCES
 
 if(MSVC)
     list(APPEND IDL_SOURCES
-        atliface.idl)
+        atliface.idl
+        cor.idl
+        cordebug.idl
+        metahost.idl)
 else()
     list(APPEND IDL_SOURCES
         wbemcli.idl
index aa98d95..bc832c3 100644 (file)
@@ -95,7 +95,7 @@ reactos/dll/win32/msacm32         # Autosync
 reactos/dll/win32/msadp32.acm     # Synced to Wine-1.3.37
 reactos/dll/win32/mscat32         # Autosync
 reactos/dll/win32/mscms           # Synced to Wine-1.3.37
-reactos/dll/win32/mscoree         # Autosync
+reactos/dll/win32/mscoree         # Synced to Wine-1.3.37
 reactos/dll/win32/msctf           # Synced to Wine-1.3.37
 reactos/dll/win32/msftedit        # Synced to Wine-1.3.37
 reactos/dll/win32/msg711.acm      # Synced to Wine-1.3.37