ddraw/tests: Validate the "surface" pointer is unmodified after CreateSurface() witho...
[wine.git] / dlls / mscoree / corruntimehost.c
blobeed96da2cdcc356a11f63c700b5c31422d79660a
1 /*
3 * Copyright 2008 Alistair Leslie-Hughes
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define COBJMACROS
22 #include <assert.h>
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "ole2.h"
31 #include "shellapi.h"
33 #include "cor.h"
34 #include "mscoree.h"
35 #include "metahost.h"
36 #include "corhdr.h"
37 #include "cordebug.h"
38 #include "wine/list.h"
39 #include "mscoree_private.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
46 #include "initguid.h"
48 DEFINE_GUID(IID__AppDomain, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13);
50 struct DomainEntry
52 struct list entry;
53 MonoDomain *domain;
56 static HANDLE dll_fixup_heap; /* using a separate heap so we can have execute permission */
58 static struct list dll_fixups;
60 struct dll_fixup
62 struct list entry;
63 BOOL done;
64 HMODULE dll;
65 void *thunk_code; /* pointer into dll_fixup_heap */
66 VTableFixup *fixup;
67 void *vtable;
68 void *tokens; /* pointer into process heap */
71 static MonoDomain* domain_attach(MonoDomain *domain)
73 MonoDomain *prev_domain = mono_domain_get();
75 if (prev_domain == domain)
76 /* Do not set or restore domain. */
77 return NULL;
79 mono_thread_attach(domain);
81 return prev_domain;
84 static void domain_restore(MonoDomain *prev_domain)
86 if (prev_domain != NULL)
87 mono_domain_set(prev_domain, FALSE);
90 static HRESULT RuntimeHost_AddDefaultDomain(RuntimeHost *This, MonoDomain **result)
92 struct DomainEntry *entry;
93 HRESULT res=S_OK;
95 EnterCriticalSection(&This->lock);
97 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
98 if (!entry)
100 res = E_OUTOFMEMORY;
101 goto end;
104 /* FIXME: Use exe filename to name the domain? */
105 entry->domain = mono_jit_init_version("mscorlib.dll", "v4.0.30319");
107 if (!entry->domain)
109 HeapFree(GetProcessHeap(), 0, entry);
110 res = E_FAIL;
111 goto end;
114 is_mono_started = TRUE;
116 list_add_tail(&This->domains, &entry->entry);
118 *result = entry->domain;
120 end:
121 LeaveCriticalSection(&This->lock);
123 return res;
126 static HRESULT RuntimeHost_GetDefaultDomain(RuntimeHost *This, const WCHAR *config_path, MonoDomain **result)
128 WCHAR config_dir[MAX_PATH];
129 WCHAR base_dir[MAX_PATH];
130 char *base_dirA, *config_pathA, *slash;
131 HRESULT res=S_OK;
133 EnterCriticalSection(&This->lock);
135 if (This->default_domain) goto end;
137 res = RuntimeHost_AddDefaultDomain(This, &This->default_domain);
139 if (!config_path)
141 DWORD len = sizeof(config_dir)/sizeof(*config_dir);
143 static const WCHAR machine_configW[] = {'\\','C','O','N','F','I','G','\\','m','a','c','h','i','n','e','.','c','o','n','f','i','g',0};
145 res = ICLRRuntimeInfo_GetRuntimeDirectory(&This->version->ICLRRuntimeInfo_iface,
146 config_dir, &len);
147 if (FAILED(res))
148 goto end;
150 lstrcatW(config_dir, machine_configW);
152 config_path = config_dir;
155 config_pathA = WtoA(config_path);
156 if (!config_pathA)
158 res = E_OUTOFMEMORY;
159 goto end;
162 GetModuleFileNameW(NULL, base_dir, sizeof(base_dir) / sizeof(*base_dir));
163 base_dirA = WtoA(base_dir);
164 if (!base_dirA)
166 HeapFree(GetProcessHeap(), 0, config_pathA);
167 res = E_OUTOFMEMORY;
168 goto end;
171 slash = strrchr(base_dirA, '\\');
172 if (slash)
173 *(slash + 1) = 0;
175 TRACE("setting base_dir: %s, config_path: %s\n", base_dirA, config_pathA);
176 mono_domain_set_config(This->default_domain, base_dirA, config_pathA);
178 HeapFree(GetProcessHeap(), 0, config_pathA);
179 HeapFree(GetProcessHeap(), 0, base_dirA);
181 end:
182 *result = This->default_domain;
184 LeaveCriticalSection(&This->lock);
186 return res;
189 static void RuntimeHost_DeleteDomain(RuntimeHost *This, MonoDomain *domain)
191 struct DomainEntry *entry;
193 EnterCriticalSection(&This->lock);
195 LIST_FOR_EACH_ENTRY(entry, &This->domains, struct DomainEntry, entry)
197 if (entry->domain == domain)
199 list_remove(&entry->entry);
200 if (This->default_domain == domain)
201 This->default_domain = NULL;
202 HeapFree(GetProcessHeap(), 0, entry);
203 break;
207 LeaveCriticalSection(&This->lock);
210 static BOOL RuntimeHost_GetMethod(MonoDomain *domain, const char *assemblyname,
211 const char *namespace, const char *typename, const char *methodname, int arg_count,
212 MonoMethod **method)
214 MonoAssembly *assembly;
215 MonoImage *image;
216 MonoClass *klass;
218 assembly = mono_domain_assembly_open(domain, assemblyname);
219 if (!assembly)
221 ERR("Cannot load assembly %s\n", assemblyname);
222 return FALSE;
225 image = mono_assembly_get_image(assembly);
226 if (!image)
228 ERR("Couldn't get assembly image for %s\n", assemblyname);
229 return FALSE;
232 klass = mono_class_from_name(image, namespace, typename);
233 if (!klass)
235 ERR("Couldn't get class %s.%s from image\n", namespace, typename);
236 return FALSE;
239 *method = mono_class_get_method_from_name(klass, methodname, arg_count);
240 if (!*method)
242 ERR("Couldn't get method %s from class %s.%s\n", methodname, namespace, typename);
243 return FALSE;
246 return TRUE;
249 static HRESULT RuntimeHost_Invoke(RuntimeHost *This, MonoDomain *domain,
250 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
251 MonoObject *obj, void **args, int arg_count, MonoObject **result);
253 static HRESULT RuntimeHost_DoInvoke(RuntimeHost *This, MonoDomain *domain,
254 const char *methodname, MonoMethod *method, MonoObject *obj, void **args, MonoObject **result)
256 MonoObject *exc;
257 static const char *get_hresult = "get_HResult";
259 *result = mono_runtime_invoke(method, obj, args, &exc);
260 if (exc)
262 HRESULT hr;
263 MonoObject *hr_object;
265 if (methodname != get_hresult)
267 /* Map the exception to an HRESULT. */
268 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System", "Exception", get_hresult,
269 exc, NULL, 0, &hr_object);
270 if (SUCCEEDED(hr))
271 hr = *(HRESULT*)mono_object_unbox(hr_object);
272 if (SUCCEEDED(hr))
273 hr = E_FAIL;
275 else
276 hr = E_FAIL;
277 *result = NULL;
278 return hr;
281 return S_OK;
284 static HRESULT RuntimeHost_Invoke(RuntimeHost *This, MonoDomain *domain,
285 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
286 MonoObject *obj, void **args, int arg_count, MonoObject **result)
288 MonoMethod *method;
289 MonoDomain *prev_domain;
290 HRESULT hr;
292 *result = NULL;
294 prev_domain = domain_attach(domain);
296 if (!RuntimeHost_GetMethod(domain, assemblyname, namespace, typename, methodname,
297 arg_count, &method))
299 domain_restore(prev_domain);
300 return E_FAIL;
303 hr = RuntimeHost_DoInvoke(This, domain, methodname, method, obj, args, result);
304 if (FAILED(hr))
306 ERR("Method %s.%s:%s raised an exception, hr=%x\n", namespace, typename, methodname, hr);
309 domain_restore(prev_domain);
311 return hr;
314 static HRESULT RuntimeHost_VirtualInvoke(RuntimeHost *This, MonoDomain *domain,
315 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
316 MonoObject *obj, void **args, int arg_count, MonoObject **result)
318 MonoMethod *method;
319 MonoDomain *prev_domain;
320 HRESULT hr;
322 *result = NULL;
324 if (!obj)
326 ERR("\"this\" object cannot be null\n");
327 return E_POINTER;
330 prev_domain = domain_attach(domain);
332 if (!RuntimeHost_GetMethod(domain, assemblyname, namespace, typename, methodname,
333 arg_count, &method))
335 domain_restore(prev_domain);
336 return E_FAIL;
339 method = mono_object_get_virtual_method(obj, method);
340 if (!method)
342 ERR("Object %p does not support method %s.%s:%s\n", obj, namespace, typename, methodname);
343 domain_restore(prev_domain);
344 return E_FAIL;
347 hr = RuntimeHost_DoInvoke(This, domain, methodname, method, obj, args, result);
348 if (FAILED(hr))
350 ERR("Method %s.%s:%s raised an exception, hr=%x\n", namespace, typename, methodname, hr);
353 domain_restore(prev_domain);
355 return hr;
358 static HRESULT RuntimeHost_GetObjectForIUnknown(RuntimeHost *This, MonoDomain *domain,
359 IUnknown *unk, MonoObject **obj)
361 HRESULT hr;
362 void *args[1];
363 MonoObject *result;
365 args[0] = &unk;
366 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System.Runtime.InteropServices", "Marshal", "GetObjectForIUnknown",
367 NULL, args, 1, &result);
369 if (SUCCEEDED(hr))
371 *obj = result;
373 return hr;
376 static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, const WCHAR *name, IUnknown *setup,
377 IUnknown *evidence, MonoDomain **result)
379 HRESULT res;
380 char *nameA;
381 MonoDomain *domain;
382 void *args[3];
383 MonoObject *new_domain, *id;
385 res = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
386 if (FAILED(res))
388 return res;
391 nameA = WtoA(name);
392 if (!nameA)
394 return E_OUTOFMEMORY;
397 args[0] = mono_string_new(domain, nameA);
398 HeapFree(GetProcessHeap(), 0, nameA);
400 if (!args[0])
402 return E_OUTOFMEMORY;
405 if (evidence)
407 res = RuntimeHost_GetObjectForIUnknown(This, domain, evidence, (MonoObject **)&args[1]);
408 if (FAILED(res))
410 return res;
413 else
415 args[1] = NULL;
418 if (setup)
420 res = RuntimeHost_GetObjectForIUnknown(This, domain, setup, (MonoObject **)&args[2]);
421 if (FAILED(res))
423 return res;
426 else
428 args[2] = NULL;
431 res = RuntimeHost_Invoke(This, domain, "mscorlib", "System", "AppDomain", "CreateDomain",
432 NULL, args, 3, &new_domain);
434 if (FAILED(res))
436 return res;
439 /* new_domain is not the AppDomain itself, but a transparent proxy.
440 * So, we'll retrieve its ID, and use that to get the real domain object.
441 * We can't do a regular invoke, because that will bypass the proxy.
442 * Instead, do a vcall.
445 res = RuntimeHost_VirtualInvoke(This, domain, "mscorlib", "System", "AppDomain", "get_Id",
446 new_domain, NULL, 0, &id);
448 if (FAILED(res))
450 return res;
453 TRACE("returning domain id %d\n", *(int *)mono_object_unbox(id));
455 *result = mono_domain_get_by_id(*(int *)mono_object_unbox(id));
457 return S_OK;
460 static HRESULT RuntimeHost_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *domain, IUnknown **punk)
462 HRESULT hr;
463 MonoObject *appdomain_object;
464 IUnknown *unk;
466 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System", "AppDomain", "get_CurrentDomain",
467 NULL, NULL, 0, &appdomain_object);
469 if (SUCCEEDED(hr))
470 hr = RuntimeHost_GetIUnknownForObject(This, appdomain_object, &unk);
472 if (SUCCEEDED(hr))
474 hr = IUnknown_QueryInterface(unk, &IID__AppDomain, (void**)punk);
476 IUnknown_Release(unk);
479 return hr;
482 void RuntimeHost_ExitProcess(RuntimeHost *This, INT exitcode)
484 HRESULT hr;
485 void *args[2];
486 MonoDomain *domain;
487 MonoObject *dummy;
489 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
490 if (FAILED(hr))
492 ERR("Cannot get domain, hr=%x\n", hr);
493 return;
496 args[0] = &exitcode;
497 args[1] = NULL;
498 RuntimeHost_Invoke(This, domain, "mscorlib", "System", "Environment", "Exit",
499 NULL, args, 1, &dummy);
501 ERR("Process should have exited\n");
504 static inline RuntimeHost *impl_from_ICLRRuntimeHost( ICLRRuntimeHost *iface )
506 return CONTAINING_RECORD(iface, RuntimeHost, ICLRRuntimeHost_iface);
509 static inline RuntimeHost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
511 return CONTAINING_RECORD(iface, RuntimeHost, ICorRuntimeHost_iface);
514 /*** IUnknown methods ***/
515 static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
516 REFIID riid,
517 void **ppvObject)
519 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
520 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
522 if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) ||
523 IsEqualGUID( riid, &IID_IUnknown ) )
525 *ppvObject = iface;
527 else
529 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
530 return E_NOINTERFACE;
533 ICorRuntimeHost_AddRef( iface );
535 return S_OK;
538 static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface)
540 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
542 return InterlockedIncrement( &This->ref );
545 static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface)
547 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
548 ULONG ref;
550 ref = InterlockedDecrement( &This->ref );
552 return ref;
555 /*** ICorRuntimeHost methods ***/
556 static HRESULT WINAPI corruntimehost_CreateLogicalThreadState(
557 ICorRuntimeHost* iface)
559 FIXME("stub %p\n", iface);
560 return E_NOTIMPL;
563 static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState(
564 ICorRuntimeHost* iface)
566 FIXME("stub %p\n", iface);
567 return E_NOTIMPL;
570 static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState(
571 ICorRuntimeHost* iface,
572 DWORD *fiberCookie)
574 FIXME("stub %p\n", iface);
575 return E_NOTIMPL;
578 static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState(
579 ICorRuntimeHost* iface,
580 DWORD **fiberCookie)
582 FIXME("stub %p\n", iface);
583 return E_NOTIMPL;
586 static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread(
587 ICorRuntimeHost* iface,
588 DWORD *pCount)
590 FIXME("stub %p\n", iface);
591 return E_NOTIMPL;
594 static HRESULT WINAPI corruntimehost_MapFile(
595 ICorRuntimeHost* iface,
596 HANDLE hFile,
597 HMODULE *mapAddress)
599 FIXME("stub %p\n", iface);
600 return E_NOTIMPL;
603 static HRESULT WINAPI corruntimehost_GetConfiguration(
604 ICorRuntimeHost* iface,
605 ICorConfiguration **pConfiguration)
607 FIXME("stub %p\n", iface);
608 return E_NOTIMPL;
611 static HRESULT WINAPI corruntimehost_Start(
612 ICorRuntimeHost* iface)
614 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
615 MonoDomain *dummy;
617 TRACE("%p\n", This);
619 return RuntimeHost_GetDefaultDomain(This, NULL, &dummy);
622 static HRESULT WINAPI corruntimehost_Stop(
623 ICorRuntimeHost* iface)
625 FIXME("stub %p\n", iface);
626 return E_NOTIMPL;
629 static HRESULT WINAPI corruntimehost_CreateDomain(
630 ICorRuntimeHost* iface,
631 LPCWSTR friendlyName,
632 IUnknown *identityArray,
633 IUnknown **appDomain)
635 return ICorRuntimeHost_CreateDomainEx(iface, friendlyName, NULL, NULL, appDomain);
638 static HRESULT WINAPI corruntimehost_GetDefaultDomain(
639 ICorRuntimeHost* iface,
640 IUnknown **pAppDomain)
642 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
643 HRESULT hr;
644 MonoDomain *domain;
646 TRACE("(%p)\n", iface);
648 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
650 if (SUCCEEDED(hr))
652 hr = RuntimeHost_GetIUnknownForDomain(This, domain, pAppDomain);
655 return hr;
658 static HRESULT WINAPI corruntimehost_EnumDomains(
659 ICorRuntimeHost* iface,
660 HDOMAINENUM *hEnum)
662 FIXME("stub %p\n", iface);
663 return E_NOTIMPL;
666 static HRESULT WINAPI corruntimehost_NextDomain(
667 ICorRuntimeHost* iface,
668 HDOMAINENUM hEnum,
669 IUnknown **appDomain)
671 FIXME("stub %p\n", iface);
672 return E_NOTIMPL;
675 static HRESULT WINAPI corruntimehost_CloseEnum(
676 ICorRuntimeHost* iface,
677 HDOMAINENUM hEnum)
679 FIXME("stub %p\n", iface);
680 return E_NOTIMPL;
683 static HRESULT WINAPI corruntimehost_CreateDomainEx(
684 ICorRuntimeHost* iface,
685 LPCWSTR friendlyName,
686 IUnknown *setup,
687 IUnknown *evidence,
688 IUnknown **appDomain)
690 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
691 HRESULT hr;
692 MonoDomain *domain;
694 if (!friendlyName || !appDomain)
696 return E_POINTER;
698 if (!is_mono_started)
700 return E_FAIL;
703 TRACE("(%p)\n", iface);
705 hr = RuntimeHost_AddDomain(This, friendlyName, setup, evidence, &domain);
707 if (SUCCEEDED(hr))
709 hr = RuntimeHost_GetIUnknownForDomain(This, domain, appDomain);
712 return hr;
715 static HRESULT WINAPI corruntimehost_CreateDomainSetup(
716 ICorRuntimeHost* iface,
717 IUnknown **appDomainSetup)
719 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
720 HRESULT hr;
721 MonoDomain *domain;
722 MonoObject *obj;
723 static const WCHAR classnameW[] = {'S','y','s','t','e','m','.','A','p','p','D','o','m','a','i','n','S','e','t','u','p',',','m','s','c','o','r','l','i','b',0};
725 TRACE("(%p)\n", iface);
727 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
729 if (SUCCEEDED(hr))
730 hr = RuntimeHost_CreateManagedInstance(This, classnameW, domain, &obj);
732 if (SUCCEEDED(hr))
733 hr = RuntimeHost_GetIUnknownForObject(This, obj, appDomainSetup);
735 return hr;
738 static HRESULT WINAPI corruntimehost_CreateEvidence(
739 ICorRuntimeHost* iface,
740 IUnknown **evidence)
742 FIXME("stub %p\n", iface);
743 return E_NOTIMPL;
746 static HRESULT WINAPI corruntimehost_UnloadDomain(
747 ICorRuntimeHost* iface,
748 IUnknown *appDomain)
750 FIXME("stub %p\n", iface);
751 return E_NOTIMPL;
754 static HRESULT WINAPI corruntimehost_CurrentDomain(
755 ICorRuntimeHost* iface,
756 IUnknown **appDomain)
758 FIXME("stub %p\n", iface);
759 return E_NOTIMPL;
762 static const struct ICorRuntimeHostVtbl corruntimehost_vtbl =
764 corruntimehost_QueryInterface,
765 corruntimehost_AddRef,
766 corruntimehost_Release,
767 corruntimehost_CreateLogicalThreadState,
768 corruntimehost_DeleteLogicalThreadState,
769 corruntimehost_SwitchInLogicalThreadState,
770 corruntimehost_SwitchOutLogicalThreadState,
771 corruntimehost_LocksHeldByLogicalThread,
772 corruntimehost_MapFile,
773 corruntimehost_GetConfiguration,
774 corruntimehost_Start,
775 corruntimehost_Stop,
776 corruntimehost_CreateDomain,
777 corruntimehost_GetDefaultDomain,
778 corruntimehost_EnumDomains,
779 corruntimehost_NextDomain,
780 corruntimehost_CloseEnum,
781 corruntimehost_CreateDomainEx,
782 corruntimehost_CreateDomainSetup,
783 corruntimehost_CreateEvidence,
784 corruntimehost_UnloadDomain,
785 corruntimehost_CurrentDomain
788 static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface,
789 REFIID riid,
790 void **ppvObject)
792 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
793 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
795 if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) ||
796 IsEqualGUID( riid, &IID_IUnknown ) )
798 *ppvObject = iface;
800 else
802 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
803 return E_NOINTERFACE;
806 ICLRRuntimeHost_AddRef( iface );
808 return S_OK;
811 static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface)
813 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
814 return ICorRuntimeHost_AddRef(&This->ICorRuntimeHost_iface);
817 static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface)
819 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
820 return ICorRuntimeHost_Release(&This->ICorRuntimeHost_iface);
823 static HRESULT WINAPI CLRRuntimeHost_Start(ICLRRuntimeHost* iface)
825 FIXME("(%p)\n", iface);
826 return E_NOTIMPL;
829 static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
831 FIXME("(%p)\n", iface);
832 return E_NOTIMPL;
835 static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
836 IHostControl *pHostControl)
838 FIXME("(%p,%p)\n", iface, pHostControl);
839 return E_NOTIMPL;
842 static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
843 ICLRControl **pCLRControl)
845 FIXME("(%p,%p)\n", iface, pCLRControl);
846 return E_NOTIMPL;
849 static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
850 DWORD dwAppDomainId, BOOL fWaitUntilDone)
852 FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
853 return E_NOTIMPL;
856 static HRESULT WINAPI CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost* iface,
857 DWORD dwAppDomainId, FExecuteInAppDomainCallback pCallback, void *cookie)
859 FIXME("(%p,%u,%p,%p)\n", iface, dwAppDomainId, pCallback, cookie);
860 return E_NOTIMPL;
863 static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
864 DWORD *pdwAppDomainId)
866 FIXME("(%p,%p)\n", iface, pdwAppDomainId);
867 return E_NOTIMPL;
870 static HRESULT WINAPI CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost* iface,
871 LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR *ppwzManifestPaths,
872 DWORD dwActivationData, LPCWSTR *ppwzActivationData, int *pReturnValue)
874 FIXME("(%p,%s,%u,%u)\n", iface, debugstr_w(pwzAppFullName), dwManifestPaths, dwActivationData);
875 return E_NOTIMPL;
878 static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* iface,
879 LPCWSTR pwzAssemblyPath, LPCWSTR pwzTypeName, LPCWSTR pwzMethodName,
880 LPCWSTR pwzArgument, DWORD *pReturnValue)
882 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
883 HRESULT hr;
884 MonoDomain *domain, *prev_domain;
885 MonoObject *result;
886 MonoString *str;
887 char *filenameA = NULL, *classA = NULL, *methodA = NULL;
888 char *argsA = NULL, *ns;
890 TRACE("(%p,%s,%s,%s,%s)\n", iface, debugstr_w(pwzAssemblyPath),
891 debugstr_w(pwzTypeName), debugstr_w(pwzMethodName), debugstr_w(pwzArgument));
893 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
895 if (FAILED(hr))
896 return hr;
898 prev_domain = domain_attach(domain);
900 if (SUCCEEDED(hr))
902 filenameA = WtoA(pwzAssemblyPath);
903 if (!filenameA) hr = E_OUTOFMEMORY;
906 if (SUCCEEDED(hr))
908 classA = WtoA(pwzTypeName);
909 if (!classA) hr = E_OUTOFMEMORY;
912 if (SUCCEEDED(hr))
914 ns = strrchr(classA, '.');
915 if (ns)
916 *ns = '\0';
917 else
918 hr = E_INVALIDARG;
921 if (SUCCEEDED(hr))
923 methodA = WtoA(pwzMethodName);
924 if (!methodA) hr = E_OUTOFMEMORY;
927 /* The .NET function we are calling has the following declaration
928 * public static int functionName(String param)
930 if (SUCCEEDED(hr))
932 argsA = WtoA(pwzArgument);
933 if (!argsA) hr = E_OUTOFMEMORY;
936 if (SUCCEEDED(hr))
938 str = mono_string_new(domain, argsA);
939 if (!str) hr = E_OUTOFMEMORY;
942 if (SUCCEEDED(hr))
944 hr = RuntimeHost_Invoke(This, domain, filenameA, classA, ns+1, methodA,
945 NULL, (void**)&str, 1, &result);
948 if (SUCCEEDED(hr))
949 *pReturnValue = *(DWORD*)mono_object_unbox(result);
951 domain_restore(prev_domain);
953 HeapFree(GetProcessHeap(), 0, filenameA);
954 HeapFree(GetProcessHeap(), 0, classA);
955 HeapFree(GetProcessHeap(), 0, argsA);
956 HeapFree(GetProcessHeap(), 0, methodA);
958 return hr;
961 static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
963 CLRRuntimeHost_QueryInterface,
964 CLRRuntimeHost_AddRef,
965 CLRRuntimeHost_Release,
966 CLRRuntimeHost_Start,
967 CLRRuntimeHost_Stop,
968 CLRRuntimeHost_SetHostControl,
969 CLRRuntimeHost_GetCLRControl,
970 CLRRuntimeHost_UnloadAppDomain,
971 CLRRuntimeHost_ExecuteInAppDomain,
972 CLRRuntimeHost_GetCurrentAppDomainId,
973 CLRRuntimeHost_ExecuteApplication,
974 CLRRuntimeHost_ExecuteInDefaultAppDomain
977 /* Create an instance of a type given its name, by calling its constructor with
978 * no arguments. Note that result MUST be in the stack, or the garbage
979 * collector may free it prematurely. */
980 HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
981 MonoDomain *domain, MonoObject **result)
983 HRESULT hr=S_OK;
984 char *nameA=NULL;
985 MonoType *type;
986 MonoClass *klass;
987 MonoObject *obj;
988 MonoDomain *prev_domain;
990 if (!domain)
991 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
993 if (FAILED(hr))
994 return hr;
996 prev_domain = domain_attach(domain);
998 if (SUCCEEDED(hr))
1000 nameA = WtoA(name);
1001 if (!nameA)
1002 hr = E_OUTOFMEMORY;
1005 if (SUCCEEDED(hr))
1007 type = mono_reflection_type_from_name(nameA, NULL);
1008 if (!type)
1010 ERR("Cannot find type %s\n", debugstr_w(name));
1011 hr = E_FAIL;
1015 if (SUCCEEDED(hr))
1017 klass = mono_class_from_mono_type(type);
1018 if (!klass)
1020 ERR("Cannot convert type %s to a class\n", debugstr_w(name));
1021 hr = E_FAIL;
1025 if (SUCCEEDED(hr))
1027 obj = mono_object_new(domain, klass);
1028 if (!obj)
1030 ERR("Cannot allocate object of type %s\n", debugstr_w(name));
1031 hr = E_FAIL;
1035 if (SUCCEEDED(hr))
1037 /* FIXME: Detect exceptions from the constructor? */
1038 mono_runtime_object_init(obj);
1039 *result = obj;
1042 domain_restore(prev_domain);
1044 HeapFree(GetProcessHeap(), 0, nameA);
1046 return hr;
1049 /* Get an IUnknown pointer for a Mono object.
1051 * This is just a "light" wrapper around
1052 * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
1054 * NOTE: The IUnknown* is created with a reference to the object.
1055 * Until they have a reference, objects must be in the stack to prevent the
1056 * garbage collector from freeing them. */
1057 HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj,
1058 IUnknown **ppUnk)
1060 MonoDomain *domain;
1061 MonoObject *result;
1062 HRESULT hr;
1064 domain = mono_object_get_domain(obj);
1066 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System.Runtime.InteropServices", "Marshal", "GetIUnknownForObject",
1067 NULL, (void**)&obj, 1, &result);
1069 if (SUCCEEDED(hr))
1070 *ppUnk = *(IUnknown**)mono_object_unbox(result);
1071 else
1072 *ppUnk = NULL;
1074 return hr;
1077 static void get_utf8_args(int *argc, char ***argv)
1079 WCHAR **argvw;
1080 int size=0, i;
1081 char *current_arg;
1083 argvw = CommandLineToArgvW(GetCommandLineW(), argc);
1085 for (i=0; i<*argc; i++)
1087 size += sizeof(char*);
1088 size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
1090 size += sizeof(char*);
1092 *argv = HeapAlloc(GetProcessHeap(), 0, size);
1093 current_arg = (char*)(*argv + *argc + 1);
1095 for (i=0; i<*argc; i++)
1097 (*argv)[i] = current_arg;
1098 current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
1101 (*argv)[*argc] = NULL;
1103 HeapFree(GetProcessHeap(), 0, argvw);
1106 #if __i386__
1108 # define CAN_FIXUP_VTABLE 1
1110 #include "pshpack1.h"
1112 struct vtable_fixup_thunk
1114 /* push %ecx */
1115 BYTE i7;
1116 /* sub $0x4,%esp */
1117 BYTE i1[3];
1118 /* mov fixup,(%esp) */
1119 BYTE i2[3];
1120 struct dll_fixup *fixup;
1121 /* mov function,%eax */
1122 BYTE i3;
1123 void (CDECL *function)(struct dll_fixup *);
1124 /* call *%eax */
1125 BYTE i4[2];
1126 /* pop %eax */
1127 BYTE i5;
1128 /* pop %ecx */
1129 BYTE i8;
1130 /* jmp *vtable_entry */
1131 BYTE i6[2];
1132 void *vtable_entry;
1135 static const struct vtable_fixup_thunk thunk_template = {
1136 0x51,
1137 {0x83,0xec,0x04},
1138 {0xc7,0x04,0x24},
1139 NULL,
1140 0xb8,
1141 NULL,
1142 {0xff,0xd0},
1143 0x58,
1144 0x59,
1145 {0xff,0x25},
1146 NULL
1149 #include "poppack.h"
1151 #elif __x86_64__ /* !__i386__ */
1153 # define CAN_FIXUP_VTABLE 1
1155 #include "pshpack1.h"
1157 struct vtable_fixup_thunk
1159 /* push %rbp;
1160 mov %rsp, %rbp
1161 sub $0x80, %rsp ; 0x8*4 + 0x10*4 + 0x20
1163 BYTE i1[11];
1165 mov %rcx, 0x60(%rsp); mov %rdx, 0x68(%rsp); mov %r8, 0x70(%rsp); mov %r9, 0x78(%rsp);
1166 movaps %xmm0,0x20(%rsp); ...; movaps %xmm3,0x50(%esp)
1168 BYTE i2[40];
1169 /* mov function,%rax */
1170 BYTE i3[2];
1171 void (CDECL *function)(struct dll_fixup *);
1172 /* mov fixup,%rcx */
1173 BYTE i4[2];
1174 struct dll_fixup *fixup;
1175 /* call *%rax */
1176 BYTE i5[2];
1178 mov 0x60(%rsp),%rcx; mov 0x68(%rsp),%rdx; mov 0x70(%rsp),%r8; mov 0x78(%rsp),%r9;
1179 movaps 0x20(%rsp),xmm0; ...; movaps 0x50(%esp),xmm3
1181 BYTE i6[40];
1182 /* mov %rbp, %rsp
1183 pop %rbp
1185 BYTE i7[4];
1186 /* mov vtable_entry, %rax */
1187 BYTE i8[2];
1188 void *vtable_entry;
1189 /* mov [%rax],%rax
1190 jmp %rax */
1191 BYTE i9[5];
1194 static const struct vtable_fixup_thunk thunk_template = {
1195 {0x55,0x48,0x89,0xE5, 0x48,0x81,0xEC,0x80,0x00,0x00,0x00},
1196 {0x48,0x89,0x4C,0x24,0x60, 0x48,0x89,0x54,0x24,0x68,
1197 0x4C,0x89,0x44,0x24,0x70, 0x4C,0x89,0x4C,0x24,0x78,
1198 0x0F,0x29,0x44,0x24,0x20, 0x0F,0x29,0x4C,0x24,0x30,
1199 0x0F,0x29,0x54,0x24,0x40, 0x0F,0x29,0x5C,0x24,0x50,
1201 {0x48,0xB8},
1202 NULL,
1203 {0x48,0xB9},
1204 NULL,
1205 {0xFF,0xD0},
1206 {0x48,0x8B,0x4C,0x24,0x60, 0x48,0x8B,0x54,0x24,0x68,
1207 0x4C,0x8B,0x44,0x24,0x70, 0x4C,0x8B,0x4C,0x24,0x78,
1208 0x0F,0x28,0x44,0x24,0x20, 0x0F,0x28,0x4C,0x24,0x30,
1209 0x0F,0x28,0x54,0x24,0x40, 0x0F,0x28,0x5C,0x24,0x50,
1211 {0x48,0x89,0xEC, 0x5D},
1212 {0x48,0xB8},
1213 NULL,
1214 {0x48,0x8B,0x00,0xFF,0xE0}
1217 #include "poppack.h"
1219 #else /* !__i386__ && !__x86_64__ */
1221 # define CAN_FIXUP_VTABLE 0
1223 struct vtable_fixup_thunk
1225 struct dll_fixup *fixup;
1226 void (CDECL *function)(struct dll_fixup *fixup);
1227 void *vtable_entry;
1230 static const struct vtable_fixup_thunk thunk_template = {0};
1232 #endif
1234 static void CDECL ReallyFixupVTable(struct dll_fixup *fixup)
1236 HRESULT hr=S_OK;
1237 WCHAR filename[MAX_PATH];
1238 ICLRRuntimeInfo *info=NULL;
1239 RuntimeHost *host;
1240 char *filenameA;
1241 MonoImage *image=NULL;
1242 MonoAssembly *assembly=NULL;
1243 MonoImageOpenStatus status=0;
1244 MonoDomain *domain;
1246 if (fixup->done) return;
1248 /* It's possible we'll have two threads doing this at once. This is
1249 * considered preferable to the potential deadlock if we use a mutex. */
1251 GetModuleFileNameW(fixup->dll, filename, MAX_PATH);
1253 TRACE("%p,%p,%s\n", fixup, fixup->dll, debugstr_w(filename));
1255 filenameA = WtoA(filename);
1256 if (!filenameA)
1257 hr = E_OUTOFMEMORY;
1259 if (SUCCEEDED(hr))
1260 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1262 if (SUCCEEDED(hr))
1263 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1265 if (SUCCEEDED(hr))
1266 hr = RuntimeHost_GetDefaultDomain(host, NULL, &domain);
1268 if (SUCCEEDED(hr))
1270 MonoDomain *prev_domain;
1272 prev_domain = domain_attach(domain);
1274 assembly = mono_assembly_open(filenameA, &status);
1276 if (assembly)
1278 int i;
1280 /* Mono needs an image that belongs to an assembly. */
1281 image = mono_assembly_get_image(assembly);
1283 #if __x86_64__
1284 if (fixup->fixup->type & COR_VTABLE_64BIT)
1285 #else
1286 if (fixup->fixup->type & COR_VTABLE_32BIT)
1287 #endif
1289 void **vtable = fixup->vtable;
1290 ULONG_PTR *tokens = fixup->tokens;
1291 for (i=0; i<fixup->fixup->count; i++)
1293 TRACE("%#lx\n", tokens[i]);
1294 vtable[i] = mono_marshal_get_vtfixup_ftnptr(
1295 image, tokens[i], fixup->fixup->type);
1299 fixup->done = TRUE;
1302 domain_restore(prev_domain);
1305 if (info != NULL)
1306 ICLRRuntimeInfo_Release(info);
1308 HeapFree(GetProcessHeap(), 0, filenameA);
1310 if (!fixup->done)
1312 ERR("unable to fixup vtable, hr=%x, status=%d\n", hr, status);
1313 /* If we returned now, we'd get an infinite loop. */
1314 assert(0);
1318 static void FixupVTableEntry(HMODULE hmodule, VTableFixup *vtable_fixup)
1320 /* We can't actually generate code for the functions without loading mono,
1321 * and loading mono inside DllMain is a terrible idea. So we make thunks
1322 * that call ReallyFixupVTable, which will load the runtime and fill in the
1323 * vtable, then do an indirect jump using the (now filled in) vtable. Note
1324 * that we have to keep the thunks around forever, as one of them may get
1325 * called while we're filling in the table, and we can never be sure all
1326 * threads are clear. */
1327 struct dll_fixup *fixup;
1329 fixup = HeapAlloc(GetProcessHeap(), 0, sizeof(*fixup));
1331 fixup->dll = hmodule;
1332 fixup->thunk_code = HeapAlloc(dll_fixup_heap, 0, sizeof(struct vtable_fixup_thunk) * vtable_fixup->count);
1333 fixup->fixup = vtable_fixup;
1334 fixup->vtable = (BYTE*)hmodule + vtable_fixup->rva;
1335 fixup->done = FALSE;
1337 TRACE("vtable_fixup->type=0x%x\n",vtable_fixup->type);
1338 #if __x86_64__
1339 if (vtable_fixup->type & COR_VTABLE_64BIT)
1340 #else
1341 if (vtable_fixup->type & COR_VTABLE_32BIT)
1342 #endif
1344 void **vtable = fixup->vtable;
1345 ULONG_PTR *tokens;
1346 int i;
1347 struct vtable_fixup_thunk *thunks = fixup->thunk_code;
1349 tokens = fixup->tokens = HeapAlloc(GetProcessHeap(), 0, sizeof(*tokens) * vtable_fixup->count);
1350 memcpy(tokens, vtable, sizeof(*tokens) * vtable_fixup->count);
1351 for (i=0; i<vtable_fixup->count; i++)
1353 thunks[i] = thunk_template;
1354 thunks[i].fixup = fixup;
1355 thunks[i].function = ReallyFixupVTable;
1356 thunks[i].vtable_entry = &vtable[i];
1357 vtable[i] = &thunks[i];
1360 else
1362 ERR("unsupported vtable fixup flags %x\n", vtable_fixup->type);
1363 HeapFree(dll_fixup_heap, 0, fixup->thunk_code);
1364 HeapFree(GetProcessHeap(), 0, fixup);
1365 return;
1368 list_add_tail(&dll_fixups, &fixup->entry);
1371 static void FixupVTable_Assembly(HMODULE hmodule, ASSEMBLY *assembly)
1373 VTableFixup *vtable_fixups;
1374 ULONG vtable_fixup_count, i;
1376 assembly_get_vtable_fixups(assembly, &vtable_fixups, &vtable_fixup_count);
1377 if (CAN_FIXUP_VTABLE)
1378 for (i=0; i<vtable_fixup_count; i++)
1379 FixupVTableEntry(hmodule, &vtable_fixups[i]);
1380 else if (vtable_fixup_count)
1381 FIXME("cannot fixup vtable; expect a crash\n");
1384 static void FixupVTable(HMODULE hmodule)
1386 ASSEMBLY *assembly;
1387 HRESULT hr;
1389 hr = assembly_from_hmodule(&assembly, hmodule);
1390 if (SUCCEEDED(hr))
1392 FixupVTable_Assembly(hmodule, assembly);
1393 assembly_release(assembly);
1395 else
1396 ERR("failed to read CLR headers, hr=%x\n", hr);
1399 __int32 WINAPI _CorExeMain(void)
1401 int exit_code;
1402 int argc;
1403 char **argv;
1404 MonoDomain *domain=NULL;
1405 MonoImage *image;
1406 MonoImageOpenStatus status;
1407 MonoAssembly *assembly=NULL;
1408 WCHAR filename[MAX_PATH];
1409 char *filenameA;
1410 ICLRRuntimeInfo *info;
1411 RuntimeHost *host;
1412 HRESULT hr;
1413 int i;
1415 get_utf8_args(&argc, &argv);
1417 GetModuleFileNameW(NULL, filename, MAX_PATH);
1419 TRACE("%s", debugstr_w(filename));
1420 for (i=0; i<argc; i++)
1421 TRACE(" %s", debugstr_a(argv[i]));
1422 TRACE("\n");
1424 filenameA = WtoA(filename);
1425 if (!filenameA)
1427 HeapFree(GetProcessHeap(), 0, argv);
1428 return -1;
1431 FixupVTable(GetModuleHandleW(NULL));
1433 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1435 if (SUCCEEDED(hr))
1437 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1439 if (SUCCEEDED(hr))
1441 WCHAR config_file[MAX_PATH];
1442 static const WCHAR dotconfig[] = {'.','c','o','n','f','i','g',0};
1444 strcpyW(config_file, filename);
1445 strcatW(config_file, dotconfig);
1447 hr = RuntimeHost_GetDefaultDomain(host, config_file, &domain);
1450 if (SUCCEEDED(hr))
1452 image = mono_image_open_from_module_handle(GetModuleHandleW(NULL),
1453 filenameA, 1, &status);
1455 if (image)
1456 assembly = mono_assembly_load_from(image, filenameA, &status);
1458 if (assembly)
1460 mono_trace_set_assembly(assembly);
1462 exit_code = mono_jit_exec(domain, assembly, argc, argv);
1464 else
1466 ERR("couldn't load %s, status=%d\n", debugstr_w(filename), status);
1467 exit_code = -1;
1470 RuntimeHost_DeleteDomain(host, domain);
1472 else
1473 exit_code = -1;
1475 ICLRRuntimeInfo_Release(info);
1477 else
1478 exit_code = -1;
1480 HeapFree(GetProcessHeap(), 0, argv);
1482 if (domain)
1484 mono_thread_manage();
1485 mono_runtime_quit();
1488 return exit_code;
1491 BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1493 ASSEMBLY *assembly=NULL;
1494 HRESULT hr;
1496 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1498 hr = assembly_from_hmodule(&assembly, hinstDLL);
1499 if (SUCCEEDED(hr))
1501 NativeEntryPointFunc NativeEntryPoint=NULL;
1503 assembly_get_native_entrypoint(assembly, &NativeEntryPoint);
1504 if (fdwReason == DLL_PROCESS_ATTACH)
1506 if (!NativeEntryPoint)
1507 DisableThreadLibraryCalls(hinstDLL);
1508 FixupVTable_Assembly(hinstDLL,assembly);
1510 assembly_release(assembly);
1511 /* FIXME: clean up the vtables on DLL_PROCESS_DETACH */
1512 if (NativeEntryPoint)
1513 return NativeEntryPoint(hinstDLL, fdwReason, lpvReserved);
1515 else
1516 ERR("failed to read CLR headers, hr=%x\n", hr);
1518 return TRUE;
1521 /* called from DLL_PROCESS_ATTACH */
1522 void runtimehost_init(void)
1524 dll_fixup_heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
1525 list_init(&dll_fixups);
1528 /* called from DLL_PROCESS_DETACH */
1529 void runtimehost_uninit(void)
1531 struct dll_fixup *fixup, *fixup2;
1533 HeapDestroy(dll_fixup_heap);
1534 LIST_FOR_EACH_ENTRY_SAFE(fixup, fixup2, &dll_fixups, struct dll_fixup, entry)
1536 HeapFree(GetProcessHeap(), 0, fixup->tokens);
1537 HeapFree(GetProcessHeap(), 0, fixup);
1541 HRESULT RuntimeHost_Construct(CLRRuntimeInfo *runtime_version, RuntimeHost** result)
1543 RuntimeHost *This;
1545 This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1546 if ( !This )
1547 return E_OUTOFMEMORY;
1549 This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
1550 This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
1552 This->ref = 1;
1553 This->version = runtime_version;
1554 list_init(&This->domains);
1555 This->default_domain = NULL;
1556 InitializeCriticalSection(&This->lock);
1557 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
1559 *result = This;
1561 return S_OK;
1564 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
1566 IUnknown *unk;
1567 HRESULT hr;
1569 if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
1571 unk = (IUnknown*)&This->ICorRuntimeHost_iface;
1572 IUnknown_AddRef(unk);
1574 else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
1576 unk = (IUnknown*)&This->ICLRRuntimeHost_iface;
1577 IUnknown_AddRef(unk);
1579 else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
1580 IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
1582 hr = MetaDataDispenser_CreateInstance(&unk);
1583 if (FAILED(hr))
1584 return hr;
1586 else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
1588 hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
1589 if (FAILED(hr))
1590 return hr;
1592 else
1593 unk = NULL;
1595 if (unk)
1597 hr = IUnknown_QueryInterface(unk, riid, ppv);
1599 IUnknown_Release(unk);
1601 return hr;
1603 else
1604 FIXME("not implemented for class %s\n", debugstr_guid(clsid));
1606 return CLASS_E_CLASSNOTAVAILABLE;
1609 #define CHARS_IN_GUID 39
1610 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
1612 HRESULT create_monodata(REFIID riid, LPVOID *ppObj )
1614 static const WCHAR wszAssembly[] = {'A','s','s','e','m','b','l','y',0};
1615 static const WCHAR wszCodebase[] = {'C','o','d','e','B','a','s','e',0};
1616 static const WCHAR wszClass[] = {'C','l','a','s','s',0};
1617 static const WCHAR wszFileSlash[] = {'f','i','l','e',':','/','/','/',0};
1618 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1619 static const WCHAR wszInprocServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1620 static const WCHAR wszDLL[] = {'.','d','l','l',0};
1621 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) + ARRAYSIZE(wszInprocServer32) - 1];
1622 MonoDomain *domain;
1623 MonoAssembly *assembly;
1624 ICLRRuntimeInfo *info = NULL;
1625 RuntimeHost *host;
1626 HRESULT hr;
1627 HKEY key, subkey;
1628 LONG res;
1629 int offset = 0;
1630 DWORD numKeys, keyLength;
1631 WCHAR codebase[MAX_PATH + 8];
1632 WCHAR classname[350], subkeyName[256];
1633 WCHAR filename[MAX_PATH];
1635 DWORD dwBufLen = 350;
1637 lstrcpyW(path, wszCLSIDSlash);
1638 StringFromGUID2(riid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
1639 lstrcatW(path, wszInprocServer32);
1641 TRACE("Registry key: %s\n", debugstr_w(path));
1643 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key);
1644 if (res == ERROR_FILE_NOT_FOUND)
1645 return CLASS_E_CLASSNOTAVAILABLE;
1647 res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen);
1648 if(res != ERROR_SUCCESS)
1650 WARN("Class value cannot be found.\n");
1651 hr = CLASS_E_CLASSNOTAVAILABLE;
1652 goto cleanup;
1655 TRACE("classname (%s)\n", debugstr_w(classname));
1657 dwBufLen = MAX_PATH + 8;
1658 res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen);
1659 if(res == ERROR_SUCCESS)
1661 /* Strip file:/// */
1662 if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0)
1663 offset = strlenW(wszFileSlash);
1665 strcpyW(filename, codebase + offset);
1667 else
1669 WCHAR assemblyname[MAX_PATH + 8];
1671 hr = CLASS_E_CLASSNOTAVAILABLE;
1672 WARN("CodeBase value cannot be found, trying Assembly.\n");
1673 /* get the last subkey of InprocServer32 */
1674 res = RegQueryInfoKeyW(key, 0, 0, 0, &numKeys, 0, 0, 0, 0, 0, 0, 0);
1675 if (res != ERROR_SUCCESS || numKeys == 0)
1676 goto cleanup;
1677 numKeys--;
1678 keyLength = sizeof(subkeyName) / sizeof(WCHAR);
1679 res = RegEnumKeyExW(key, numKeys, subkeyName, &keyLength, 0, 0, 0, 0);
1680 if (res != ERROR_SUCCESS)
1681 goto cleanup;
1682 res = RegOpenKeyExW(key, subkeyName, 0, KEY_READ, &subkey);
1683 if (res != ERROR_SUCCESS)
1684 goto cleanup;
1685 dwBufLen = MAX_PATH + 8;
1686 res = RegGetValueW(subkey, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen);
1687 RegCloseKey(subkey);
1688 if (res != ERROR_SUCCESS)
1689 goto cleanup;
1691 hr = get_file_from_strongname(assemblyname, filename, MAX_PATH);
1692 if (FAILED(hr))
1695 * The registry doesn't have a CodeBase entry and it's not in the GAC.
1697 * Use the Assembly Key to retrieve the filename.
1698 * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null
1700 WCHAR *ns;
1702 WARN("Attempt to load from the application directory.\n");
1703 GetModuleFileNameW(NULL, filename, MAX_PATH);
1704 ns = strrchrW(filename, '\\');
1705 *(ns+1) = '\0';
1707 ns = strchrW(assemblyname, ',');
1708 *(ns) = '\0';
1709 strcatW(filename, assemblyname);
1710 *(ns) = '.';
1711 strcatW(filename, wszDLL);
1715 TRACE("filename (%s)\n", debugstr_w(filename));
1717 *ppObj = NULL;
1720 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1721 if (SUCCEEDED(hr))
1723 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1725 if (SUCCEEDED(hr))
1726 hr = RuntimeHost_GetDefaultDomain(host, NULL, &domain);
1728 if (SUCCEEDED(hr))
1730 MonoImage *image;
1731 MonoClass *klass;
1732 MonoObject *result;
1733 MonoDomain *prev_domain;
1734 IUnknown *unk = NULL;
1735 char *filenameA, *ns;
1736 char *classA;
1738 hr = CLASS_E_CLASSNOTAVAILABLE;
1740 prev_domain = domain_attach(domain);
1742 filenameA = WtoA(filename);
1743 assembly = mono_domain_assembly_open(domain, filenameA);
1744 HeapFree(GetProcessHeap(), 0, filenameA);
1745 if (!assembly)
1747 ERR("Cannot open assembly %s\n", filenameA);
1748 domain_restore(prev_domain);
1749 goto cleanup;
1752 image = mono_assembly_get_image(assembly);
1753 if (!image)
1755 ERR("Couldn't get assembly image\n");
1756 domain_restore(prev_domain);
1757 goto cleanup;
1760 classA = WtoA(classname);
1761 ns = strrchr(classA, '.');
1762 *ns = '\0';
1764 klass = mono_class_from_name(image, classA, ns+1);
1765 HeapFree(GetProcessHeap(), 0, classA);
1766 if (!klass)
1768 ERR("Couldn't get class from image\n");
1769 domain_restore(prev_domain);
1770 goto cleanup;
1774 * Use the default constructor for the .NET class.
1776 result = mono_object_new(domain, klass);
1777 mono_runtime_object_init(result);
1779 hr = RuntimeHost_GetIUnknownForObject(host, result, &unk);
1780 if (SUCCEEDED(hr))
1782 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj);
1784 IUnknown_Release(unk);
1786 else
1787 hr = CLASS_E_CLASSNOTAVAILABLE;
1789 domain_restore(prev_domain);
1791 else
1792 hr = CLASS_E_CLASSNOTAVAILABLE;
1794 else
1795 hr = CLASS_E_CLASSNOTAVAILABLE;
1797 cleanup:
1798 if(info)
1799 ICLRRuntimeInfo_Release(info);
1801 RegCloseKey(key);
1803 return hr;