riched20: Don't apply paragraph formatting until the end of paragraph.
[wine.git] / dlls / mscoree / corruntimehost.c
blob7fc6867c9c7ab92d5782c4841dc0014091bf6fee
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 HRESULT RuntimeHost_AddDefaultDomain(RuntimeHost *This, MonoDomain **result)
73 struct DomainEntry *entry;
74 HRESULT res=S_OK;
76 EnterCriticalSection(&This->lock);
78 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
79 if (!entry)
81 res = E_OUTOFMEMORY;
82 goto end;
85 /* FIXME: Use exe filename to name the domain? */
86 entry->domain = mono_jit_init_version("mscorlib.dll", "v4.0.30319");
88 if (!entry->domain)
90 HeapFree(GetProcessHeap(), 0, entry);
91 res = E_FAIL;
92 goto end;
95 is_mono_started = TRUE;
97 list_add_tail(&This->domains, &entry->entry);
99 *result = entry->domain;
101 end:
102 LeaveCriticalSection(&This->lock);
104 return res;
107 static HRESULT RuntimeHost_GetDefaultDomain(RuntimeHost *This, const WCHAR *config_path, MonoDomain **result)
109 WCHAR config_dir[MAX_PATH];
110 WCHAR base_dir[MAX_PATH];
111 char *base_dirA, *config_pathA, *slash;
112 HRESULT res=S_OK;
114 EnterCriticalSection(&This->lock);
116 if (This->default_domain) goto end;
118 res = RuntimeHost_AddDefaultDomain(This, &This->default_domain);
120 if (!config_path)
122 DWORD len = sizeof(config_dir)/sizeof(*config_dir);
124 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};
126 res = ICLRRuntimeInfo_GetRuntimeDirectory(&This->version->ICLRRuntimeInfo_iface,
127 config_dir, &len);
128 if (FAILED(res))
129 goto end;
131 lstrcatW(config_dir, machine_configW);
133 config_path = config_dir;
136 config_pathA = WtoA(config_path);
137 if (!config_pathA)
139 res = E_OUTOFMEMORY;
140 goto end;
143 GetModuleFileNameW(NULL, base_dir, sizeof(base_dir) / sizeof(*base_dir));
144 base_dirA = WtoA(base_dir);
145 if (!base_dirA)
147 HeapFree(GetProcessHeap(), 0, config_pathA);
148 res = E_OUTOFMEMORY;
149 goto end;
152 slash = strrchr(base_dirA, '\\');
153 if (slash)
154 *slash = 0;
156 TRACE("setting base_dir: %s, config_path: %s\n", base_dirA, config_pathA);
157 mono_domain_set_config(This->default_domain, base_dirA, config_pathA);
159 HeapFree(GetProcessHeap(), 0, config_pathA);
160 HeapFree(GetProcessHeap(), 0, base_dirA);
162 end:
163 *result = This->default_domain;
165 LeaveCriticalSection(&This->lock);
167 return res;
170 static void RuntimeHost_DeleteDomain(RuntimeHost *This, MonoDomain *domain)
172 struct DomainEntry *entry;
174 EnterCriticalSection(&This->lock);
176 LIST_FOR_EACH_ENTRY(entry, &This->domains, struct DomainEntry, entry)
178 if (entry->domain == domain)
180 list_remove(&entry->entry);
181 if (This->default_domain == domain)
182 This->default_domain = NULL;
183 HeapFree(GetProcessHeap(), 0, entry);
184 break;
188 LeaveCriticalSection(&This->lock);
191 static BOOL RuntimeHost_GetMethod(MonoDomain *domain, const char *assemblyname,
192 const char *namespace, const char *typename, const char *methodname, int arg_count,
193 MonoMethod **method)
195 MonoAssembly *assembly;
196 MonoImage *image;
197 MonoClass *klass;
199 assembly = mono_domain_assembly_open(domain, assemblyname);
200 if (!assembly)
202 ERR("Cannot load assembly %s\n", assemblyname);
203 return FALSE;
206 image = mono_assembly_get_image(assembly);
207 if (!image)
209 ERR("Couldn't get assembly image for %s\n", assemblyname);
210 return FALSE;
213 klass = mono_class_from_name(image, namespace, typename);
214 if (!klass)
216 ERR("Couldn't get class %s.%s from image\n", namespace, typename);
217 return FALSE;
220 *method = mono_class_get_method_from_name(klass, methodname, arg_count);
221 if (!*method)
223 ERR("Couldn't get method %s from class %s.%s\n", methodname, namespace, typename);
224 return FALSE;
227 return TRUE;
230 static HRESULT RuntimeHost_Invoke(RuntimeHost *This, MonoDomain *domain,
231 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
232 MonoObject *obj, void **args, int arg_count, MonoObject **result);
234 static HRESULT RuntimeHost_DoInvoke(RuntimeHost *This, MonoDomain *domain,
235 const char *methodname, MonoMethod *method, MonoObject *obj, void **args, MonoObject **result)
237 MonoObject *exc;
238 static const char *get_hresult = "get_HResult";
240 *result = mono_runtime_invoke(method, obj, args, &exc);
241 if (exc)
243 HRESULT hr;
244 MonoObject *hr_object;
246 if (methodname != get_hresult)
248 /* Map the exception to an HRESULT. */
249 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System", "Exception", get_hresult,
250 exc, NULL, 0, &hr_object);
251 if (SUCCEEDED(hr))
252 hr = *(HRESULT*)mono_object_unbox(hr_object);
253 if (SUCCEEDED(hr))
254 hr = E_FAIL;
256 else
257 hr = E_FAIL;
258 *result = NULL;
259 return hr;
262 return S_OK;
265 static HRESULT RuntimeHost_Invoke(RuntimeHost *This, MonoDomain *domain,
266 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
267 MonoObject *obj, void **args, int arg_count, MonoObject **result)
269 MonoMethod *method;
270 HRESULT hr;
272 *result = NULL;
274 mono_thread_attach(domain);
276 if (!RuntimeHost_GetMethod(domain, assemblyname, namespace, typename, methodname,
277 arg_count, &method))
279 return E_FAIL;
282 hr = RuntimeHost_DoInvoke(This, domain, methodname, method, obj, args, result);
283 if (FAILED(hr))
285 ERR("Method %s.%s:%s raised an exception, hr=%x\n", namespace, typename, methodname, hr);
288 return hr;
291 static HRESULT RuntimeHost_VirtualInvoke(RuntimeHost *This, MonoDomain *domain,
292 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
293 MonoObject *obj, void **args, int arg_count, MonoObject **result)
295 MonoMethod *method;
296 HRESULT hr;
298 *result = NULL;
300 if (!obj)
302 ERR("\"this\" object cannot be null\n");
303 return E_POINTER;
306 mono_thread_attach(domain);
308 if (!RuntimeHost_GetMethod(domain, assemblyname, namespace, typename, methodname,
309 arg_count, &method))
311 return E_FAIL;
314 method = mono_object_get_virtual_method(obj, method);
315 if (!method)
317 ERR("Object %p does not support method %s.%s:%s\n", obj, namespace, typename, methodname);
318 return E_FAIL;
321 hr = RuntimeHost_DoInvoke(This, domain, methodname, method, obj, args, result);
322 if (FAILED(hr))
324 ERR("Method %s.%s:%s raised an exception, hr=%x\n", namespace, typename, methodname, hr);
327 return hr;
330 static HRESULT RuntimeHost_GetObjectForIUnknown(RuntimeHost *This, MonoDomain *domain,
331 IUnknown *unk, MonoObject **obj)
333 HRESULT hr;
334 void *args[1];
335 MonoObject *result;
337 args[0] = &unk;
338 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System.Runtime.InteropServices", "Marshal", "GetObjectForIUnknown",
339 NULL, args, 1, &result);
341 if (SUCCEEDED(hr))
343 *obj = result;
345 return hr;
348 static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, const WCHAR *name, IUnknown *setup,
349 IUnknown *evidence, MonoDomain **result)
351 HRESULT res;
352 char *nameA;
353 MonoDomain *domain;
354 void *args[3];
355 MonoObject *new_domain, *id;
357 res = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
358 if (FAILED(res))
360 return res;
363 nameA = WtoA(name);
364 if (!nameA)
366 return E_OUTOFMEMORY;
369 args[0] = mono_string_new(domain, nameA);
370 HeapFree(GetProcessHeap(), 0, nameA);
372 if (!args[0])
374 return E_OUTOFMEMORY;
377 if (evidence)
379 res = RuntimeHost_GetObjectForIUnknown(This, domain, evidence, (MonoObject **)&args[1]);
380 if (FAILED(res))
382 return res;
385 else
387 args[1] = NULL;
390 if (setup)
392 res = RuntimeHost_GetObjectForIUnknown(This, domain, setup, (MonoObject **)&args[2]);
393 if (FAILED(res))
395 return res;
398 else
400 args[2] = NULL;
403 res = RuntimeHost_Invoke(This, domain, "mscorlib", "System", "AppDomain", "CreateDomain",
404 NULL, args, 3, &new_domain);
406 if (FAILED(res))
408 return res;
411 /* new_domain is not the AppDomain itself, but a transparent proxy.
412 * So, we'll retrieve its ID, and use that to get the real domain object.
413 * We can't do a regular invoke, because that will bypass the proxy.
414 * Instead, do a vcall.
417 res = RuntimeHost_VirtualInvoke(This, domain, "mscorlib", "System", "AppDomain", "get_Id",
418 new_domain, NULL, 0, &id);
420 if (FAILED(res))
422 return res;
425 TRACE("returning domain id %d\n", *(int *)mono_object_unbox(id));
427 *result = mono_domain_get_by_id(*(int *)mono_object_unbox(id));
429 return S_OK;
432 static HRESULT RuntimeHost_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *domain, IUnknown **punk)
434 HRESULT hr;
435 MonoObject *appdomain_object;
436 IUnknown *unk;
438 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System", "AppDomain", "get_CurrentDomain",
439 NULL, NULL, 0, &appdomain_object);
441 if (SUCCEEDED(hr))
442 hr = RuntimeHost_GetIUnknownForObject(This, appdomain_object, &unk);
444 if (SUCCEEDED(hr))
446 hr = IUnknown_QueryInterface(unk, &IID__AppDomain, (void**)punk);
448 IUnknown_Release(unk);
451 return hr;
454 void RuntimeHost_ExitProcess(RuntimeHost *This, INT exitcode)
456 HRESULT hr;
457 void *args[2];
458 MonoDomain *domain;
459 MonoObject *dummy;
461 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
462 if (FAILED(hr))
464 ERR("Cannot get domain, hr=%x\n", hr);
465 return;
468 args[0] = &exitcode;
469 args[1] = NULL;
470 RuntimeHost_Invoke(This, domain, "mscorlib", "System", "Environment", "Exit",
471 NULL, args, 1, &dummy);
473 ERR("Process should have exited\n");
476 static inline RuntimeHost *impl_from_ICLRRuntimeHost( ICLRRuntimeHost *iface )
478 return CONTAINING_RECORD(iface, RuntimeHost, ICLRRuntimeHost_iface);
481 static inline RuntimeHost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
483 return CONTAINING_RECORD(iface, RuntimeHost, ICorRuntimeHost_iface);
486 /*** IUnknown methods ***/
487 static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
488 REFIID riid,
489 void **ppvObject)
491 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
492 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
494 if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) ||
495 IsEqualGUID( riid, &IID_IUnknown ) )
497 *ppvObject = iface;
499 else
501 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
502 return E_NOINTERFACE;
505 ICorRuntimeHost_AddRef( iface );
507 return S_OK;
510 static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface)
512 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
514 return InterlockedIncrement( &This->ref );
517 static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface)
519 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
520 ULONG ref;
522 ref = InterlockedDecrement( &This->ref );
524 return ref;
527 /*** ICorRuntimeHost methods ***/
528 static HRESULT WINAPI corruntimehost_CreateLogicalThreadState(
529 ICorRuntimeHost* iface)
531 FIXME("stub %p\n", iface);
532 return E_NOTIMPL;
535 static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState(
536 ICorRuntimeHost* iface)
538 FIXME("stub %p\n", iface);
539 return E_NOTIMPL;
542 static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState(
543 ICorRuntimeHost* iface,
544 DWORD *fiberCookie)
546 FIXME("stub %p\n", iface);
547 return E_NOTIMPL;
550 static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState(
551 ICorRuntimeHost* iface,
552 DWORD **fiberCookie)
554 FIXME("stub %p\n", iface);
555 return E_NOTIMPL;
558 static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread(
559 ICorRuntimeHost* iface,
560 DWORD *pCount)
562 FIXME("stub %p\n", iface);
563 return E_NOTIMPL;
566 static HRESULT WINAPI corruntimehost_MapFile(
567 ICorRuntimeHost* iface,
568 HANDLE hFile,
569 HMODULE *mapAddress)
571 FIXME("stub %p\n", iface);
572 return E_NOTIMPL;
575 static HRESULT WINAPI corruntimehost_GetConfiguration(
576 ICorRuntimeHost* iface,
577 ICorConfiguration **pConfiguration)
579 FIXME("stub %p\n", iface);
580 return E_NOTIMPL;
583 static HRESULT WINAPI corruntimehost_Start(
584 ICorRuntimeHost* iface)
586 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
587 MonoDomain *dummy;
589 TRACE("%p\n", This);
591 return RuntimeHost_GetDefaultDomain(This, NULL, &dummy);
594 static HRESULT WINAPI corruntimehost_Stop(
595 ICorRuntimeHost* iface)
597 FIXME("stub %p\n", iface);
598 return E_NOTIMPL;
601 static HRESULT WINAPI corruntimehost_CreateDomain(
602 ICorRuntimeHost* iface,
603 LPCWSTR friendlyName,
604 IUnknown *identityArray,
605 IUnknown **appDomain)
607 return ICorRuntimeHost_CreateDomainEx(iface, friendlyName, NULL, NULL, appDomain);
610 static HRESULT WINAPI corruntimehost_GetDefaultDomain(
611 ICorRuntimeHost* iface,
612 IUnknown **pAppDomain)
614 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
615 HRESULT hr;
616 MonoDomain *domain;
618 TRACE("(%p)\n", iface);
620 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
622 if (SUCCEEDED(hr))
624 hr = RuntimeHost_GetIUnknownForDomain(This, domain, pAppDomain);
627 return hr;
630 static HRESULT WINAPI corruntimehost_EnumDomains(
631 ICorRuntimeHost* iface,
632 HDOMAINENUM *hEnum)
634 FIXME("stub %p\n", iface);
635 return E_NOTIMPL;
638 static HRESULT WINAPI corruntimehost_NextDomain(
639 ICorRuntimeHost* iface,
640 HDOMAINENUM hEnum,
641 IUnknown **appDomain)
643 FIXME("stub %p\n", iface);
644 return E_NOTIMPL;
647 static HRESULT WINAPI corruntimehost_CloseEnum(
648 ICorRuntimeHost* iface,
649 HDOMAINENUM hEnum)
651 FIXME("stub %p\n", iface);
652 return E_NOTIMPL;
655 static HRESULT WINAPI corruntimehost_CreateDomainEx(
656 ICorRuntimeHost* iface,
657 LPCWSTR friendlyName,
658 IUnknown *setup,
659 IUnknown *evidence,
660 IUnknown **appDomain)
662 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
663 HRESULT hr;
664 MonoDomain *domain;
666 if (!friendlyName || !appDomain)
668 return E_POINTER;
670 if (!is_mono_started)
672 return E_FAIL;
675 TRACE("(%p)\n", iface);
677 hr = RuntimeHost_AddDomain(This, friendlyName, setup, evidence, &domain);
679 if (SUCCEEDED(hr))
681 hr = RuntimeHost_GetIUnknownForDomain(This, domain, appDomain);
684 return hr;
687 static HRESULT WINAPI corruntimehost_CreateDomainSetup(
688 ICorRuntimeHost* iface,
689 IUnknown **appDomainSetup)
691 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
692 HRESULT hr;
693 MonoDomain *domain;
694 MonoObject *obj;
695 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};
697 TRACE("(%p)\n", iface);
699 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
701 if (SUCCEEDED(hr))
702 hr = RuntimeHost_CreateManagedInstance(This, classnameW, domain, &obj);
704 if (SUCCEEDED(hr))
705 hr = RuntimeHost_GetIUnknownForObject(This, obj, appDomainSetup);
707 return hr;
710 static HRESULT WINAPI corruntimehost_CreateEvidence(
711 ICorRuntimeHost* iface,
712 IUnknown **evidence)
714 FIXME("stub %p\n", iface);
715 return E_NOTIMPL;
718 static HRESULT WINAPI corruntimehost_UnloadDomain(
719 ICorRuntimeHost* iface,
720 IUnknown *appDomain)
722 FIXME("stub %p\n", iface);
723 return E_NOTIMPL;
726 static HRESULT WINAPI corruntimehost_CurrentDomain(
727 ICorRuntimeHost* iface,
728 IUnknown **appDomain)
730 FIXME("stub %p\n", iface);
731 return E_NOTIMPL;
734 static const struct ICorRuntimeHostVtbl corruntimehost_vtbl =
736 corruntimehost_QueryInterface,
737 corruntimehost_AddRef,
738 corruntimehost_Release,
739 corruntimehost_CreateLogicalThreadState,
740 corruntimehost_DeleteLogicalThreadState,
741 corruntimehost_SwitchInLogicalThreadState,
742 corruntimehost_SwitchOutLogicalThreadState,
743 corruntimehost_LocksHeldByLogicalThread,
744 corruntimehost_MapFile,
745 corruntimehost_GetConfiguration,
746 corruntimehost_Start,
747 corruntimehost_Stop,
748 corruntimehost_CreateDomain,
749 corruntimehost_GetDefaultDomain,
750 corruntimehost_EnumDomains,
751 corruntimehost_NextDomain,
752 corruntimehost_CloseEnum,
753 corruntimehost_CreateDomainEx,
754 corruntimehost_CreateDomainSetup,
755 corruntimehost_CreateEvidence,
756 corruntimehost_UnloadDomain,
757 corruntimehost_CurrentDomain
760 static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface,
761 REFIID riid,
762 void **ppvObject)
764 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
765 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
767 if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) ||
768 IsEqualGUID( riid, &IID_IUnknown ) )
770 *ppvObject = iface;
772 else
774 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
775 return E_NOINTERFACE;
778 ICLRRuntimeHost_AddRef( iface );
780 return S_OK;
783 static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface)
785 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
786 return ICorRuntimeHost_AddRef(&This->ICorRuntimeHost_iface);
789 static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface)
791 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
792 return ICorRuntimeHost_Release(&This->ICorRuntimeHost_iface);
795 static HRESULT WINAPI CLRRuntimeHost_Start(ICLRRuntimeHost* iface)
797 FIXME("(%p)\n", iface);
798 return E_NOTIMPL;
801 static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
803 FIXME("(%p)\n", iface);
804 return E_NOTIMPL;
807 static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
808 IHostControl *pHostControl)
810 FIXME("(%p,%p)\n", iface, pHostControl);
811 return E_NOTIMPL;
814 static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
815 ICLRControl **pCLRControl)
817 FIXME("(%p,%p)\n", iface, pCLRControl);
818 return E_NOTIMPL;
821 static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
822 DWORD dwAppDomainId, BOOL fWaitUntilDone)
824 FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
825 return E_NOTIMPL;
828 static HRESULT WINAPI CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost* iface,
829 DWORD dwAppDomainId, FExecuteInAppDomainCallback pCallback, void *cookie)
831 FIXME("(%p,%u,%p,%p)\n", iface, dwAppDomainId, pCallback, cookie);
832 return E_NOTIMPL;
835 static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
836 DWORD *pdwAppDomainId)
838 FIXME("(%p,%p)\n", iface, pdwAppDomainId);
839 return E_NOTIMPL;
842 static HRESULT WINAPI CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost* iface,
843 LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR *ppwzManifestPaths,
844 DWORD dwActivationData, LPCWSTR *ppwzActivationData, int *pReturnValue)
846 FIXME("(%p,%s,%u,%u)\n", iface, debugstr_w(pwzAppFullName), dwManifestPaths, dwActivationData);
847 return E_NOTIMPL;
850 static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* iface,
851 LPCWSTR pwzAssemblyPath, LPCWSTR pwzTypeName, LPCWSTR pwzMethodName,
852 LPCWSTR pwzArgument, DWORD *pReturnValue)
854 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
855 HRESULT hr;
856 MonoDomain *domain;
857 MonoObject *result;
858 MonoString *str;
859 char *filenameA = NULL, *classA = NULL, *methodA = NULL;
860 char *argsA = NULL, *ns;
862 TRACE("(%p,%s,%s,%s,%s)\n", iface, debugstr_w(pwzAssemblyPath),
863 debugstr_w(pwzTypeName), debugstr_w(pwzMethodName), debugstr_w(pwzArgument));
865 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
867 if (SUCCEEDED(hr))
869 mono_thread_attach(domain);
871 filenameA = WtoA(pwzAssemblyPath);
872 if (!filenameA) hr = E_OUTOFMEMORY;
875 if (SUCCEEDED(hr))
877 classA = WtoA(pwzTypeName);
878 if (!classA) hr = E_OUTOFMEMORY;
881 if (SUCCEEDED(hr))
883 ns = strrchr(classA, '.');
884 if (ns)
885 *ns = '\0';
886 else
887 hr = E_INVALIDARG;
890 if (SUCCEEDED(hr))
892 methodA = WtoA(pwzMethodName);
893 if (!methodA) hr = E_OUTOFMEMORY;
896 /* The .NET function we are calling has the following declaration
897 * public static int functionName(String param)
899 if (SUCCEEDED(hr))
901 argsA = WtoA(pwzArgument);
902 if (!argsA) hr = E_OUTOFMEMORY;
905 if (SUCCEEDED(hr))
907 str = mono_string_new(domain, argsA);
908 if (!str) hr = E_OUTOFMEMORY;
911 if (SUCCEEDED(hr))
913 hr = RuntimeHost_Invoke(This, domain, filenameA, classA, ns+1, methodA,
914 NULL, (void**)&str, 1, &result);
917 if (SUCCEEDED(hr))
918 *pReturnValue = *(DWORD*)mono_object_unbox(result);
920 HeapFree(GetProcessHeap(), 0, filenameA);
921 HeapFree(GetProcessHeap(), 0, classA);
922 HeapFree(GetProcessHeap(), 0, argsA);
923 HeapFree(GetProcessHeap(), 0, methodA);
925 return hr;
928 static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
930 CLRRuntimeHost_QueryInterface,
931 CLRRuntimeHost_AddRef,
932 CLRRuntimeHost_Release,
933 CLRRuntimeHost_Start,
934 CLRRuntimeHost_Stop,
935 CLRRuntimeHost_SetHostControl,
936 CLRRuntimeHost_GetCLRControl,
937 CLRRuntimeHost_UnloadAppDomain,
938 CLRRuntimeHost_ExecuteInAppDomain,
939 CLRRuntimeHost_GetCurrentAppDomainId,
940 CLRRuntimeHost_ExecuteApplication,
941 CLRRuntimeHost_ExecuteInDefaultAppDomain
944 /* Create an instance of a type given its name, by calling its constructor with
945 * no arguments. Note that result MUST be in the stack, or the garbage
946 * collector may free it prematurely. */
947 HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
948 MonoDomain *domain, MonoObject **result)
950 HRESULT hr=S_OK;
951 char *nameA=NULL;
952 MonoType *type;
953 MonoClass *klass;
954 MonoObject *obj;
956 if (!domain)
957 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
959 if (SUCCEEDED(hr))
961 nameA = WtoA(name);
962 if (!nameA)
963 hr = E_OUTOFMEMORY;
966 if (SUCCEEDED(hr))
968 mono_thread_attach(domain);
970 type = mono_reflection_type_from_name(nameA, NULL);
971 if (!type)
973 ERR("Cannot find type %s\n", debugstr_w(name));
974 hr = E_FAIL;
978 if (SUCCEEDED(hr))
980 klass = mono_class_from_mono_type(type);
981 if (!klass)
983 ERR("Cannot convert type %s to a class\n", debugstr_w(name));
984 hr = E_FAIL;
988 if (SUCCEEDED(hr))
990 obj = mono_object_new(domain, klass);
991 if (!obj)
993 ERR("Cannot allocate object of type %s\n", debugstr_w(name));
994 hr = E_FAIL;
998 if (SUCCEEDED(hr))
1000 /* FIXME: Detect exceptions from the constructor? */
1001 mono_runtime_object_init(obj);
1002 *result = obj;
1005 HeapFree(GetProcessHeap(), 0, nameA);
1007 return hr;
1010 /* Get an IUnknown pointer for a Mono object.
1012 * This is just a "light" wrapper around
1013 * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
1015 * NOTE: The IUnknown* is created with a reference to the object.
1016 * Until they have a reference, objects must be in the stack to prevent the
1017 * garbage collector from freeing them.
1019 * mono_thread_attach must have already been called for this thread. */
1020 HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj,
1021 IUnknown **ppUnk)
1023 MonoDomain *domain;
1024 MonoObject *result;
1025 HRESULT hr;
1027 domain = mono_object_get_domain(obj);
1029 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System.Runtime.InteropServices", "Marshal", "GetIUnknownForObject",
1030 NULL, (void**)&obj, 1, &result);
1032 if (SUCCEEDED(hr))
1033 *ppUnk = *(IUnknown**)mono_object_unbox(result);
1034 else
1035 *ppUnk = NULL;
1037 return hr;
1040 static void get_utf8_args(int *argc, char ***argv)
1042 WCHAR **argvw;
1043 int size=0, i;
1044 char *current_arg;
1046 argvw = CommandLineToArgvW(GetCommandLineW(), argc);
1048 for (i=0; i<*argc; i++)
1050 size += sizeof(char*);
1051 size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
1053 size += sizeof(char*);
1055 *argv = HeapAlloc(GetProcessHeap(), 0, size);
1056 current_arg = (char*)(*argv + *argc + 1);
1058 for (i=0; i<*argc; i++)
1060 (*argv)[i] = current_arg;
1061 current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
1064 (*argv)[*argc] = NULL;
1066 HeapFree(GetProcessHeap(), 0, argvw);
1069 #if __i386__
1071 # define CAN_FIXUP_VTABLE 1
1073 #include "pshpack1.h"
1075 struct vtable_fixup_thunk
1077 /* push %ecx */
1078 BYTE i7;
1079 /* sub $0x4,%esp */
1080 BYTE i1[3];
1081 /* mov fixup,(%esp) */
1082 BYTE i2[3];
1083 struct dll_fixup *fixup;
1084 /* mov function,%eax */
1085 BYTE i3;
1086 void (CDECL *function)(struct dll_fixup *);
1087 /* call *%eax */
1088 BYTE i4[2];
1089 /* pop %eax */
1090 BYTE i5;
1091 /* pop %ecx */
1092 BYTE i8;
1093 /* jmp *vtable_entry */
1094 BYTE i6[2];
1095 void *vtable_entry;
1098 static const struct vtable_fixup_thunk thunk_template = {
1099 0x51,
1100 {0x83,0xec,0x04},
1101 {0xc7,0x04,0x24},
1102 NULL,
1103 0xb8,
1104 NULL,
1105 {0xff,0xd0},
1106 0x58,
1107 0x59,
1108 {0xff,0x25},
1109 NULL
1112 #include "poppack.h"
1114 #elif __x86_64__ /* !__i386__ */
1116 # define CAN_FIXUP_VTABLE 1
1118 #include "pshpack1.h"
1120 struct vtable_fixup_thunk
1122 /* push %rbp;
1123 mov %rsp, %rbp
1124 sub $0x80, %rsp ; 0x8*4 + 0x10*4 + 0x20
1126 BYTE i1[11];
1128 mov %rcx, 0x60(%rsp); mov %rdx, 0x68(%rsp); mov %r8, 0x70(%rsp); mov %r9, 0x78(%rsp);
1129 movaps %xmm0,0x20(%rsp); ...; movaps %xmm3,0x50(%esp)
1131 BYTE i2[40];
1132 /* mov function,%rax */
1133 BYTE i3[2];
1134 void (CDECL *function)(struct dll_fixup *);
1135 /* mov fixup,%rcx */
1136 BYTE i4[2];
1137 struct dll_fixup *fixup;
1138 /* call *%rax */
1139 BYTE i5[2];
1141 mov 0x60(%rsp),%rcx; mov 0x68(%rsp),%rdx; mov 0x70(%rsp),%r8; mov 0x78(%rsp),%r9;
1142 movaps 0x20(%rsp),xmm0; ...; movaps 0x50(%esp),xmm3
1144 BYTE i6[40];
1145 /* mov %rbp, %rsp
1146 pop %rbp
1148 BYTE i7[4];
1149 /* mov vtable_entry, %rax */
1150 BYTE i8[2];
1151 void *vtable_entry;
1152 /* mov [%rax],%rax
1153 jmp %rax */
1154 BYTE i9[5];
1157 static const struct vtable_fixup_thunk thunk_template = {
1158 {0x55,0x48,0x89,0xE5, 0x48,0x81,0xEC,0x80,0x00,0x00,0x00},
1159 {0x48,0x89,0x4C,0x24,0x60, 0x48,0x89,0x54,0x24,0x68,
1160 0x4C,0x89,0x44,0x24,0x70, 0x4C,0x89,0x4C,0x24,0x78,
1161 0x0F,0x29,0x44,0x24,0x20, 0x0F,0x29,0x4C,0x24,0x30,
1162 0x0F,0x29,0x54,0x24,0x40, 0x0F,0x29,0x5C,0x24,0x50,
1164 {0x48,0xB8},
1165 NULL,
1166 {0x48,0xB9},
1167 NULL,
1168 {0xFF,0xD0},
1169 {0x48,0x8B,0x4C,0x24,0x60, 0x48,0x8B,0x54,0x24,0x68,
1170 0x4C,0x8B,0x44,0x24,0x70, 0x4C,0x8B,0x4C,0x24,0x78,
1171 0x0F,0x28,0x44,0x24,0x20, 0x0F,0x28,0x4C,0x24,0x30,
1172 0x0F,0x28,0x54,0x24,0x40, 0x0F,0x28,0x5C,0x24,0x50,
1174 {0x48,0x89,0xEC, 0x5D},
1175 {0x48,0xB8},
1176 NULL,
1177 {0x48,0x8B,0x00,0xFF,0xE0}
1180 #include "poppack.h"
1182 #else /* !__i386__ && !__x86_64__ */
1184 # define CAN_FIXUP_VTABLE 0
1186 struct vtable_fixup_thunk
1188 struct dll_fixup *fixup;
1189 void (CDECL *function)(struct dll_fixup *fixup);
1190 void *vtable_entry;
1193 static const struct vtable_fixup_thunk thunk_template = {0};
1195 #endif
1197 static void CDECL ReallyFixupVTable(struct dll_fixup *fixup)
1199 HRESULT hr=S_OK;
1200 WCHAR filename[MAX_PATH];
1201 ICLRRuntimeInfo *info=NULL;
1202 RuntimeHost *host;
1203 char *filenameA;
1204 MonoImage *image=NULL;
1205 MonoAssembly *assembly=NULL;
1206 MonoImageOpenStatus status=0;
1207 MonoDomain *domain;
1209 if (fixup->done) return;
1211 /* It's possible we'll have two threads doing this at once. This is
1212 * considered preferable to the potential deadlock if we use a mutex. */
1214 GetModuleFileNameW(fixup->dll, filename, MAX_PATH);
1216 TRACE("%p,%p,%s\n", fixup, fixup->dll, debugstr_w(filename));
1218 filenameA = WtoA(filename);
1219 if (!filenameA)
1220 hr = E_OUTOFMEMORY;
1222 if (SUCCEEDED(hr))
1223 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1225 if (SUCCEEDED(hr))
1226 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1228 if (SUCCEEDED(hr))
1229 hr = RuntimeHost_GetDefaultDomain(host, NULL, &domain);
1231 if (SUCCEEDED(hr))
1233 mono_thread_attach(domain);
1235 assembly = mono_assembly_open(filenameA, &status);
1238 if (assembly)
1240 int i;
1242 /* Mono needs an image that belongs to an assembly. */
1243 image = mono_assembly_get_image(assembly);
1245 #if __x86_64__
1246 if (fixup->fixup->type & COR_VTABLE_64BIT)
1247 #else
1248 if (fixup->fixup->type & COR_VTABLE_32BIT)
1249 #endif
1251 void **vtable = fixup->vtable;
1252 ULONG_PTR *tokens = fixup->tokens;
1253 for (i=0; i<fixup->fixup->count; i++)
1255 TRACE("%#lx\n", tokens[i]);
1256 vtable[i] = mono_marshal_get_vtfixup_ftnptr(
1257 image, tokens[i], fixup->fixup->type);
1261 fixup->done = TRUE;
1264 if (info != NULL)
1265 ICLRRuntimeInfo_Release(info);
1267 HeapFree(GetProcessHeap(), 0, filenameA);
1269 if (!fixup->done)
1271 ERR("unable to fixup vtable, hr=%x, status=%d\n", hr, status);
1272 /* If we returned now, we'd get an infinite loop. */
1273 assert(0);
1277 static void FixupVTableEntry(HMODULE hmodule, VTableFixup *vtable_fixup)
1279 /* We can't actually generate code for the functions without loading mono,
1280 * and loading mono inside DllMain is a terrible idea. So we make thunks
1281 * that call ReallyFixupVTable, which will load the runtime and fill in the
1282 * vtable, then do an indirect jump using the (now filled in) vtable. Note
1283 * that we have to keep the thunks around forever, as one of them may get
1284 * called while we're filling in the table, and we can never be sure all
1285 * threads are clear. */
1286 struct dll_fixup *fixup;
1288 fixup = HeapAlloc(GetProcessHeap(), 0, sizeof(*fixup));
1290 fixup->dll = hmodule;
1291 fixup->thunk_code = HeapAlloc(dll_fixup_heap, 0, sizeof(struct vtable_fixup_thunk) * vtable_fixup->count);
1292 fixup->fixup = vtable_fixup;
1293 fixup->vtable = (BYTE*)hmodule + vtable_fixup->rva;
1294 fixup->done = FALSE;
1296 TRACE("vtable_fixup->type=0x%x\n",vtable_fixup->type);
1297 #if __x86_64__
1298 if (vtable_fixup->type & COR_VTABLE_64BIT)
1299 #else
1300 if (vtable_fixup->type & COR_VTABLE_32BIT)
1301 #endif
1303 void **vtable = fixup->vtable;
1304 ULONG_PTR *tokens;
1305 int i;
1306 struct vtable_fixup_thunk *thunks = fixup->thunk_code;
1308 tokens = fixup->tokens = HeapAlloc(GetProcessHeap(), 0, sizeof(*tokens) * vtable_fixup->count);
1309 memcpy(tokens, vtable, sizeof(*tokens) * vtable_fixup->count);
1310 for (i=0; i<vtable_fixup->count; i++)
1312 thunks[i] = thunk_template;
1313 thunks[i].fixup = fixup;
1314 thunks[i].function = ReallyFixupVTable;
1315 thunks[i].vtable_entry = &vtable[i];
1316 vtable[i] = &thunks[i];
1319 else
1321 ERR("unsupported vtable fixup flags %x\n", vtable_fixup->type);
1322 HeapFree(dll_fixup_heap, 0, fixup->thunk_code);
1323 HeapFree(GetProcessHeap(), 0, fixup);
1324 return;
1327 list_add_tail(&dll_fixups, &fixup->entry);
1330 static void FixupVTable_Assembly(HMODULE hmodule, ASSEMBLY *assembly)
1332 VTableFixup *vtable_fixups;
1333 ULONG vtable_fixup_count, i;
1335 assembly_get_vtable_fixups(assembly, &vtable_fixups, &vtable_fixup_count);
1336 if (CAN_FIXUP_VTABLE)
1337 for (i=0; i<vtable_fixup_count; i++)
1338 FixupVTableEntry(hmodule, &vtable_fixups[i]);
1339 else if (vtable_fixup_count)
1340 FIXME("cannot fixup vtable; expect a crash\n");
1343 static void FixupVTable(HMODULE hmodule)
1345 ASSEMBLY *assembly;
1346 HRESULT hr;
1348 hr = assembly_from_hmodule(&assembly, hmodule);
1349 if (SUCCEEDED(hr))
1351 FixupVTable_Assembly(hmodule, assembly);
1352 assembly_release(assembly);
1354 else
1355 ERR("failed to read CLR headers, hr=%x\n", hr);
1358 __int32 WINAPI _CorExeMain(void)
1360 int exit_code;
1361 int argc;
1362 char **argv;
1363 MonoDomain *domain=NULL;
1364 MonoImage *image;
1365 MonoImageOpenStatus status;
1366 MonoAssembly *assembly=NULL;
1367 WCHAR filename[MAX_PATH];
1368 char *filenameA;
1369 ICLRRuntimeInfo *info;
1370 RuntimeHost *host;
1371 HRESULT hr;
1372 int i;
1374 get_utf8_args(&argc, &argv);
1376 GetModuleFileNameW(NULL, filename, MAX_PATH);
1378 TRACE("%s", debugstr_w(filename));
1379 for (i=0; i<argc; i++)
1380 TRACE(" %s", debugstr_a(argv[i]));
1381 TRACE("\n");
1383 filenameA = WtoA(filename);
1384 if (!filenameA)
1385 return -1;
1387 FixupVTable(GetModuleHandleW(NULL));
1389 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1391 if (SUCCEEDED(hr))
1393 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1395 if (SUCCEEDED(hr))
1397 WCHAR config_file[MAX_PATH];
1398 static const WCHAR dotconfig[] = {'.','c','o','n','f','i','g',0};
1400 strcpyW(config_file, filename);
1401 strcatW(config_file, dotconfig);
1403 hr = RuntimeHost_GetDefaultDomain(host, config_file, &domain);
1406 if (SUCCEEDED(hr))
1408 image = mono_image_open_from_module_handle(GetModuleHandleW(NULL),
1409 filenameA, 1, &status);
1411 if (image)
1412 assembly = mono_assembly_load_from(image, filenameA, &status);
1414 if (assembly)
1416 mono_trace_set_assembly(assembly);
1418 exit_code = mono_jit_exec(domain, assembly, argc, argv);
1420 else
1422 ERR("couldn't load %s, status=%d\n", debugstr_w(filename), status);
1423 exit_code = -1;
1426 RuntimeHost_DeleteDomain(host, domain);
1428 else
1429 exit_code = -1;
1431 ICLRRuntimeInfo_Release(info);
1433 else
1434 exit_code = -1;
1436 HeapFree(GetProcessHeap(), 0, argv);
1438 if (domain)
1440 mono_thread_manage();
1441 mono_runtime_quit();
1444 return exit_code;
1447 BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1449 ASSEMBLY *assembly=NULL;
1450 HRESULT hr;
1452 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1454 hr = assembly_from_hmodule(&assembly, hinstDLL);
1455 if (SUCCEEDED(hr))
1457 NativeEntryPointFunc NativeEntryPoint=NULL;
1459 assembly_get_native_entrypoint(assembly, &NativeEntryPoint);
1460 if (fdwReason == DLL_PROCESS_ATTACH)
1462 if (!NativeEntryPoint)
1463 DisableThreadLibraryCalls(hinstDLL);
1464 FixupVTable_Assembly(hinstDLL,assembly);
1466 assembly_release(assembly);
1467 /* FIXME: clean up the vtables on DLL_PROCESS_DETACH */
1468 if (NativeEntryPoint)
1469 return NativeEntryPoint(hinstDLL, fdwReason, lpvReserved);
1471 else
1472 ERR("failed to read CLR headers, hr=%x\n", hr);
1474 return TRUE;
1477 /* called from DLL_PROCESS_ATTACH */
1478 void runtimehost_init(void)
1480 dll_fixup_heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
1481 list_init(&dll_fixups);
1484 /* called from DLL_PROCESS_DETACH */
1485 void runtimehost_uninit(void)
1487 struct dll_fixup *fixup, *fixup2;
1489 HeapDestroy(dll_fixup_heap);
1490 LIST_FOR_EACH_ENTRY_SAFE(fixup, fixup2, &dll_fixups, struct dll_fixup, entry)
1492 HeapFree(GetProcessHeap(), 0, fixup->tokens);
1493 HeapFree(GetProcessHeap(), 0, fixup);
1497 HRESULT RuntimeHost_Construct(CLRRuntimeInfo *runtime_version, RuntimeHost** result)
1499 RuntimeHost *This;
1501 This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1502 if ( !This )
1503 return E_OUTOFMEMORY;
1505 This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
1506 This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
1508 This->ref = 1;
1509 This->version = runtime_version;
1510 list_init(&This->domains);
1511 This->default_domain = NULL;
1512 InitializeCriticalSection(&This->lock);
1513 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
1515 *result = This;
1517 return S_OK;
1520 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
1522 IUnknown *unk;
1523 HRESULT hr;
1525 if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
1527 unk = (IUnknown*)&This->ICorRuntimeHost_iface;
1528 IUnknown_AddRef(unk);
1530 else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
1532 unk = (IUnknown*)&This->ICLRRuntimeHost_iface;
1533 IUnknown_AddRef(unk);
1535 else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
1536 IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
1538 hr = MetaDataDispenser_CreateInstance(&unk);
1539 if (FAILED(hr))
1540 return hr;
1542 else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
1544 hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
1545 if (FAILED(hr))
1546 return hr;
1548 else
1549 unk = NULL;
1551 if (unk)
1553 hr = IUnknown_QueryInterface(unk, riid, ppv);
1555 IUnknown_Release(unk);
1557 return hr;
1559 else
1560 FIXME("not implemented for class %s\n", debugstr_guid(clsid));
1562 return CLASS_E_CLASSNOTAVAILABLE;
1565 #define CHARS_IN_GUID 39
1566 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
1568 HRESULT create_monodata(REFIID riid, LPVOID *ppObj )
1570 static const WCHAR wszAssembly[] = {'A','s','s','e','m','b','l','y',0};
1571 static const WCHAR wszCodebase[] = {'C','o','d','e','B','a','s','e',0};
1572 static const WCHAR wszClass[] = {'C','l','a','s','s',0};
1573 static const WCHAR wszFileSlash[] = {'f','i','l','e',':','/','/','/',0};
1574 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1575 static const WCHAR wszInprocServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1576 static const WCHAR wszDLL[] = {'.','d','l','l',0};
1577 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) + ARRAYSIZE(wszInprocServer32) - 1];
1578 MonoDomain *domain;
1579 MonoAssembly *assembly;
1580 ICLRRuntimeInfo *info = NULL;
1581 RuntimeHost *host;
1582 HRESULT hr;
1583 HKEY key, subkey;
1584 LONG res;
1585 int offset = 0;
1586 DWORD numKeys, keyLength;
1587 WCHAR codebase[MAX_PATH + 8];
1588 WCHAR classname[350], subkeyName[256];
1589 WCHAR filename[MAX_PATH];
1591 DWORD dwBufLen = 350;
1593 lstrcpyW(path, wszCLSIDSlash);
1594 StringFromGUID2(riid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
1595 lstrcatW(path, wszInprocServer32);
1597 TRACE("Registry key: %s\n", debugstr_w(path));
1599 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key);
1600 if (res == ERROR_FILE_NOT_FOUND)
1601 return CLASS_E_CLASSNOTAVAILABLE;
1603 res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen);
1604 if(res != ERROR_SUCCESS)
1606 WARN("Class value cannot be found.\n");
1607 hr = CLASS_E_CLASSNOTAVAILABLE;
1608 goto cleanup;
1611 TRACE("classname (%s)\n", debugstr_w(classname));
1613 dwBufLen = MAX_PATH + 8;
1614 res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen);
1615 if(res == ERROR_SUCCESS)
1617 /* Strip file:/// */
1618 if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0)
1619 offset = strlenW(wszFileSlash);
1621 strcpyW(filename, codebase + offset);
1623 else
1625 WCHAR assemblyname[MAX_PATH + 8];
1627 hr = CLASS_E_CLASSNOTAVAILABLE;
1628 WARN("CodeBase value cannot be found, trying Assembly.\n");
1629 /* get the last subkey of InprocServer32 */
1630 res = RegQueryInfoKeyW(key, 0, 0, 0, &numKeys, 0, 0, 0, 0, 0, 0, 0);
1631 if (res != ERROR_SUCCESS || numKeys == 0)
1632 goto cleanup;
1633 numKeys--;
1634 keyLength = sizeof(subkeyName) / sizeof(WCHAR);
1635 res = RegEnumKeyExW(key, numKeys, subkeyName, &keyLength, 0, 0, 0, 0);
1636 if (res != ERROR_SUCCESS)
1637 goto cleanup;
1638 res = RegOpenKeyExW(key, subkeyName, 0, KEY_READ, &subkey);
1639 if (res != ERROR_SUCCESS)
1640 goto cleanup;
1641 dwBufLen = MAX_PATH + 8;
1642 res = RegGetValueW(subkey, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen);
1643 RegCloseKey(subkey);
1644 if (res != ERROR_SUCCESS)
1645 goto cleanup;
1647 hr = get_file_from_strongname(assemblyname, filename, MAX_PATH);
1648 if (FAILED(hr))
1651 * The registry doesn't have a CodeBase entry and it's not in the GAC.
1653 * Use the Assembly Key to retrieve the filename.
1654 * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null
1656 WCHAR *ns;
1658 WARN("Attempt to load from the application directory.\n");
1659 GetModuleFileNameW(NULL, filename, MAX_PATH);
1660 ns = strrchrW(filename, '\\');
1661 *(ns+1) = '\0';
1663 ns = strchrW(assemblyname, ',');
1664 *(ns) = '\0';
1665 strcatW(filename, assemblyname);
1666 *(ns) = '.';
1667 strcatW(filename, wszDLL);
1671 TRACE("filename (%s)\n", debugstr_w(filename));
1673 *ppObj = NULL;
1676 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1677 if (SUCCEEDED(hr))
1679 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1681 if (SUCCEEDED(hr))
1682 hr = RuntimeHost_GetDefaultDomain(host, NULL, &domain);
1684 if (SUCCEEDED(hr))
1686 MonoImage *image;
1687 MonoClass *klass;
1688 MonoObject *result;
1689 IUnknown *unk = NULL;
1690 char *filenameA, *ns;
1691 char *classA;
1693 hr = CLASS_E_CLASSNOTAVAILABLE;
1695 mono_thread_attach(domain);
1697 filenameA = WtoA(filename);
1698 assembly = mono_domain_assembly_open(domain, filenameA);
1699 HeapFree(GetProcessHeap(), 0, filenameA);
1700 if (!assembly)
1702 ERR("Cannot open assembly %s\n", filenameA);
1703 goto cleanup;
1706 image = mono_assembly_get_image(assembly);
1707 if (!image)
1709 ERR("Couldn't get assembly image\n");
1710 goto cleanup;
1713 classA = WtoA(classname);
1714 ns = strrchr(classA, '.');
1715 *ns = '\0';
1717 klass = mono_class_from_name(image, classA, ns+1);
1718 HeapFree(GetProcessHeap(), 0, classA);
1719 if (!klass)
1721 ERR("Couldn't get class from image\n");
1722 goto cleanup;
1726 * Use the default constructor for the .NET class.
1728 result = mono_object_new(domain, klass);
1729 mono_runtime_object_init(result);
1731 hr = RuntimeHost_GetIUnknownForObject(host, result, &unk);
1732 if (SUCCEEDED(hr))
1734 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj);
1736 IUnknown_Release(unk);
1738 else
1739 hr = CLASS_E_CLASSNOTAVAILABLE;
1741 else
1742 hr = CLASS_E_CLASSNOTAVAILABLE;
1744 else
1745 hr = CLASS_E_CLASSNOTAVAILABLE;
1747 cleanup:
1748 if(info)
1749 ICLRRuntimeInfo_Release(info);
1751 RegCloseKey(key);
1753 return hr;