| /* |
| * |
| * Copyright 2008 Alistair Leslie-Hughes |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #define COBJMACROS |
| |
| #include <stdarg.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winuser.h" |
| #include "winnls.h" |
| #include "winreg.h" |
| #include "ole2.h" |
| #include "shellapi.h" |
| |
| #include "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" |
| #include "wine/unicode.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL( mscoree ); |
| |
| #include "initguid.h" |
| |
| DEFINE_GUID(IID__AppDomain, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13); |
| |
| struct DomainEntry |
| { |
| struct list entry; |
| MonoDomain *domain; |
| }; |
| |
| static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, MonoDomain **result) |
| { |
| 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; |
| |
| This->mono->mono_thread_attach(domain); |
| |
| 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 ***/ |
| static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface, |
| REFIID riid, |
| void **ppvObject) |
| { |
| RuntimeHost *This = impl_from_ICorRuntimeHost( iface ); |
| TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject); |
| |
| if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) || |
| IsEqualGUID( riid, &IID_IUnknown ) ) |
| { |
| *ppvObject = iface; |
| } |
| else |
| { |
| FIXME("Unsupported interface %s\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| ICorRuntimeHost_AddRef( iface ); |
| |
| return S_OK; |
| } |
| |
| static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface) |
| { |
| RuntimeHost *This = impl_from_ICorRuntimeHost( iface ); |
| |
| return InterlockedIncrement( &This->ref ); |
| } |
| |
| static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface) |
| { |
| RuntimeHost *This = impl_from_ICorRuntimeHost( iface ); |
| ULONG ref; |
| |
| ref = InterlockedDecrement( &This->ref ); |
| |
| return ref; |
| } |
| |
| /*** ICorRuntimeHost methods ***/ |
| static HRESULT WINAPI corruntimehost_CreateLogicalThreadState( |
| ICorRuntimeHost* iface) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState( |
| ICorRuntimeHost* iface) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState( |
| ICorRuntimeHost* iface, |
| DWORD *fiberCookie) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState( |
| ICorRuntimeHost* iface, |
| DWORD **fiberCookie) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread( |
| ICorRuntimeHost* iface, |
| DWORD *pCount) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_MapFile( |
| ICorRuntimeHost* iface, |
| HANDLE hFile, |
| HMODULE *mapAddress) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_GetConfiguration( |
| ICorRuntimeHost* iface, |
| ICorConfiguration **pConfiguration) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_Start( |
| ICorRuntimeHost* iface) |
| { |
| FIXME("stub %p\n", iface); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI corruntimehost_Stop( |
| ICorRuntimeHost* iface) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_CreateDomain( |
| ICorRuntimeHost* iface, |
| LPCWSTR friendlyName, |
| IUnknown *identityArray, |
| IUnknown **appDomain) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_GetDefaultDomain( |
| ICorRuntimeHost* iface, |
| IUnknown **pAppDomain) |
| { |
| 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( |
| ICorRuntimeHost* iface, |
| HDOMAINENUM *hEnum) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_NextDomain( |
| ICorRuntimeHost* iface, |
| HDOMAINENUM hEnum, |
| IUnknown **appDomain) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_CloseEnum( |
| ICorRuntimeHost* iface, |
| HDOMAINENUM hEnum) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_CreateDomainEx( |
| ICorRuntimeHost* iface, |
| LPCWSTR friendlyName, |
| IUnknown *setup, |
| IUnknown *evidence, |
| IUnknown **appDomain) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_CreateDomainSetup( |
| ICorRuntimeHost* iface, |
| IUnknown **appDomainSetup) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_CreateEvidence( |
| ICorRuntimeHost* iface, |
| IUnknown **evidence) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_UnloadDomain( |
| ICorRuntimeHost* iface, |
| IUnknown *appDomain) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI corruntimehost_CurrentDomain( |
| ICorRuntimeHost* iface, |
| IUnknown **appDomain) |
| { |
| FIXME("stub %p\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static const struct ICorRuntimeHostVtbl corruntimehost_vtbl = |
| { |
| corruntimehost_QueryInterface, |
| corruntimehost_AddRef, |
| corruntimehost_Release, |
| corruntimehost_CreateLogicalThreadState, |
| corruntimehost_DeleteLogicalThreadState, |
| corruntimehost_SwitchInLogicalThreadState, |
| corruntimehost_SwitchOutLogicalThreadState, |
| corruntimehost_LocksHeldByLogicalThread, |
| corruntimehost_MapFile, |
| corruntimehost_GetConfiguration, |
| corruntimehost_Start, |
| corruntimehost_Stop, |
| corruntimehost_CreateDomain, |
| corruntimehost_GetDefaultDomain, |
| corruntimehost_EnumDomains, |
| corruntimehost_NextDomain, |
| corruntimehost_CloseEnum, |
| corruntimehost_CreateDomainEx, |
| corruntimehost_CreateDomainSetup, |
| corruntimehost_CreateEvidence, |
| corruntimehost_UnloadDomain, |
| corruntimehost_CurrentDomain |
| }; |
| |
| static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface, |
| REFIID riid, |
| void **ppvObject) |
| { |
| RuntimeHost *This = impl_from_ICLRRuntimeHost( iface ); |
| TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject); |
| |
| if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) || |
| IsEqualGUID( riid, &IID_IUnknown ) ) |
| { |
| *ppvObject = iface; |
| } |
| else |
| { |
| FIXME("Unsupported interface %s\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| ICLRRuntimeHost_AddRef( iface ); |
| |
| return S_OK; |
| } |
| |
| static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface) |
| { |
| RuntimeHost *This = impl_from_ICLRRuntimeHost( iface ); |
| return ICorRuntimeHost_AddRef(&This->ICorRuntimeHost_iface); |
| } |
| |
| static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface) |
| { |
| 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; |
| |
| This->mono->mono_thread_attach(domain); |
| |
| 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: |
| HeapFree(GetProcessHeap(), 0, filenameA); |
| HeapFree(GetProcessHeap(), 0, classA); |
| HeapFree(GetProcessHeap(), 0, argsA); |
| 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)) |
| { |
| This->mono->mono_thread_attach(domain); |
| |
| 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. |
| * |
| * mono_thread_attach must have already been called for this thread. */ |
| HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj, |
| IUnknown **ppUnk) |
| { |
| MonoDomain *domain; |
| MonoAssembly *assembly; |
| MonoImage *image; |
| MonoClass *klass; |
| MonoMethod *method; |
| MonoObject *result; |
| void *args[2]; |
| |
| domain = This->mono->mono_object_get_domain(obj); |
| |
| assembly = This->mono->mono_domain_assembly_open(domain, "mscorlib"); |
| if (!assembly) |
| { |
| ERR("Cannot load mscorlib\n"); |
| return E_FAIL; |
| } |
| |
| image = This->mono->mono_assembly_get_image(assembly); |
| if (!image) |
| { |
| ERR("Couldn't get assembly image\n"); |
| return E_FAIL; |
| } |
| |
| klass = This->mono->mono_class_from_name(image, "System.Runtime.InteropServices", "Marshal"); |
| if (!klass) |
| { |
| ERR("Couldn't get class from image\n"); |
| return E_FAIL; |
| } |
| |
| method = This->mono->mono_class_get_method_from_name(klass, "GetIUnknownForObject", 1); |
| if (!method) |
| { |
| ERR("Couldn't get method from class\n"); |
| return E_FAIL; |
| } |
| |
| args[0] = obj; |
| args[1] = NULL; |
| result = This->mono->mono_runtime_invoke(method, NULL, args, NULL); |
| if (!result) |
| { |
| ERR("Couldn't get result pointer\n"); |
| return E_FAIL; |
| } |
| |
| *ppUnk = *(IUnknown**)This->mono->mono_object_unbox(result); |
| if (!*ppUnk) |
| { |
| ERR("GetIUnknownForObject returned 0\n"); |
| return E_FAIL; |
| } |
| |
| return S_OK; |
| } |
| |
| static void get_utf8_args(int *argc, char ***argv) |
| { |
| WCHAR **argvw; |
| int size=0, i; |
| char *current_arg; |
| |
| argvw = CommandLineToArgvW(GetCommandLineW(), argc); |
| |
| for (i=0; i<*argc; i++) |
| { |
| size += sizeof(char*); |
| size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL); |
| } |
| size += sizeof(char*); |
| |
| *argv = HeapAlloc(GetProcessHeap(), 0, size); |
| current_arg = (char*)(*argv + *argc + 1); |
| |
| for (i=0; i<*argc; i++) |
| { |
| (*argv)[i] = current_arg; |
| current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL); |
| } |
| |
| (*argv)[*argc] = NULL; |
| |
| HeapFree(GetProcessHeap(), 0, argvw); |
| } |
| |
| __int32 WINAPI _CorExeMain(void) |
| { |
| int exit_code; |
| int argc; |
| char **argv; |
| MonoDomain *domain; |
| MonoAssembly *assembly; |
| WCHAR filename[MAX_PATH]; |
| char *filenameA; |
| ICLRRuntimeInfo *info; |
| RuntimeHost *host; |
| HRESULT hr; |
| int i; |
| |
| get_utf8_args(&argc, &argv); |
| |
| GetModuleFileNameW(NULL, filename, MAX_PATH); |
| |
| TRACE("%s", debugstr_w(filename)); |
| for (i=0; i<argc; i++) |
| TRACE(" %s", debugstr_a(argv[i])); |
| TRACE("\n"); |
| |
| filenameA = WtoA(filename); |
| if (!filenameA) |
| return -1; |
| |
| hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info); |
| |
| if (SUCCEEDED(hr)) |
| { |
| hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host); |
| |
| if (SUCCEEDED(hr)) |
| hr = RuntimeHost_GetDefaultDomain(host, &domain); |
| |
| if (SUCCEEDED(hr)) |
| { |
| assembly = host->mono->mono_domain_assembly_open(domain, filenameA); |
| |
| exit_code = host->mono->mono_jit_exec(domain, assembly, argc, argv); |
| |
| RuntimeHost_DeleteDomain(host, domain); |
| } |
| else |
| exit_code = -1; |
| |
| ICLRRuntimeInfo_Release(info); |
| } |
| else |
| exit_code = -1; |
| |
| HeapFree(GetProcessHeap(), 0, argv); |
| |
| unload_all_runtimes(); |
| |
| return exit_code; |
| } |
| |
| HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version, |
| loaded_mono *loaded_mono, RuntimeHost** result) |
| { |
| RuntimeHost *This; |
| |
| This = HeapAlloc( GetProcessHeap(), 0, sizeof *This ); |
| if ( !This ) |
| return E_OUTOFMEMORY; |
| |
| This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl; |
| This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl; |
| |
| 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"); |
| |
| *result = This; |
| |
| 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; |
| } |
| |
| #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; |
| } |