diff --git a/reactos/dll/win32/mscoree/CMakeLists.txt b/reactos/dll/win32/mscoree/CMakeLists.txt index 75d41f63ddb..1aab2a671ac 100644 --- a/reactos/dll/win32/mscoree/CMakeLists.txt +++ b/reactos/dll/win32/mscoree/CMakeLists.txt @@ -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 index 00000000000..07723f9edb7 --- /dev/null +++ b/reactos/dll/win32/mscoree/assembly.c @@ -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 +#include + +#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 index 00000000000..02c11b1adf5 --- /dev/null +++ b/reactos/dll/win32/mscoree/config.c @@ -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 + +#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 index 00000000000..da06f49e04b --- /dev/null +++ b/reactos/dll/win32/mscoree/cordebug.c @@ -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 + +#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; +} diff --git a/reactos/dll/win32/mscoree/corruntimehost.c b/reactos/dll/win32/mscoree/corruntimehost.c index 9de9bf5497b..5042f203d71 100644 --- a/reactos/dll/win32/mscoree/corruntimehost.c +++ b/reactos/dll/win32/mscoree/corruntimehost.c @@ -24,25 +24,185 @@ #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 -{ - const struct ICorRuntimeHostVtbl *lpVtbl; - LONG ref; -} corruntimehost; +#include "initguid.h" -static inline corruntimehost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface ) +DEFINE_GUID(IID__AppDomain, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13); + +struct DomainEntry { - return (corruntimehost *)((char*)iface - FIELD_OFFSET(corruntimehost, lpVtbl)); + struct list entry; + MonoDomain *domain; +}; + +static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, MonoDomain **result) +{ + 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; + } + + 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) +{ + 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) { - corruntimehost *This; + 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) +{ + 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; imono->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 index 00000000000..9ca0d933b55 --- /dev/null +++ b/reactos/dll/win32/mscoree/metadata.c @@ -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 +#include +#include + +#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 index 00000000000..49fb0ee5460 --- /dev/null +++ b/reactos/dll/win32/mscoree/metahost.c @@ -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 +#include +#include + +#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; imono_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; imono_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; iref); + + 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= *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; +} diff --git a/reactos/dll/win32/mscoree/mscoree.rbuild b/reactos/dll/win32/mscoree/mscoree.rbuild index a014334a962..1c67d5e41d3 100644 --- a/reactos/dll/win32/mscoree/mscoree.rbuild +++ b/reactos/dll/win32/mscoree/mscoree.rbuild @@ -4,9 +4,18 @@ include/reactos/wine wine + dbghelp advapi32 shell32 + ole32 + shlwapi uuid + assembly.c + config.c + cordebug.c corruntimehost.c + metadata.c + metahost.c mscoree_main.c + mscoree.rc diff --git a/reactos/dll/win32/mscoree/mscoree.rc b/reactos/dll/win32/mscoree/mscoree.rc new file mode 100644 index 00000000000..88714379f29 --- /dev/null +++ b/reactos/dll/win32/mscoree/mscoree.rc @@ -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 index 00000000000..3730c5455b7 --- /dev/null +++ b/reactos/dll/win32/mscoree/mscoree.rgs @@ -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' + } +} diff --git a/reactos/dll/win32/mscoree/mscoree.spec b/reactos/dll/win32/mscoree/mscoree.spec index 8e25cec2b7d..b2f72cd211a 100644 --- a/reactos/dll/win32/mscoree/mscoree.spec +++ b/reactos/dll/win32/mscoree/mscoree.spec @@ -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 diff --git a/reactos/dll/win32/mscoree/mscoree_main.c b/reactos/dll/win32/mscoree/mscoree_main.c index 0e6f25204cc..8b72ec83c08 100644 --- a/reactos/dll/win32/mscoree/mscoree_main.c +++ b/reactos/dll/win32/mscoree/mscoree_main.c @@ -21,55 +21,65 @@ #include +#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 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}; +static HINSTANCE MSCOREE_hInstance; + +char *WtoA(LPCWSTR wstr) +{ + int length; + char *result; + + length = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); + + result = HeapAlloc(GetProcessHeap(), 0, length); + + if (result) + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, length, NULL, NULL); + + return result; +} + +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}; - WCHAR version[64], version_key[MAX_PATH]; DWORD len; HKEY key; - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, mono_key, 0, KEY_READ, &key)) + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, dotnet_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)) + 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; - if (!dwLength) + TRACE("(%p, %d, %p)!\n", pbuffer, cchBuffer, 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 = create_corruntimehost(); - return S_OK; - } *ppv = NULL; - return E_NOTIMPL; + + ret = get_runtime_info(NULL, szVersion, NULL, nflags, RUNTIME_INFO_UPGRADE_VERSION, TRUE, &info); + + if (SUCCEEDED(ret)) + { + ret = ICLRRuntimeInfo_GetInterface(info, rslsid, riid, ppv); + + ICLRRuntimeInfo_Release(info); + } + + 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 ) diff --git a/reactos/dll/win32/mscoree/mscoree_private.h b/reactos/dll/win32/mscoree/mscoree_private.h index f14da1d15cd..a45a4052e9d 100644 --- a/reactos/dll/win32/mscoree/mscoree_private.h +++ b/reactos/dll/win32/mscoree/mscoree_private.h @@ -20,20 +20,170 @@ #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; -extern HMODULE mono_handle; +typedef struct loaded_mono loaded_mono; +typedef struct RuntimeHost RuntimeHost; -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); +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; + +HRESULT WINAPI CLRMetaHost_GetRuntime(ICLRMetaHost* iface, LPCWSTR pwzVersion, REFIID iid, LPVOID *ppRuntime) DECLSPEC_HIDDEN; + +extern HRESULT CorDebug_Create(ICLRRuntimeHost *runtimehost, IUnknown** ppUnk) DECLSPEC_HIDDEN; #endif /* __MSCOREE_PRIVATE__ */ diff --git a/reactos/lib/sdk/uuid/CMakeLists.txt b/reactos/lib/sdk/uuid/CMakeLists.txt index 87bc8244e91..8b2dd887b09 100644 --- a/reactos/lib/sdk/uuid/CMakeLists.txt +++ b/reactos/lib/sdk/uuid/CMakeLists.txt @@ -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 diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index aa98d95ed3c..bc832c3547f 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -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