diff --git a/reactos/dll/win32/mscoree/CMakeLists.txt b/reactos/dll/win32/mscoree/CMakeLists.txt index 1aab2a671ac..1c386979ca3 100644 --- a/reactos/dll/win32/mscoree/CMakeLists.txt +++ b/reactos/dll/win32/mscoree/CMakeLists.txt @@ -2,7 +2,9 @@ add_definitions(-D__WINESRC__) include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine) -set_rc_compiler() +remove_definitions(-D_WIN32_WINNT=0x502) +add_definitions(-D_WIN32_WINNT=0x600) + spec2def(mscoree.dll mscoree.spec) list(APPEND SOURCE diff --git a/reactos/dll/win32/mscoree/assembly.c b/reactos/dll/win32/mscoree/assembly.c index 07723f9edb7..13e7f03e4da 100644 --- a/reactos/dll/win32/mscoree/assembly.c +++ b/reactos/dll/win32/mscoree/assembly.c @@ -63,10 +63,13 @@ typedef struct tagCLRTABLE struct tagASSEMBLY { - LPWSTR path; + int is_mapped_file; + /* mapped files */ + LPWSTR path; HANDLE hfile; HANDLE hmap; + BYTE *data; IMAGE_NT_HEADERS *nthdr; @@ -89,6 +92,29 @@ static inline LPWSTR strdupW(LPCWSTR src) return dest; } +static void* assembly_rva_to_va(ASSEMBLY *assembly, ULONG rva) +{ + if (assembly->is_mapped_file) + return ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL); + else + return assembly->data + rva; +} + +static ULONG assembly_datadir_get_data(ASSEMBLY *assembly, + IMAGE_DATA_DIRECTORY *datadir, void **data) +{ + if (!datadir->VirtualAddress || !datadir->Size) + { + *data = NULL; + return 0; + } + else + { + *data = assembly_rva_to_va(assembly, datadir->VirtualAddress); + return datadir->Size; + } +} + static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz) { METADATAHDR *metadatahdr; @@ -97,7 +123,7 @@ static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz) ULONG rva; rva = assembly->corhdr->MetaData.VirtualAddress; - ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL); + ptr = assembly_rva_to_va(assembly, rva); if (!ptr) return E_FAIL; @@ -158,20 +184,24 @@ static HRESULT parse_pe_header(ASSEMBLY *assembly) 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) + if (!assembly_datadir_get_data(assembly, &datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR], (void**)&assembly->corhdr)) return E_FAIL; return S_OK; } +static HRESULT parse_headers(ASSEMBLY *assembly) +{ + HRESULT hr; + + hr = parse_pe_header(assembly); + + if (SUCCEEDED(hr)) + hr = parse_clr_metadata(assembly); + + return hr; +} + HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file) { ASSEMBLY *assembly; @@ -183,6 +213,8 @@ HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file) if (!assembly) return E_OUTOFMEMORY; + assembly->is_mapped_file = 1; + assembly->path = strdupW(file); if (!assembly->path) { @@ -213,10 +245,7 @@ HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file) goto failed; } - hr = parse_pe_header(assembly); - if (FAILED(hr)) goto failed; - - hr = parse_clr_metadata(assembly); + hr = parse_headers(assembly); if (FAILED(hr)) goto failed; *out = assembly; @@ -227,16 +256,43 @@ failed: return hr; } +HRESULT assembly_from_hmodule(ASSEMBLY **out, HMODULE hmodule) +{ + ASSEMBLY *assembly; + HRESULT hr; + + *out = NULL; + + assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY)); + if (!assembly) + return E_OUTOFMEMORY; + + assembly->is_mapped_file = 0; + + assembly->data = (BYTE*)hmodule; + + hr = parse_headers(assembly); + if (SUCCEEDED(hr)) + *out = assembly; + else + assembly_release(assembly); + + return hr; +} + HRESULT assembly_release(ASSEMBLY *assembly) { if (!assembly) return S_OK; + if (assembly->is_mapped_file) + { + UnmapViewOfFile(assembly->data); + CloseHandle(assembly->hmap); + CloseHandle(assembly->hfile); + } 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; @@ -248,3 +304,13 @@ HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) return S_OK; } + +HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count) +{ + ULONG size; + + size = assembly_datadir_get_data(assembly, &assembly->corhdr->VTableFixups, (void**)fixups); + *count = size / sizeof(VTableFixup); + + return S_OK; +} diff --git a/reactos/dll/win32/mscoree/config.c b/reactos/dll/win32/mscoree/config.c index 02c11b1adf5..c5e3cec7cd6 100644 --- a/reactos/dll/win32/mscoree/config.c +++ b/reactos/dll/win32/mscoree/config.c @@ -425,7 +425,7 @@ static HRESULT parse_config(VARIANT input, parsed_config_file *result) ISAXXMLReader_Release(reader); } - IUnknown_Release((IUnknown*)handler); + ISAXContentHandler_Release(&handler->ISAXContentHandler_iface); return S_OK; } @@ -445,7 +445,7 @@ HRESULT parse_config_file(LPCWSTR filename, parsed_config_file *result) if (SUCCEEDED(hr)) { - V_VT(&var) = VT_UNKNOWN|VT_DISPATCH; + V_VT(&var) = VT_UNKNOWN; V_UNKNOWN(&var) = (IUnknown*)stream; hr = parse_config(var, result); diff --git a/reactos/dll/win32/mscoree/corruntimehost.c b/reactos/dll/win32/mscoree/corruntimehost.c index 5042f203d71..3f2b9a28d30 100644 --- a/reactos/dll/win32/mscoree/corruntimehost.c +++ b/reactos/dll/win32/mscoree/corruntimehost.c @@ -19,6 +19,7 @@ #define COBJMACROS +#include #include #include "windef.h" @@ -38,6 +39,8 @@ #include "mscoree_private.h" #include "wine/debug.h" +#include "wine/unicode.h" +#include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL( mscoree ); @@ -51,6 +54,21 @@ struct DomainEntry MonoDomain *domain; }; +static HANDLE dll_fixup_heap; /* using a separate heap so we can have execute permission */ + +static struct list dll_fixups; + +struct dll_fixup +{ + struct list entry; + int done; + HMODULE dll; + void *thunk_code; /* pointer into dll_fixup_heap */ + VTableFixup *fixup; + void *vtable; + void *tokens; /* pointer into process heap */ +}; + static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, MonoDomain **result) { struct DomainEntry *entry; @@ -147,6 +165,8 @@ static HRESULT RuntimeHost_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *d MonoObject *appdomain_object; IUnknown *unk; + This->mono->mono_thread_attach(domain); + assembly = This->mono->mono_domain_assembly_open(domain, "mscorlib"); if (!assembly) { @@ -559,6 +579,8 @@ static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* hr = E_FAIL; + This->mono->mono_thread_attach(domain); + filenameA = WtoA(pwzAssemblyPath); assembly = This->mono->mono_domain_assembly_open(domain, filenameA); if (!assembly) @@ -609,14 +631,10 @@ static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* } 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); + HeapFree(GetProcessHeap(), 0, filenameA); + HeapFree(GetProcessHeap(), 0, classA); + HeapFree(GetProcessHeap(), 0, argsA); + HeapFree(GetProcessHeap(), 0, methodA); return hr; } @@ -661,6 +679,8 @@ HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name, if (SUCCEEDED(hr)) { + This->mono->mono_thread_attach(domain); + type = This->mono->mono_reflection_type_from_name(nameA, NULL); if (!type) { @@ -708,7 +728,9 @@ HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name, * * 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. */ + * garbage collector from freeing them. + * + * mono_thread_attach must have already been called for this thread. */ HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj, IUnknown **ppUnk) { @@ -798,13 +820,223 @@ static void get_utf8_args(int *argc, char ***argv) HeapFree(GetProcessHeap(), 0, argvw); } +#if __i386__ + +# define CAN_FIXUP_VTABLE 1 + +#include "pshpack1.h" + +struct vtable_fixup_thunk +{ + /* sub $0x4,%esp */ + BYTE i1[3]; + /* mov fixup,(%esp) */ + BYTE i2[3]; + struct dll_fixup *fixup; + /* mov function,%eax */ + BYTE i3; + void (CDECL *function)(struct dll_fixup *); + /* call *%eax */ + BYTE i4[2]; + /* pop %eax */ + BYTE i5; + /* jmp *vtable_entry */ + BYTE i6[2]; + void *vtable_entry; +}; + +static const struct vtable_fixup_thunk thunk_template = { + {0x83,0xec,0x04}, + {0xc7,0x04,0x24}, + NULL, + 0xb8, + NULL, + {0xff,0xd0}, + 0x58, + {0xff,0x25}, + NULL +}; + +#include "poppack.h" + +#else /* !defined(__i386__) */ + +# define CAN_FIXUP_VTABLE 0 + +struct vtable_fixup_thunk +{ + struct dll_fixup *fixup; + void (CDECL *function)(struct dll_fixup *fixup); + void *vtable_entry; +}; + +static const struct vtable_fixup_thunk thunk_template = {0}; + +#endif + +static void CDECL ReallyFixupVTable(struct dll_fixup *fixup) +{ + HRESULT hr=S_OK; + WCHAR filename[MAX_PATH]; + ICLRRuntimeInfo *info=NULL; + RuntimeHost *host; + char *filenameA; + MonoImage *image=NULL; + MonoAssembly *assembly=NULL; + MonoImageOpenStatus status=0; + MonoDomain *domain; + + if (fixup->done) return; + + /* It's possible we'll have two threads doing this at once. This is + * considered preferable to the potential deadlock if we use a mutex. */ + + GetModuleFileNameW(fixup->dll, filename, MAX_PATH); + + TRACE("%p,%p,%s\n", fixup, fixup->dll, debugstr_w(filename)); + + filenameA = WtoA(filename); + if (!filenameA) + hr = E_OUTOFMEMORY; + + if (SUCCEEDED(hr)) + hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info); + + if (SUCCEEDED(hr)) + hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host); + + if (SUCCEEDED(hr)) + hr = RuntimeHost_GetDefaultDomain(host, &domain); + + if (SUCCEEDED(hr)) + { + host->mono->mono_thread_attach(domain); + + image = host->mono->mono_image_open_from_module_handle(fixup->dll, + filenameA, 1, &status); + } + + if (image) + assembly = host->mono->mono_assembly_load_from(image, filenameA, &status); + + if (assembly) + { + int i; + + /* Mono needs an image that belongs to an assembly. */ + image = host->mono->mono_assembly_get_image(assembly); + + if (fixup->fixup->type & COR_VTABLE_32BIT) + { + DWORD *vtable = fixup->vtable; + DWORD *tokens = fixup->tokens; + for (i=0; ifixup->count; i++) + { + TRACE("%x\n", tokens[i]); + vtable[i] = PtrToUint(host->mono->mono_marshal_get_vtfixup_ftnptr( + image, tokens[i], fixup->fixup->type)); + } + } + + fixup->done = 1; + } + + if (info != NULL) + ICLRRuntimeHost_Release(info); + + HeapFree(GetProcessHeap(), 0, filenameA); + + if (!fixup->done) + { + ERR("unable to fixup vtable, hr=%x, status=%d\n", hr, status); + /* If we returned now, we'd get an infinite loop. */ + assert(0); + } +} + +static void FixupVTableEntry(HMODULE hmodule, VTableFixup *vtable_fixup) +{ + /* We can't actually generate code for the functions without loading mono, + * and loading mono inside DllMain is a terrible idea. So we make thunks + * that call ReallyFixupVTable, which will load the runtime and fill in the + * vtable, then do an indirect jump using the (now filled in) vtable. Note + * that we have to keep the thunks around forever, as one of them may get + * called while we're filling in the table, and we can never be sure all + * threads are clear. */ + struct dll_fixup *fixup; + + fixup = HeapAlloc(GetProcessHeap(), 0, sizeof(*fixup)); + + fixup->dll = hmodule; + fixup->thunk_code = HeapAlloc(dll_fixup_heap, 0, sizeof(struct vtable_fixup_thunk) * vtable_fixup->count); + fixup->fixup = vtable_fixup; + fixup->vtable = (BYTE*)hmodule + vtable_fixup->rva; + fixup->done = 0; + + if (vtable_fixup->type & COR_VTABLE_32BIT) + { + DWORD *vtable = fixup->vtable; + DWORD *tokens; + int i; + struct vtable_fixup_thunk *thunks = fixup->thunk_code; + + if (sizeof(void*) > 4) + ERR("32-bit fixup in 64-bit mode; broken image?\n"); + + tokens = fixup->tokens = HeapAlloc(GetProcessHeap(), 0, sizeof(*tokens) * vtable_fixup->count); + memcpy(tokens, vtable, sizeof(*tokens) * vtable_fixup->count); + for (i=0; icount; i++) + { + memcpy(&thunks[i], &thunk_template, sizeof(thunk_template)); + thunks[i].fixup = fixup; + thunks[i].function = ReallyFixupVTable; + thunks[i].vtable_entry = &vtable[i]; + vtable[i] = PtrToUint(&thunks[i]); + } + } + else + { + ERR("unsupported vtable fixup flags %x\n", vtable_fixup->type); + HeapFree(dll_fixup_heap, 0, fixup->thunk_code); + HeapFree(GetProcessHeap(), 0, fixup); + return; + } + + list_add_tail(&dll_fixups, &fixup->entry); +} + +static void FixupVTable(HMODULE hmodule) +{ + ASSEMBLY *assembly; + HRESULT hr; + VTableFixup *vtable_fixups; + ULONG vtable_fixup_count, i; + + hr = assembly_from_hmodule(&assembly, hmodule); + if (SUCCEEDED(hr)) + { + hr = assembly_get_vtable_fixups(assembly, &vtable_fixups, &vtable_fixup_count); + if (CAN_FIXUP_VTABLE) + for (i=0; imono->mono_domain_assembly_open(domain, filenameA); + image = host->mono->mono_image_open_from_module_handle(GetModuleHandleW(NULL), + filenameA, 1, &status); - exit_code = host->mono->mono_jit_exec(domain, assembly, argc, argv); + if (image) + assembly = host->mono->mono_assembly_load_from(image, filenameA, &status); + + if (assembly) + { + exit_code = host->mono->mono_jit_exec(domain, assembly, argc, argv); + } + else + { + ERR("couldn't load %s, status=%d\n", debugstr_w(filename), status); + exit_code = -1; + } RuntimeHost_DeleteDomain(host, domain); } @@ -857,6 +1103,43 @@ __int32 WINAPI _CorExeMain(void) return exit_code; } +BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved); + + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + FixupVTable(hinstDLL); + break; + case DLL_PROCESS_DETACH: + /* FIXME: clean up the vtables */ + break; + } + return TRUE; +} + +/* called from DLL_PROCESS_ATTACH */ +void runtimehost_init(void) +{ + dll_fixup_heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0); + list_init(&dll_fixups); +} + +/* called from DLL_PROCESS_DETACH */ +void runtimehost_uninit(void) +{ + struct dll_fixup *fixup, *fixup2; + + HeapDestroy(dll_fixup_heap); + LIST_FOR_EACH_ENTRY_SAFE(fixup, fixup2, &dll_fixups, struct dll_fixup, entry) + { + HeapFree(GetProcessHeap(), 0, fixup->tokens); + HeapFree(GetProcessHeap(), 0, fixup); + } +} + HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version, loaded_mono *loaded_mono, RuntimeHost** result) { @@ -943,3 +1226,148 @@ HRESULT RuntimeHost_Destroy(RuntimeHost *This) HeapFree( GetProcessHeap(), 0, This ); return S_OK; } + +#define CHARS_IN_GUID 39 +#define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0])) + +HRESULT create_monodata(REFIID riid, LPVOID *ppObj ) +{ + static const WCHAR wszCodebase[] = {'C','o','d','e','B','a','s','e',0}; + static const WCHAR wszClass[] = {'C','l','a','s','s',0}; + static const WCHAR wszFileSlash[] = {'f','i','l','e',':','/','/','/',0}; + static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0}; + static const WCHAR wszInprocServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0}; + WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) + ARRAYSIZE(wszInprocServer32) - 1]; + MonoDomain *domain; + MonoAssembly *assembly; + ICLRRuntimeInfo *info; + RuntimeHost *host; + HRESULT hr; + HKEY key; + LONG res; + int offset = 0; + WCHAR codebase[MAX_PATH + 8]; + WCHAR classname[350]; + WCHAR filename[MAX_PATH]; + + DWORD dwBufLen = 350; + + lstrcpyW(path, wszCLSIDSlash); + StringFromGUID2(riid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID); + lstrcatW(path, wszInprocServer32); + + TRACE("Registry key: %s\n", debugstr_w(path)); + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key); + if (res == ERROR_FILE_NOT_FOUND) + return CLASS_E_CLASSNOTAVAILABLE; + + res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen); + if(res != ERROR_SUCCESS) + { + WARN("Class value cannot be found.\n"); + hr = CLASS_E_CLASSNOTAVAILABLE; + goto cleanup; + } + + TRACE("classname (%s)\n", debugstr_w(classname)); + + dwBufLen = MAX_PATH + 8; + res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen); + if(res != ERROR_SUCCESS) + { + WARN("CodeBase value cannot be found.\n"); + hr = CLASS_E_CLASSNOTAVAILABLE; + goto cleanup; + } + + /* Strip file:/// */ + if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0) + offset = strlenW(wszFileSlash); + + strcpyW(filename, codebase + offset); + + TRACE("codebase (%s)\n", debugstr_w(filename)); + + *ppObj = NULL; + + + hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info); + if (SUCCEEDED(hr)) + { + hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host); + + if (SUCCEEDED(hr)) + hr = RuntimeHost_GetDefaultDomain(host, &domain); + + if (SUCCEEDED(hr)) + { + MonoImage *image; + MonoClass *klass; + MonoObject *result; + IUnknown *unk = NULL; + char *filenameA, *ns; + char *classA; + + hr = CLASS_E_CLASSNOTAVAILABLE; + + host->mono->mono_thread_attach(domain); + + filenameA = WtoA(filename); + assembly = host->mono->mono_domain_assembly_open(domain, filenameA); + HeapFree(GetProcessHeap(), 0, filenameA); + if (!assembly) + { + ERR("Cannot open assembly %s\n", filenameA); + goto cleanup; + } + + image = host->mono->mono_assembly_get_image(assembly); + if (!image) + { + ERR("Couldn't get assembly image\n"); + goto cleanup; + } + + classA = WtoA(classname); + ns = strrchr(classA, '.'); + *ns = '\0'; + + klass = host->mono->mono_class_from_name(image, classA, ns+1); + HeapFree(GetProcessHeap(), 0, classA); + if (!klass) + { + ERR("Couldn't get class from image\n"); + goto cleanup; + } + + /* + * Use the default constructor for the .NET class. + */ + result = host->mono->mono_object_new(domain, klass); + host->mono->mono_runtime_object_init(result); + + hr = RuntimeHost_GetIUnknownForObject(host, result, &unk); + if (SUCCEEDED(hr)) + { + hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj); + + IUnknown_Release(unk); + } + else + hr = CLASS_E_CLASSNOTAVAILABLE; + } + else + hr = CLASS_E_CLASSNOTAVAILABLE; + } + else + hr = CLASS_E_CLASSNOTAVAILABLE; + +cleanup: + if(info) + ICLRRuntimeInfo_Release(info); + + RegCloseKey(key); + + return hr; +} diff --git a/reactos/dll/win32/mscoree/metahost.c b/reactos/dll/win32/mscoree/metahost.c index 49fb0ee5460..3736dc0ace1 100644 --- a/reactos/dll/win32/mscoree/metahost.c +++ b/reactos/dll/win32/mscoree/metahost.c @@ -165,16 +165,19 @@ static HRESULT load_mono(CLRRuntimeInfo *This, loaded_mono **result) } while (0); LOAD_MONO_FUNCTION(mono_assembly_get_image); + LOAD_MONO_FUNCTION(mono_assembly_load_from); 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_image_open_from_module_handle); 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_marshal_get_vtfixup_ftnptr); LOAD_MONO_FUNCTION(mono_object_get_domain); LOAD_MONO_FUNCTION(mono_object_new); LOAD_MONO_FUNCTION(mono_object_unbox); @@ -186,6 +189,7 @@ static HRESULT load_mono(CLRRuntimeInfo *This, loaded_mono **result) LOAD_MONO_FUNCTION(mono_set_dirs); LOAD_MONO_FUNCTION(mono_stringify_assembly_name); LOAD_MONO_FUNCTION(mono_string_new); + LOAD_MONO_FUNCTION(mono_thread_attach); /* GLib imports obsoleted by the 2.0 ABI */ if (This->mono_abi_version == 1) @@ -564,6 +568,14 @@ HRESULT ICLRRuntimeInfo_GetRuntimeHost(ICLRRuntimeInfo *iface, RuntimeHost **res return CLRRuntimeInfo_GetRuntimeHost(This, result); } +#ifdef __i386__ +static const WCHAR libmono2_arch_dll[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','-','x','8','6','.','d','l','l',0}; +#elif defined(__x86_64__) +static const WCHAR libmono2_arch_dll[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','-','x','8','6','_','6','4','.','d','l','l',0}; +#else +static const WCHAR libmono2_arch_dll[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','.','d','l','l',0}; +#endif + 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}; @@ -588,9 +600,16 @@ static BOOL find_mono_dll(LPCWSTR path, LPWSTR dll_path, int abi_version) else if (abi_version == 2) { strcpyW(dll_path, path); - strcatW(dll_path, mono2_dll); + strcatW(dll_path, libmono2_arch_dll); attributes = GetFileAttributesW(dll_path); + if (attributes == INVALID_FILE_ATTRIBUTES) + { + strcpyW(dll_path, path); + strcatW(dll_path, mono2_dll); + attributes = GetFileAttributesW(dll_path); + } + if (attributes == INVALID_FILE_ATTRIBUTES) { strcpyW(dll_path, path); @@ -973,7 +992,7 @@ static BOOL parse_runtime_version(LPCWSTR version, DWORD *major, DWORD *minor, D *minor = 0; *build = 0; - if (version[0] == 'v') + if (version[0] == 'v' || version[0] == 'V') { version++; if (!isdigit(*version)) @@ -1310,11 +1329,21 @@ HRESULT get_runtime_info(LPCWSTR exefile, LPCWSTR version, LPCWSTR config_file, if (version) { - return CLRMetaHost_GetRuntime(0, version, &IID_ICLRRuntimeInfo, (void**)result); + hr = CLRMetaHost_GetRuntime(0, version, &IID_ICLRRuntimeInfo, (void**)result); + if(SUCCEEDED(hr)) + return hr; } if (runtimeinfo_flags & RUNTIME_INFO_UPGRADE_VERSION) { + DWORD major, minor, build; + + if (version && !parse_runtime_version(version, &major, &minor, &build)) + { + ERR("Cannot parse %s\n", debugstr_w(version)); + return CLR_E_SHIM_RUNTIME; + } + find_runtimes(); if (legacy) @@ -1325,8 +1354,16 @@ HRESULT get_runtime_info(LPCWSTR exefile, LPCWSTR version, LPCWSTR config_file, while (i--) { if (runtimes[i].mono_abi_version) - return ICLRRuntimeInfo_QueryInterface(&runtimes[i].ICLRRuntimeInfo_iface, - &IID_ICLRRuntimeInfo, (void **)result); + { + /* Must be greater or equal to the version passed in. */ + if (!version || ((runtimes[i].major >= major && runtimes[i].minor >= minor && runtimes[i].build >= build) || + (runtimes[i].major >= major && runtimes[i].minor > minor) || + (runtimes[i].major > major))) + { + return ICLRRuntimeInfo_QueryInterface(&runtimes[i].ICLRRuntimeInfo_iface, + &IID_ICLRRuntimeInfo, (void **)result); + } + } } if (legacy) diff --git a/reactos/dll/win32/mscoree/mscoree.spec b/reactos/dll/win32/mscoree/mscoree.spec index b2f72cd211a..a51a2f1c599 100644 --- a/reactos/dll/win32/mscoree/mscoree.spec +++ b/reactos/dll/win32/mscoree/mscoree.spec @@ -9,7 +9,7 @@ @ stub CloseCtrs @ stdcall CLRCreateInstance(ptr ptr ptr) @ stdcall ClrCreateManagedInstance(wstr ptr ptr) -@ stub CoEEShutDownCOM +@ stdcall CoEEShutDownCOM() @ stdcall CoInitializeCor(long) @ stub CoInitializeEE @ stub CoUninitializeCor diff --git a/reactos/dll/win32/mscoree/mscoree_main.c b/reactos/dll/win32/mscoree/mscoree_main.c index 8b72ec83c08..0aa736f93df 100644 --- a/reactos/dll/win32/mscoree/mscoree_main.c +++ b/reactos/dll/win32/mscoree/mscoree_main.c @@ -52,6 +52,8 @@ WINE_DEFAULT_DEBUG_CHANNEL( mscoree ); static HINSTANCE MSCOREE_hInstance; +typedef HRESULT (*fnCreateInstance)(REFIID riid, LPVOID *ppObj); + char *WtoA(LPCWSTR wstr) { int length; @@ -89,6 +91,105 @@ static BOOL get_install_root(LPWSTR install_dir) return TRUE; } +typedef struct mscorecf +{ + IClassFactory IClassFactory_iface; + LONG ref; + + fnCreateInstance pfnCreateInstance; + + CLSID clsid; +} mscorecf; + +static inline mscorecf *impl_from_IClassFactory( IClassFactory *iface ) +{ + return CONTAINING_RECORD(iface, mscorecf, IClassFactory_iface); +} + +static HRESULT WINAPI mscorecf_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppobj ) +{ + TRACE("%s %p\n", debugstr_guid(riid), ppobj); + + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IClassFactory)) + { + IClassFactory_AddRef( iface ); + *ppobj = iface; + return S_OK; + } + + ERR("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI mscorecf_AddRef(IClassFactory *iface ) +{ + mscorecf *This = impl_from_IClassFactory(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("%p ref=%u\n", This, ref); + + return ref; +} + +static ULONG WINAPI mscorecf_Release(IClassFactory *iface ) +{ + mscorecf *This = impl_from_IClassFactory(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 mscorecf_CreateInstance(IClassFactory *iface,LPUNKNOWN pOuter, + REFIID riid, LPVOID *ppobj ) +{ + mscorecf *This = impl_from_IClassFactory( iface ); + HRESULT hr; + IUnknown *punk; + + TRACE("%p %s %p\n", pOuter, debugstr_guid(riid), ppobj ); + + *ppobj = NULL; + + if (pOuter) + return CLASS_E_NOAGGREGATION; + + hr = This->pfnCreateInstance( &This->clsid, (LPVOID*) &punk ); + if (SUCCEEDED(hr)) + { + hr = IUnknown_QueryInterface( punk, riid, ppobj ); + + IUnknown_Release( punk ); + } + else + { + WARN("Cannot create an instance object. 0x%08x\n", hr); + } + return hr; +} + +static HRESULT WINAPI mscorecf_LockServer(IClassFactory *iface, BOOL dolock) +{ + FIXME("(%p)->(%d),stub!\n",iface,dolock); + return S_OK; +} + +static const struct IClassFactoryVtbl mscorecf_vtbl = +{ + mscorecf_QueryInterface, + mscorecf_AddRef, + mscorecf_Release, + mscorecf_CreateInstance, + mscorecf_LockServer +}; + HRESULT WINAPI CorBindToRuntimeHost(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, LPCWSTR pwszHostConfigFile, VOID *pReserved, DWORD startupFlags, REFCLSID rclsid, @@ -126,25 +227,13 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_WINE_PREATTACH: return FALSE; /* prefer native version */ case DLL_PROCESS_ATTACH: + runtimehost_init(); DisableThreadLibraryCalls(hinstDLL); break; case DLL_PROCESS_DETACH: expect_no_runtimes(); - break; - } - return TRUE; -} - -BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - FIXME("(%p, %d, %p): stub\n", hinstDLL, fdwReason, lpvReserved); - - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinstDLL); - break; - case DLL_PROCESS_DETACH: + if (lpvReserved) break; /* process is terminating */ + runtimehost_uninit(); break; } return TRUE; @@ -246,6 +335,9 @@ HRESULT WINAPI GetRequestedRuntimeInfo(LPCWSTR pExe, LPCWSTR pwszVersion, LPCWST if (SUCCEEDED(ret)) { + if(pwszVersion) + pVersion[0] = pwszVersion[0]; + *dwDirectoryLength = dwDirectory; ret = ICLRRuntimeInfo_GetRuntimeDirectory(info, pDirectory, dwDirectoryLength); } @@ -258,7 +350,7 @@ HRESULT WINAPI GetRequestedRuntimeInfo(LPCWSTR pExe, LPCWSTR pwszVersion, LPCWST 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); + TRACE("(%s, %p, %d, %p)\n", debugstr_w(pExe), pVersion, cchBuffer, dwlength); if(!dwlength) return E_POINTER; @@ -504,11 +596,25 @@ HRESULT WINAPI CLRCreateInstance(REFCLSID clsid, REFIID riid, LPVOID *ppInterfac HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { - FIXME("(%s, %s, %p): stub\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + mscorecf *This; + HRESULT hr; + + TRACE("(%s, %s, %p): stub\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + if(!ppv) return E_INVALIDARG; - return E_NOTIMPL; + This = HeapAlloc(GetProcessHeap(), 0, sizeof(mscorecf)); + + This->IClassFactory_iface.lpVtbl = &mscorecf_vtbl; + This->pfnCreateInstance = &create_monodata; + This->ref = 1; + This->clsid = *rclsid; + + hr = IClassFactory_QueryInterface( &This->IClassFactory_iface, riid, ppv ); + IClassFactory_Release(&This->IClassFactory_iface); + + return hr; } HRESULT WINAPI DllRegisterServer(void) @@ -526,6 +632,11 @@ HRESULT WINAPI DllCanUnloadNow(VOID) return S_FALSE; } +void WINAPI CoEEShutDownCOM(void) +{ + FIXME("stub.\n"); +} + INT WINAPI ND_RU1( const void *ptr, INT offset ) { return *((const BYTE *)ptr + offset); diff --git a/reactos/dll/win32/mscoree/mscoree_private.h b/reactos/dll/win32/mscoree/mscoree_private.h index a45a4052e9d..ef9079ebdef 100644 --- a/reactos/dll/win32/mscoree/mscoree_private.h +++ b/reactos/dll/win32/mscoree/mscoree_private.h @@ -27,11 +27,19 @@ extern HRESULT CLRMetaHost_CreateInstance(REFIID riid, void **ppobj) DECLSPEC_HI extern HRESULT WINAPI CLRMetaHost_GetVersionFromFile(ICLRMetaHost* iface, LPCWSTR pwzFilePath, LPWSTR pwzBuffer, DWORD *pcchBuffer) DECLSPEC_HIDDEN; +typedef struct _VTableFixup { + DWORD rva; + WORD count; + WORD type; +} VTableFixup; + 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; +extern HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file) DECLSPEC_HIDDEN; +extern HRESULT assembly_from_hmodule(ASSEMBLY **out, HMODULE hmodule) DECLSPEC_HIDDEN; +extern HRESULT assembly_release(ASSEMBLY *assembly) DECLSPEC_HIDDEN; +extern HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) DECLSPEC_HIDDEN; +extern HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count) DECLSPEC_HIDDEN; /* Mono embedding */ typedef struct _MonoDomain MonoDomain; @@ -44,6 +52,7 @@ typedef struct _MonoObject MonoObject; typedef struct _MonoString MonoString; typedef struct _MonoMethod MonoMethod; typedef struct _MonoProfiler MonoProfiler; +typedef struct _MonoThread MonoThread; typedef struct loaded_mono loaded_mono; typedef struct RuntimeHost RuntimeHost; @@ -137,6 +146,7 @@ struct loaded_mono BOOL is_shutdown; MonoImage* (CDECL *mono_assembly_get_image)(MonoAssembly *assembly); + MonoAssembly* (CDECL *mono_assembly_load_from)(MonoImage *image, const char *fname, MonoImageOpenStatus *status); 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); @@ -144,10 +154,12 @@ struct loaded_mono void (CDECL *mono_config_parse)(const char *filename); MonoAssembly* (CDECL *mono_domain_assembly_open) (MonoDomain *domain, const char *name); void (CDECL *mono_free)(void *); + MonoImage* (CDECL *mono_image_open_from_module_handle)(HMODULE module_handle, char* fname, UINT has_entry_point, MonoImageOpenStatus* status); 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); + void* (CDECL *mono_marshal_get_vtfixup_ftnptr)(MonoImage *image, DWORD token, WORD type); MonoDomain* (CDECL *mono_object_get_domain)(MonoObject *obj); MonoObject* (CDECL *mono_object_new)(MonoDomain *domain, MonoClass *klass); void* (CDECL *mono_object_unbox)(MonoObject *obj); @@ -163,6 +175,7 @@ struct loaded_mono 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); + MonoThread* (CDECL *mono_thread_attach)(MonoDomain *domain); }; /* loaded runtime interfaces */ @@ -186,4 +199,9 @@ HRESULT WINAPI CLRMetaHost_GetRuntime(ICLRMetaHost* iface, LPCWSTR pwzVersion, R extern HRESULT CorDebug_Create(ICLRRuntimeHost *runtimehost, IUnknown** ppUnk) DECLSPEC_HIDDEN; +extern HRESULT create_monodata(REFIID riid, LPVOID *ppObj) DECLSPEC_HIDDEN; + +extern void runtimehost_init(void); +extern void runtimehost_uninit(void); + #endif /* __MSCOREE_PRIVATE__ */ diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index fcac37c7ae8..9b212a67e88 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 # Synced to Wine-1.3.37 reactos/dll/win32/mscms # Synced to Wine-1.5.4 -reactos/dll/win32/mscoree # Synced to Wine-1.3.37 +reactos/dll/win32/mscoree # Synced to Wine-1.5.4 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