mf/session: Forward more events to the application.
[wine/zf.git] / dlls / mscoree / corruntimehost.c
blob51522c57d83d4b01c19a73c2bfec5925f845ac90
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"
32 #include "shlwapi.h"
34 #include "cor.h"
35 #include "mscoree.h"
36 #include "metahost.h"
37 #include "corhdr.h"
38 #include "cordebug.h"
39 #include "wine/list.h"
40 #include "mscoree_private.h"
42 #include "wine/debug.h"
43 #include "wine/heap.h"
45 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
47 #include "initguid.h"
49 DEFINE_GUID(IID__AppDomain, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13);
51 struct DomainEntry
53 struct list entry;
54 MonoDomain *domain;
57 static HANDLE dll_fixup_heap; /* using a separate heap so we can have execute permission */
59 static CRITICAL_SECTION fixup_list_cs;
60 static CRITICAL_SECTION_DEBUG fixup_list_cs_debug =
62 0, 0, &fixup_list_cs,
63 { &fixup_list_cs_debug.ProcessLocksList,
64 &fixup_list_cs_debug.ProcessLocksList },
65 0, 0, { (DWORD_PTR)(__FILE__ ": fixup_list_cs") }
67 static CRITICAL_SECTION fixup_list_cs = { &fixup_list_cs_debug, -1, 0, 0, 0, 0 };
69 static struct list dll_fixups;
71 WCHAR **private_path = NULL;
73 struct dll_fixup
75 struct list entry;
76 BOOL done;
77 HMODULE dll;
78 void *thunk_code; /* pointer into dll_fixup_heap */
79 VTableFixup *fixup;
80 void *vtable;
81 void *tokens; /* pointer into process heap */
84 struct comclassredirect_data
86 ULONG size;
87 ULONG flags;
88 DWORD model;
89 GUID clsid;
90 GUID alias;
91 GUID clsid2;
92 GUID tlbid;
93 ULONG name_len;
94 ULONG name_offset;
95 ULONG progid_len;
96 ULONG progid_offset;
97 ULONG clrdata_len;
98 ULONG clrdata_offset;
99 DWORD miscstatus;
100 DWORD miscstatuscontent;
101 DWORD miscstatusthumbnail;
102 DWORD miscstatusicon;
103 DWORD miscstatusdocprint;
106 struct clrclass_data
108 ULONG size;
109 DWORD res[2];
110 ULONG module_len;
111 ULONG module_offset;
112 ULONG name_len;
113 ULONG name_offset;
114 ULONG version_len;
115 ULONG version_offset;
116 DWORD res2[2];
119 static MonoDomain* domain_attach(MonoDomain *domain)
121 MonoDomain *prev_domain = mono_domain_get();
123 if (prev_domain == domain)
124 /* Do not set or restore domain. */
125 return NULL;
127 mono_thread_attach(domain);
129 return prev_domain;
132 static void domain_restore(MonoDomain *prev_domain)
134 if (prev_domain != NULL)
135 mono_domain_set(prev_domain, FALSE);
138 static HRESULT RuntimeHost_GetDefaultDomain(RuntimeHost *This, const WCHAR *config_path, MonoDomain **result)
140 WCHAR config_dir[MAX_PATH];
141 WCHAR base_dir[MAX_PATH];
142 char *base_dirA, *config_pathA, *slash;
143 HRESULT res=S_OK;
144 static BOOL configured_domain;
146 *result = get_root_domain();
148 EnterCriticalSection(&This->lock);
150 if (configured_domain) goto end;
152 if (!config_path)
154 DWORD len = ARRAY_SIZE(config_dir);
156 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};
158 res = ICLRRuntimeInfo_GetRuntimeDirectory(&This->version->ICLRRuntimeInfo_iface,
159 config_dir, &len);
160 if (FAILED(res))
161 goto end;
163 lstrcatW(config_dir, machine_configW);
165 config_path = config_dir;
168 config_pathA = WtoA(config_path);
169 if (!config_pathA)
171 res = E_OUTOFMEMORY;
172 goto end;
175 GetModuleFileNameW(NULL, base_dir, ARRAY_SIZE(base_dir));
176 base_dirA = WtoA(base_dir);
177 if (!base_dirA)
179 HeapFree(GetProcessHeap(), 0, config_pathA);
180 res = E_OUTOFMEMORY;
181 goto end;
184 slash = strrchr(base_dirA, '\\');
185 if (slash)
186 *(slash + 1) = 0;
188 TRACE("setting base_dir: %s, config_path: %s\n", base_dirA, config_pathA);
189 mono_domain_set_config(*result, base_dirA, config_pathA);
191 HeapFree(GetProcessHeap(), 0, config_pathA);
192 HeapFree(GetProcessHeap(), 0, base_dirA);
194 end:
196 configured_domain = TRUE;
198 LeaveCriticalSection(&This->lock);
200 return res;
203 static BOOL RuntimeHost_GetMethod(MonoDomain *domain, const char *assemblyname,
204 const char *namespace, const char *typename, const char *methodname, int arg_count,
205 MonoMethod **method)
207 MonoAssembly *assembly;
208 MonoImage *image;
209 MonoClass *klass;
211 if (!assemblyname)
213 image = mono_get_corlib();
215 else
217 MonoImageOpenStatus status;
218 assembly = mono_assembly_open(assemblyname, &status);
219 if (!assembly)
221 ERR("Cannot load assembly %s, status=%i\n", assemblyname, status);
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;
233 klass = mono_class_from_name(image, namespace, typename);
234 if (!klass)
236 ERR("Couldn't get class %s.%s from image\n", namespace, typename);
237 return FALSE;
240 *method = mono_class_get_method_from_name(klass, methodname, arg_count);
241 if (!*method)
243 ERR("Couldn't get method %s from class %s.%s\n", methodname, namespace, typename);
244 return FALSE;
247 return TRUE;
250 static HRESULT RuntimeHost_Invoke(RuntimeHost *This, MonoDomain *domain,
251 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
252 MonoObject *obj, void **args, int arg_count, MonoObject **result);
254 static HRESULT RuntimeHost_DoInvoke(RuntimeHost *This, MonoDomain *domain,
255 const char *methodname, MonoMethod *method, MonoObject *obj, void **args, MonoObject **result)
257 MonoObject *exc;
258 static const char *get_hresult = "get_HResult";
260 *result = mono_runtime_invoke(method, obj, args, &exc);
261 if (exc)
263 HRESULT hr;
264 MonoObject *hr_object;
266 if (methodname != get_hresult)
268 /* Map the exception to an HRESULT. */
269 hr = RuntimeHost_Invoke(This, domain, NULL, "System", "Exception", get_hresult,
270 exc, NULL, 0, &hr_object);
271 if (SUCCEEDED(hr))
272 hr = *(HRESULT*)mono_object_unbox(hr_object);
273 if (SUCCEEDED(hr))
274 hr = E_FAIL;
276 else
277 hr = E_FAIL;
278 *result = NULL;
279 return hr;
282 return S_OK;
285 static HRESULT RuntimeHost_Invoke(RuntimeHost *This, MonoDomain *domain,
286 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
287 MonoObject *obj, void **args, int arg_count, MonoObject **result)
289 MonoMethod *method;
290 MonoDomain *prev_domain;
291 HRESULT hr;
293 *result = NULL;
295 prev_domain = domain_attach(domain);
297 if (!RuntimeHost_GetMethod(domain, assemblyname, namespace, typename, methodname,
298 arg_count, &method))
300 domain_restore(prev_domain);
301 return E_FAIL;
304 hr = RuntimeHost_DoInvoke(This, domain, methodname, method, obj, args, result);
305 if (FAILED(hr))
307 ERR("Method %s.%s:%s raised an exception, hr=%x\n", namespace, typename, methodname, hr);
310 domain_restore(prev_domain);
312 return hr;
315 static HRESULT RuntimeHost_VirtualInvoke(RuntimeHost *This, MonoDomain *domain,
316 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
317 MonoObject *obj, void **args, int arg_count, MonoObject **result)
319 MonoMethod *method;
320 MonoDomain *prev_domain;
321 HRESULT hr;
323 *result = NULL;
325 if (!obj)
327 ERR("\"this\" object cannot be null\n");
328 return E_POINTER;
331 prev_domain = domain_attach(domain);
333 if (!RuntimeHost_GetMethod(domain, assemblyname, namespace, typename, methodname,
334 arg_count, &method))
336 domain_restore(prev_domain);
337 return E_FAIL;
340 method = mono_object_get_virtual_method(obj, method);
341 if (!method)
343 ERR("Object %p does not support method %s.%s:%s\n", obj, namespace, typename, methodname);
344 domain_restore(prev_domain);
345 return E_FAIL;
348 hr = RuntimeHost_DoInvoke(This, domain, methodname, method, obj, args, result);
349 if (FAILED(hr))
351 ERR("Method %s.%s:%s raised an exception, hr=%x\n", namespace, typename, methodname, hr);
354 domain_restore(prev_domain);
356 return hr;
359 static HRESULT RuntimeHost_GetObjectForIUnknown(RuntimeHost *This, MonoDomain *domain,
360 IUnknown *unk, MonoObject **obj)
362 HRESULT hr;
363 void *args[1];
364 MonoObject *result;
366 args[0] = &unk;
367 hr = RuntimeHost_Invoke(This, domain, NULL, "System.Runtime.InteropServices", "Marshal", "GetObjectForIUnknown",
368 NULL, args, 1, &result);
370 if (SUCCEEDED(hr))
372 *obj = result;
374 return hr;
377 static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, const WCHAR *name, IUnknown *setup,
378 IUnknown *evidence, MonoDomain **result)
380 HRESULT res;
381 char *nameA;
382 MonoDomain *domain;
383 void *args[3];
384 MonoObject *new_domain, *id;
386 res = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
387 if (FAILED(res))
389 return res;
392 nameA = WtoA(name);
393 if (!nameA)
395 return E_OUTOFMEMORY;
398 args[0] = mono_string_new(domain, nameA);
399 HeapFree(GetProcessHeap(), 0, nameA);
401 if (!args[0])
403 return E_OUTOFMEMORY;
406 if (evidence)
408 res = RuntimeHost_GetObjectForIUnknown(This, domain, evidence, (MonoObject **)&args[1]);
409 if (FAILED(res))
411 return res;
414 else
416 args[1] = NULL;
419 if (setup)
421 res = RuntimeHost_GetObjectForIUnknown(This, domain, setup, (MonoObject **)&args[2]);
422 if (FAILED(res))
424 return res;
427 else
429 args[2] = NULL;
432 res = RuntimeHost_Invoke(This, domain, NULL, "System", "AppDomain", "CreateDomain",
433 NULL, args, 3, &new_domain);
435 if (FAILED(res))
437 return res;
440 /* new_domain is not the AppDomain itself, but a transparent proxy.
441 * So, we'll retrieve its ID, and use that to get the real domain object.
442 * We can't do a regular invoke, because that will bypass the proxy.
443 * Instead, do a vcall.
446 res = RuntimeHost_VirtualInvoke(This, domain, NULL, "System", "AppDomain", "get_Id",
447 new_domain, NULL, 0, &id);
449 if (FAILED(res))
451 return res;
454 TRACE("returning domain id %d\n", *(int *)mono_object_unbox(id));
456 *result = mono_domain_get_by_id(*(int *)mono_object_unbox(id));
458 return S_OK;
461 static HRESULT RuntimeHost_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *domain, IUnknown **punk)
463 HRESULT hr;
464 MonoObject *appdomain_object;
465 IUnknown *unk;
467 hr = RuntimeHost_Invoke(This, domain, NULL, "System", "AppDomain", "get_CurrentDomain",
468 NULL, NULL, 0, &appdomain_object);
470 if (SUCCEEDED(hr))
471 hr = RuntimeHost_GetIUnknownForObject(This, appdomain_object, &unk);
473 if (SUCCEEDED(hr))
475 hr = IUnknown_QueryInterface(unk, &IID__AppDomain, (void**)punk);
477 IUnknown_Release(unk);
480 return hr;
483 void RuntimeHost_ExitProcess(RuntimeHost *This, INT exitcode)
485 HRESULT hr;
486 void *args[2];
487 MonoDomain *domain;
488 MonoObject *dummy;
490 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
491 if (FAILED(hr))
493 ERR("Cannot get domain, hr=%x\n", hr);
494 return;
497 args[0] = &exitcode;
498 args[1] = NULL;
499 RuntimeHost_Invoke(This, domain, NULL, "System", "Environment", "Exit",
500 NULL, args, 1, &dummy);
502 ERR("Process should have exited\n");
505 static inline RuntimeHost *impl_from_ICLRRuntimeHost( ICLRRuntimeHost *iface )
507 return CONTAINING_RECORD(iface, RuntimeHost, ICLRRuntimeHost_iface);
510 static inline RuntimeHost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
512 return CONTAINING_RECORD(iface, RuntimeHost, ICorRuntimeHost_iface);
515 /*** IUnknown methods ***/
516 static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
517 REFIID riid,
518 void **ppvObject)
520 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
521 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
523 if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) ||
524 IsEqualGUID( riid, &IID_IUnknown ) )
526 *ppvObject = iface;
528 else
530 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
531 return E_NOINTERFACE;
534 ICorRuntimeHost_AddRef( iface );
536 return S_OK;
539 static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface)
541 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
543 return InterlockedIncrement( &This->ref );
546 static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface)
548 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
549 ULONG ref;
551 ref = InterlockedDecrement( &This->ref );
553 return ref;
556 /*** ICorRuntimeHost methods ***/
557 static HRESULT WINAPI corruntimehost_CreateLogicalThreadState(
558 ICorRuntimeHost* iface)
560 FIXME("stub %p\n", iface);
561 return E_NOTIMPL;
564 static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState(
565 ICorRuntimeHost* iface)
567 FIXME("stub %p\n", iface);
568 return E_NOTIMPL;
571 static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState(
572 ICorRuntimeHost* iface,
573 DWORD *fiberCookie)
575 FIXME("stub %p\n", iface);
576 return E_NOTIMPL;
579 static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState(
580 ICorRuntimeHost* iface,
581 DWORD **fiberCookie)
583 FIXME("stub %p\n", iface);
584 return E_NOTIMPL;
587 static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread(
588 ICorRuntimeHost* iface,
589 DWORD *pCount)
591 FIXME("stub %p\n", iface);
592 return E_NOTIMPL;
595 static HRESULT WINAPI corruntimehost_MapFile(
596 ICorRuntimeHost* iface,
597 HANDLE hFile,
598 HMODULE *mapAddress)
600 FIXME("stub %p\n", iface);
601 return E_NOTIMPL;
604 static HRESULT WINAPI corruntimehost_GetConfiguration(
605 ICorRuntimeHost* iface,
606 ICorConfiguration **pConfiguration)
608 FIXME("stub %p\n", iface);
609 return E_NOTIMPL;
612 static HRESULT WINAPI corruntimehost_Start(
613 ICorRuntimeHost* iface)
615 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
616 MonoDomain *dummy;
618 TRACE("%p\n", This);
620 return RuntimeHost_GetDefaultDomain(This, NULL, &dummy);
623 static HRESULT WINAPI corruntimehost_Stop(
624 ICorRuntimeHost* iface)
626 FIXME("stub %p\n", iface);
627 return E_NOTIMPL;
630 static HRESULT WINAPI corruntimehost_CreateDomain(
631 ICorRuntimeHost* iface,
632 LPCWSTR friendlyName,
633 IUnknown *identityArray,
634 IUnknown **appDomain)
636 return ICorRuntimeHost_CreateDomainEx(iface, friendlyName, NULL, NULL, appDomain);
639 static HRESULT WINAPI corruntimehost_GetDefaultDomain(
640 ICorRuntimeHost* iface,
641 IUnknown **pAppDomain)
643 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
644 HRESULT hr;
645 MonoDomain *domain;
647 TRACE("(%p)\n", iface);
649 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
651 if (SUCCEEDED(hr))
653 hr = RuntimeHost_GetIUnknownForDomain(This, domain, pAppDomain);
656 return hr;
659 static HRESULT WINAPI corruntimehost_EnumDomains(
660 ICorRuntimeHost* iface,
661 HDOMAINENUM *hEnum)
663 FIXME("stub %p\n", iface);
664 return E_NOTIMPL;
667 static HRESULT WINAPI corruntimehost_NextDomain(
668 ICorRuntimeHost* iface,
669 HDOMAINENUM hEnum,
670 IUnknown **appDomain)
672 FIXME("stub %p\n", iface);
673 return E_NOTIMPL;
676 static HRESULT WINAPI corruntimehost_CloseEnum(
677 ICorRuntimeHost* iface,
678 HDOMAINENUM hEnum)
680 FIXME("stub %p\n", iface);
681 return E_NOTIMPL;
684 static HRESULT WINAPI corruntimehost_CreateDomainEx(
685 ICorRuntimeHost* iface,
686 LPCWSTR friendlyName,
687 IUnknown *setup,
688 IUnknown *evidence,
689 IUnknown **appDomain)
691 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
692 HRESULT hr;
693 MonoDomain *domain;
695 if (!friendlyName || !appDomain)
697 return E_POINTER;
699 if (!is_mono_started)
701 return E_FAIL;
704 TRACE("(%p)\n", iface);
706 hr = RuntimeHost_AddDomain(This, friendlyName, setup, evidence, &domain);
708 if (SUCCEEDED(hr))
710 hr = RuntimeHost_GetIUnknownForDomain(This, domain, appDomain);
713 return hr;
716 static HRESULT WINAPI corruntimehost_CreateDomainSetup(
717 ICorRuntimeHost* iface,
718 IUnknown **appDomainSetup)
720 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
721 HRESULT hr;
722 MonoDomain *domain;
723 MonoObject *obj;
724 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};
726 TRACE("(%p)\n", iface);
728 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
730 if (SUCCEEDED(hr))
731 hr = RuntimeHost_CreateManagedInstance(This, classnameW, domain, &obj);
733 if (SUCCEEDED(hr))
734 hr = RuntimeHost_GetIUnknownForObject(This, obj, appDomainSetup);
736 return hr;
739 static HRESULT WINAPI corruntimehost_CreateEvidence(
740 ICorRuntimeHost* iface,
741 IUnknown **evidence)
743 FIXME("stub %p\n", iface);
744 return E_NOTIMPL;
747 static HRESULT WINAPI corruntimehost_UnloadDomain(
748 ICorRuntimeHost* iface,
749 IUnknown *appDomain)
751 FIXME("stub %p\n", iface);
752 return E_NOTIMPL;
755 static HRESULT WINAPI corruntimehost_CurrentDomain(
756 ICorRuntimeHost* iface,
757 IUnknown **appDomain)
759 FIXME("stub %p\n", iface);
760 return E_NOTIMPL;
763 static const struct ICorRuntimeHostVtbl corruntimehost_vtbl =
765 corruntimehost_QueryInterface,
766 corruntimehost_AddRef,
767 corruntimehost_Release,
768 corruntimehost_CreateLogicalThreadState,
769 corruntimehost_DeleteLogicalThreadState,
770 corruntimehost_SwitchInLogicalThreadState,
771 corruntimehost_SwitchOutLogicalThreadState,
772 corruntimehost_LocksHeldByLogicalThread,
773 corruntimehost_MapFile,
774 corruntimehost_GetConfiguration,
775 corruntimehost_Start,
776 corruntimehost_Stop,
777 corruntimehost_CreateDomain,
778 corruntimehost_GetDefaultDomain,
779 corruntimehost_EnumDomains,
780 corruntimehost_NextDomain,
781 corruntimehost_CloseEnum,
782 corruntimehost_CreateDomainEx,
783 corruntimehost_CreateDomainSetup,
784 corruntimehost_CreateEvidence,
785 corruntimehost_UnloadDomain,
786 corruntimehost_CurrentDomain
789 static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface,
790 REFIID riid,
791 void **ppvObject)
793 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
794 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
796 if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) ||
797 IsEqualGUID( riid, &IID_IUnknown ) )
799 *ppvObject = iface;
801 else
803 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
804 return E_NOINTERFACE;
807 ICLRRuntimeHost_AddRef( iface );
809 return S_OK;
812 static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface)
814 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
815 return ICorRuntimeHost_AddRef(&This->ICorRuntimeHost_iface);
818 static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface)
820 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
821 return ICorRuntimeHost_Release(&This->ICorRuntimeHost_iface);
824 static HRESULT WINAPI CLRRuntimeHost_Start(ICLRRuntimeHost* iface)
826 FIXME("(%p)\n", iface);
827 return E_NOTIMPL;
830 static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
832 FIXME("(%p)\n", iface);
833 return E_NOTIMPL;
836 static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
837 IHostControl *pHostControl)
839 FIXME("(%p,%p)\n", iface, pHostControl);
840 return E_NOTIMPL;
843 static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
844 ICLRControl **pCLRControl)
846 FIXME("(%p,%p)\n", iface, pCLRControl);
847 return E_NOTIMPL;
850 static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
851 DWORD dwAppDomainId, BOOL fWaitUntilDone)
853 FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
854 return E_NOTIMPL;
857 static HRESULT WINAPI CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost* iface,
858 DWORD dwAppDomainId, FExecuteInAppDomainCallback pCallback, void *cookie)
860 FIXME("(%p,%u,%p,%p)\n", iface, dwAppDomainId, pCallback, cookie);
861 return E_NOTIMPL;
864 static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
865 DWORD *pdwAppDomainId)
867 FIXME("(%p,%p)\n", iface, pdwAppDomainId);
868 return E_NOTIMPL;
871 static HRESULT WINAPI CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost* iface,
872 LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR *ppwzManifestPaths,
873 DWORD dwActivationData, LPCWSTR *ppwzActivationData, int *pReturnValue)
875 FIXME("(%p,%s,%u,%u)\n", iface, debugstr_w(pwzAppFullName), dwManifestPaths, dwActivationData);
876 return E_NOTIMPL;
879 static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* iface,
880 LPCWSTR pwzAssemblyPath, LPCWSTR pwzTypeName, LPCWSTR pwzMethodName,
881 LPCWSTR pwzArgument, DWORD *pReturnValue)
883 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
884 HRESULT hr;
885 MonoDomain *domain, *prev_domain;
886 MonoObject *result;
887 MonoString *str;
888 char *filenameA = NULL, *classA = NULL, *methodA = NULL;
889 char *argsA = NULL, *ns;
891 TRACE("(%p,%s,%s,%s,%s)\n", iface, debugstr_w(pwzAssemblyPath),
892 debugstr_w(pwzTypeName), debugstr_w(pwzMethodName), debugstr_w(pwzArgument));
894 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
896 if (FAILED(hr))
897 return hr;
899 prev_domain = domain_attach(domain);
901 if (SUCCEEDED(hr))
903 filenameA = WtoA(pwzAssemblyPath);
904 if (!filenameA) hr = E_OUTOFMEMORY;
907 if (SUCCEEDED(hr))
909 classA = WtoA(pwzTypeName);
910 if (!classA) hr = E_OUTOFMEMORY;
913 if (SUCCEEDED(hr))
915 ns = strrchr(classA, '.');
916 if (ns)
917 *ns = '\0';
918 else
919 hr = E_INVALIDARG;
922 if (SUCCEEDED(hr))
924 methodA = WtoA(pwzMethodName);
925 if (!methodA) hr = E_OUTOFMEMORY;
928 /* The .NET function we are calling has the following declaration
929 * public static int functionName(String param)
931 if (SUCCEEDED(hr))
933 argsA = WtoA(pwzArgument);
934 if (!argsA) hr = E_OUTOFMEMORY;
937 if (SUCCEEDED(hr))
939 str = mono_string_new(domain, argsA);
940 if (!str) hr = E_OUTOFMEMORY;
943 if (SUCCEEDED(hr))
945 hr = RuntimeHost_Invoke(This, domain, filenameA, classA, ns+1, methodA,
946 NULL, (void**)&str, 1, &result);
949 if (SUCCEEDED(hr))
950 *pReturnValue = *(DWORD*)mono_object_unbox(result);
952 domain_restore(prev_domain);
954 HeapFree(GetProcessHeap(), 0, filenameA);
955 HeapFree(GetProcessHeap(), 0, classA);
956 HeapFree(GetProcessHeap(), 0, argsA);
957 HeapFree(GetProcessHeap(), 0, methodA);
959 return hr;
962 static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
964 CLRRuntimeHost_QueryInterface,
965 CLRRuntimeHost_AddRef,
966 CLRRuntimeHost_Release,
967 CLRRuntimeHost_Start,
968 CLRRuntimeHost_Stop,
969 CLRRuntimeHost_SetHostControl,
970 CLRRuntimeHost_GetCLRControl,
971 CLRRuntimeHost_UnloadAppDomain,
972 CLRRuntimeHost_ExecuteInAppDomain,
973 CLRRuntimeHost_GetCurrentAppDomainId,
974 CLRRuntimeHost_ExecuteApplication,
975 CLRRuntimeHost_ExecuteInDefaultAppDomain
978 /* Create an instance of a type given its name, by calling its constructor with
979 * no arguments. Note that result MUST be in the stack, or the garbage
980 * collector may free it prematurely. */
981 HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
982 MonoDomain *domain, MonoObject **result)
984 HRESULT hr=S_OK;
985 char *nameA=NULL;
986 MonoType *type;
987 MonoClass *klass;
988 MonoObject *obj;
989 MonoDomain *prev_domain;
991 if (!domain)
992 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
994 if (FAILED(hr))
995 return hr;
997 prev_domain = domain_attach(domain);
999 if (SUCCEEDED(hr))
1001 nameA = WtoA(name);
1002 if (!nameA)
1003 hr = E_OUTOFMEMORY;
1006 if (SUCCEEDED(hr))
1008 type = mono_reflection_type_from_name(nameA, NULL);
1009 if (!type)
1011 ERR("Cannot find type %s\n", debugstr_w(name));
1012 hr = E_FAIL;
1016 if (SUCCEEDED(hr))
1018 klass = mono_class_from_mono_type(type);
1019 if (!klass)
1021 ERR("Cannot convert type %s to a class\n", debugstr_w(name));
1022 hr = E_FAIL;
1026 if (SUCCEEDED(hr))
1028 obj = mono_object_new(domain, klass);
1029 if (!obj)
1031 ERR("Cannot allocate object of type %s\n", debugstr_w(name));
1032 hr = E_FAIL;
1036 if (SUCCEEDED(hr))
1038 /* FIXME: Detect exceptions from the constructor? */
1039 mono_runtime_object_init(obj);
1040 *result = obj;
1043 domain_restore(prev_domain);
1045 HeapFree(GetProcessHeap(), 0, nameA);
1047 return hr;
1050 /* Get an IUnknown pointer for a Mono object.
1052 * This is just a "light" wrapper around
1053 * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
1055 * NOTE: The IUnknown* is created with a reference to the object.
1056 * Until they have a reference, objects must be in the stack to prevent the
1057 * garbage collector from freeing them. */
1058 HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj,
1059 IUnknown **ppUnk)
1061 MonoDomain *domain;
1062 MonoObject *result;
1063 HRESULT hr;
1065 domain = mono_object_get_domain(obj);
1067 hr = RuntimeHost_Invoke(This, domain, NULL, "System.Runtime.InteropServices", "Marshal", "GetIUnknownForObject",
1068 NULL, (void**)&obj, 1, &result);
1070 if (SUCCEEDED(hr))
1071 *ppUnk = *(IUnknown**)mono_object_unbox(result);
1072 else
1073 *ppUnk = NULL;
1075 return hr;
1078 static void get_utf8_args(int *argc, char ***argv)
1080 WCHAR **argvw;
1081 int size=0, i;
1082 char *current_arg;
1084 argvw = CommandLineToArgvW(GetCommandLineW(), argc);
1086 for (i=0; i<*argc; i++)
1088 size += sizeof(char*);
1089 size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
1091 size += sizeof(char*);
1093 *argv = HeapAlloc(GetProcessHeap(), 0, size);
1094 current_arg = (char*)(*argv + *argc + 1);
1096 for (i=0; i<*argc; i++)
1098 (*argv)[i] = current_arg;
1099 current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
1102 (*argv)[*argc] = NULL;
1104 HeapFree(GetProcessHeap(), 0, argvw);
1107 #if __i386__
1109 # define CAN_FIXUP_VTABLE 1
1111 #include "pshpack1.h"
1113 struct vtable_fixup_thunk
1115 /* push %ecx */
1116 BYTE i7;
1117 /* sub $0x4,%esp */
1118 BYTE i1[3];
1119 /* mov fixup,(%esp) */
1120 BYTE i2[3];
1121 struct dll_fixup *fixup;
1122 /* mov function,%eax */
1123 BYTE i3;
1124 void (CDECL *function)(struct dll_fixup *);
1125 /* call *%eax */
1126 BYTE i4[2];
1127 /* pop %eax */
1128 BYTE i5;
1129 /* pop %ecx */
1130 BYTE i8;
1131 /* jmp *vtable_entry */
1132 BYTE i6[2];
1133 void *vtable_entry;
1136 static const struct vtable_fixup_thunk thunk_template = {
1137 0x51,
1138 {0x83,0xec,0x04},
1139 {0xc7,0x04,0x24},
1140 NULL,
1141 0xb8,
1142 NULL,
1143 {0xff,0xd0},
1144 0x58,
1145 0x59,
1146 {0xff,0x25},
1147 NULL
1150 #include "poppack.h"
1152 #elif __x86_64__ /* !__i386__ */
1154 # define CAN_FIXUP_VTABLE 1
1156 #include "pshpack1.h"
1158 struct vtable_fixup_thunk
1160 /* push %rbp;
1161 mov %rsp, %rbp
1162 sub $0x80, %rsp ; 0x8*4 + 0x10*4 + 0x20
1164 BYTE i1[11];
1166 mov %rcx, 0x60(%rsp); mov %rdx, 0x68(%rsp); mov %r8, 0x70(%rsp); mov %r9, 0x78(%rsp);
1167 movaps %xmm0,0x20(%rsp); ...; movaps %xmm3,0x50(%esp)
1169 BYTE i2[40];
1170 /* mov function,%rax */
1171 BYTE i3[2];
1172 void (CDECL *function)(struct dll_fixup *);
1173 /* mov fixup,%rcx */
1174 BYTE i4[2];
1175 struct dll_fixup *fixup;
1176 /* call *%rax */
1177 BYTE i5[2];
1179 mov 0x60(%rsp),%rcx; mov 0x68(%rsp),%rdx; mov 0x70(%rsp),%r8; mov 0x78(%rsp),%r9;
1180 movaps 0x20(%rsp),xmm0; ...; movaps 0x50(%esp),xmm3
1182 BYTE i6[40];
1183 /* mov %rbp, %rsp
1184 pop %rbp
1186 BYTE i7[4];
1187 /* mov vtable_entry, %rax */
1188 BYTE i8[2];
1189 void *vtable_entry;
1190 /* mov [%rax],%rax
1191 jmp %rax */
1192 BYTE i9[5];
1195 static const struct vtable_fixup_thunk thunk_template = {
1196 {0x55,0x48,0x89,0xE5, 0x48,0x81,0xEC,0x80,0x00,0x00,0x00},
1197 {0x48,0x89,0x4C,0x24,0x60, 0x48,0x89,0x54,0x24,0x68,
1198 0x4C,0x89,0x44,0x24,0x70, 0x4C,0x89,0x4C,0x24,0x78,
1199 0x0F,0x29,0x44,0x24,0x20, 0x0F,0x29,0x4C,0x24,0x30,
1200 0x0F,0x29,0x54,0x24,0x40, 0x0F,0x29,0x5C,0x24,0x50,
1202 {0x48,0xB8},
1203 NULL,
1204 {0x48,0xB9},
1205 NULL,
1206 {0xFF,0xD0},
1207 {0x48,0x8B,0x4C,0x24,0x60, 0x48,0x8B,0x54,0x24,0x68,
1208 0x4C,0x8B,0x44,0x24,0x70, 0x4C,0x8B,0x4C,0x24,0x78,
1209 0x0F,0x28,0x44,0x24,0x20, 0x0F,0x28,0x4C,0x24,0x30,
1210 0x0F,0x28,0x54,0x24,0x40, 0x0F,0x28,0x5C,0x24,0x50,
1212 {0x48,0x89,0xEC, 0x5D},
1213 {0x48,0xB8},
1214 NULL,
1215 {0x48,0x8B,0x00,0xFF,0xE0}
1218 #include "poppack.h"
1220 #else /* !__i386__ && !__x86_64__ */
1222 # define CAN_FIXUP_VTABLE 0
1224 struct vtable_fixup_thunk
1226 struct dll_fixup *fixup;
1227 void (CDECL *function)(struct dll_fixup *fixup);
1228 void *vtable_entry;
1231 static const struct vtable_fixup_thunk thunk_template = {0};
1233 #endif
1235 DWORD WINAPI GetTokenForVTableEntry(HINSTANCE hinst, BYTE **ppVTEntry)
1237 struct dll_fixup *fixup;
1238 DWORD result = 0;
1239 DWORD rva;
1240 int i;
1242 TRACE("%p,%p\n", hinst, ppVTEntry);
1244 rva = (BYTE*)ppVTEntry - (BYTE*)hinst;
1246 EnterCriticalSection(&fixup_list_cs);
1247 LIST_FOR_EACH_ENTRY(fixup, &dll_fixups, struct dll_fixup, entry)
1249 if (fixup->dll != hinst)
1250 continue;
1251 if (rva < fixup->fixup->rva || (rva - fixup->fixup->rva >= fixup->fixup->count * sizeof(ULONG_PTR)))
1252 continue;
1253 i = (rva - fixup->fixup->rva) / sizeof(ULONG_PTR);
1254 result = ((ULONG_PTR*)fixup->tokens)[i];
1255 break;
1257 LeaveCriticalSection(&fixup_list_cs);
1259 TRACE("<-- %x\n", result);
1260 return result;
1263 static void CDECL ReallyFixupVTable(struct dll_fixup *fixup)
1265 HRESULT hr=S_OK;
1266 WCHAR filename[MAX_PATH];
1267 ICLRRuntimeInfo *info=NULL;
1268 RuntimeHost *host;
1269 char *filenameA;
1270 MonoImage *image=NULL;
1271 MonoAssembly *assembly=NULL;
1272 MonoImageOpenStatus status=0;
1273 MonoDomain *domain;
1275 if (fixup->done) return;
1277 /* It's possible we'll have two threads doing this at once. This is
1278 * considered preferable to the potential deadlock if we use a mutex. */
1280 GetModuleFileNameW(fixup->dll, filename, MAX_PATH);
1282 TRACE("%p,%p,%s\n", fixup, fixup->dll, debugstr_w(filename));
1284 filenameA = WtoA(filename);
1285 if (!filenameA)
1286 hr = E_OUTOFMEMORY;
1288 if (SUCCEEDED(hr))
1289 hr = get_runtime_info(filename, NULL, NULL, NULL, 0, 0, FALSE, &info);
1291 if (SUCCEEDED(hr))
1292 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1294 if (SUCCEEDED(hr))
1295 hr = RuntimeHost_GetDefaultDomain(host, NULL, &domain);
1297 if (SUCCEEDED(hr))
1299 MonoDomain *prev_domain;
1301 prev_domain = domain_attach(domain);
1303 assembly = mono_assembly_open(filenameA, &status);
1305 if (assembly)
1307 int i;
1309 /* Mono needs an image that belongs to an assembly. */
1310 image = mono_assembly_get_image(assembly);
1312 #if __x86_64__
1313 if (fixup->fixup->type & COR_VTABLE_64BIT)
1314 #else
1315 if (fixup->fixup->type & COR_VTABLE_32BIT)
1316 #endif
1318 void **vtable = fixup->vtable;
1319 ULONG_PTR *tokens = fixup->tokens;
1320 for (i=0; i<fixup->fixup->count; i++)
1322 vtable[i] = mono_marshal_get_vtfixup_ftnptr(
1323 image, tokens[i], fixup->fixup->type);
1327 fixup->done = TRUE;
1330 domain_restore(prev_domain);
1333 if (info != NULL)
1334 ICLRRuntimeInfo_Release(info);
1336 HeapFree(GetProcessHeap(), 0, filenameA);
1338 if (!fixup->done)
1340 ERR("unable to fixup vtable, hr=%x, status=%d\n", hr, status);
1341 /* If we returned now, we'd get an infinite loop. */
1342 assert(0);
1346 static void FixupVTableEntry(HMODULE hmodule, VTableFixup *vtable_fixup)
1348 /* We can't actually generate code for the functions without loading mono,
1349 * and loading mono inside DllMain is a terrible idea. So we make thunks
1350 * that call ReallyFixupVTable, which will load the runtime and fill in the
1351 * vtable, then do an indirect jump using the (now filled in) vtable. Note
1352 * that we have to keep the thunks around forever, as one of them may get
1353 * called while we're filling in the table, and we can never be sure all
1354 * threads are clear. */
1355 struct dll_fixup *fixup;
1357 fixup = HeapAlloc(GetProcessHeap(), 0, sizeof(*fixup));
1359 fixup->dll = hmodule;
1360 fixup->thunk_code = HeapAlloc(dll_fixup_heap, 0, sizeof(struct vtable_fixup_thunk) * vtable_fixup->count);
1361 fixup->fixup = vtable_fixup;
1362 fixup->vtable = (BYTE*)hmodule + vtable_fixup->rva;
1363 fixup->done = FALSE;
1365 #if __x86_64__
1366 if (vtable_fixup->type & COR_VTABLE_64BIT)
1367 #else
1368 if (vtable_fixup->type & COR_VTABLE_32BIT)
1369 #endif
1371 void **vtable = fixup->vtable;
1372 ULONG_PTR *tokens;
1373 int i;
1374 struct vtable_fixup_thunk *thunks = fixup->thunk_code;
1376 tokens = fixup->tokens = HeapAlloc(GetProcessHeap(), 0, sizeof(*tokens) * vtable_fixup->count);
1377 memcpy(tokens, vtable, sizeof(*tokens) * vtable_fixup->count);
1378 for (i=0; i<vtable_fixup->count; i++)
1380 thunks[i] = thunk_template;
1381 thunks[i].fixup = fixup;
1382 thunks[i].function = ReallyFixupVTable;
1383 thunks[i].vtable_entry = &vtable[i];
1384 vtable[i] = &thunks[i];
1387 else
1389 ERR("unsupported vtable fixup flags %x\n", vtable_fixup->type);
1390 HeapFree(dll_fixup_heap, 0, fixup->thunk_code);
1391 HeapFree(GetProcessHeap(), 0, fixup);
1392 return;
1395 EnterCriticalSection(&fixup_list_cs);
1396 list_add_tail(&dll_fixups, &fixup->entry);
1397 LeaveCriticalSection(&fixup_list_cs);
1400 static void FixupVTable_Assembly(HMODULE hmodule, ASSEMBLY *assembly)
1402 VTableFixup *vtable_fixups;
1403 ULONG vtable_fixup_count, i;
1405 assembly_get_vtable_fixups(assembly, &vtable_fixups, &vtable_fixup_count);
1406 if (CAN_FIXUP_VTABLE)
1407 for (i=0; i<vtable_fixup_count; i++)
1408 FixupVTableEntry(hmodule, &vtable_fixups[i]);
1409 else if (vtable_fixup_count)
1410 FIXME("cannot fixup vtable; expect a crash\n");
1413 static void FixupVTable(HMODULE hmodule)
1415 ASSEMBLY *assembly;
1416 HRESULT hr;
1418 hr = assembly_from_hmodule(&assembly, hmodule);
1419 if (SUCCEEDED(hr))
1421 FixupVTable_Assembly(hmodule, assembly);
1422 assembly_release(assembly);
1424 else
1425 ERR("failed to read CLR headers, hr=%x\n", hr);
1428 __int32 WINAPI _CorExeMain(void)
1430 static const WCHAR dotconfig[] = {'.','c','o','n','f','i','g',0};
1431 static const WCHAR scW[] = {';',0};
1432 int exit_code;
1433 int argc;
1434 char **argv;
1435 MonoDomain *domain=NULL;
1436 MonoImage *image;
1437 MonoImageOpenStatus status;
1438 MonoAssembly *assembly=NULL;
1439 WCHAR filename[MAX_PATH], config_file[MAX_PATH], *temp, **priv_path;
1440 SIZE_T config_file_dir_size;
1441 char *filenameA;
1442 ICLRRuntimeInfo *info;
1443 RuntimeHost *host;
1444 parsed_config_file parsed_config;
1445 HRESULT hr;
1446 int i, number_of_private_paths = 0;
1448 get_utf8_args(&argc, &argv);
1450 GetModuleFileNameW(NULL, filename, MAX_PATH);
1452 TRACE("%s", debugstr_w(filename));
1453 for (i=0; i<argc; i++)
1454 TRACE(" %s", debugstr_a(argv[i]));
1455 TRACE("\n");
1457 filenameA = WtoA(filename);
1458 if (!filenameA)
1460 HeapFree(GetProcessHeap(), 0, argv);
1461 return -1;
1464 FixupVTable(GetModuleHandleW(NULL));
1466 wcscpy(config_file, filename);
1467 wcscat(config_file, dotconfig);
1469 hr = parse_config_file(config_file, &parsed_config);
1470 if (SUCCEEDED(hr) && parsed_config.private_path && parsed_config.private_path[0])
1472 WCHAR *save;
1473 for(i = 0; parsed_config.private_path[i] != 0; i++)
1474 if (parsed_config.private_path[i] == ';') number_of_private_paths++;
1475 if (parsed_config.private_path[wcslen(parsed_config.private_path) - 1] != ';') number_of_private_paths++;
1476 config_file_dir_size = (wcsrchr(config_file, '\\') - config_file) + 1;
1477 priv_path = HeapAlloc(GetProcessHeap(), 0, (number_of_private_paths + 1) * sizeof(WCHAR *));
1478 /* wcstok ignores trailing semicolons */
1479 temp = wcstok_s(parsed_config.private_path, scW, &save);
1480 for (i = 0; i < number_of_private_paths; i++)
1482 priv_path[i] = HeapAlloc(GetProcessHeap(), 0, (config_file_dir_size + wcslen(temp) + 1) * sizeof(WCHAR));
1483 memcpy(priv_path[i], config_file, config_file_dir_size * sizeof(WCHAR));
1484 wcscpy(priv_path[i] + config_file_dir_size, temp);
1485 temp = wcstok_s(NULL, scW, &save);
1487 priv_path[number_of_private_paths] = NULL;
1488 if (InterlockedCompareExchangePointer((void **)&private_path, priv_path, NULL))
1489 ERR("private_path was already set\n");
1492 free_parsed_config_file(&parsed_config);
1494 hr = get_runtime_info(filename, NULL, NULL, NULL, 0, 0, FALSE, &info);
1496 if (SUCCEEDED(hr))
1498 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1500 if (SUCCEEDED(hr))
1501 hr = RuntimeHost_GetDefaultDomain(host, config_file, &domain);
1503 if (SUCCEEDED(hr))
1505 image = mono_image_open_from_module_handle(GetModuleHandleW(NULL),
1506 filenameA, 1, &status);
1508 if (image)
1509 assembly = mono_assembly_load_from(image, filenameA, &status);
1511 if (assembly)
1513 mono_callspec_set_assembly(assembly);
1515 exit_code = mono_jit_exec(domain, assembly, argc, argv);
1517 else
1519 ERR("couldn't load %s, status=%d\n", debugstr_w(filename), status);
1520 exit_code = -1;
1523 else
1524 exit_code = -1;
1526 ICLRRuntimeInfo_Release(info);
1528 else
1529 exit_code = -1;
1531 HeapFree(GetProcessHeap(), 0, argv);
1533 if (domain)
1535 mono_thread_manage();
1536 mono_runtime_quit();
1539 ExitProcess(exit_code);
1541 return exit_code;
1544 BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1546 ASSEMBLY *assembly=NULL;
1547 HRESULT hr;
1549 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1551 hr = assembly_from_hmodule(&assembly, hinstDLL);
1552 if (SUCCEEDED(hr))
1554 NativeEntryPointFunc NativeEntryPoint=NULL;
1556 assembly_get_native_entrypoint(assembly, &NativeEntryPoint);
1557 if (fdwReason == DLL_PROCESS_ATTACH)
1559 if (!NativeEntryPoint)
1560 DisableThreadLibraryCalls(hinstDLL);
1561 FixupVTable_Assembly(hinstDLL,assembly);
1563 assembly_release(assembly);
1564 /* FIXME: clean up the vtables on DLL_PROCESS_DETACH */
1565 if (NativeEntryPoint)
1566 return NativeEntryPoint(hinstDLL, fdwReason, lpvReserved);
1568 else
1569 ERR("failed to read CLR headers, hr=%x\n", hr);
1571 return TRUE;
1574 /* called from DLL_PROCESS_ATTACH */
1575 void runtimehost_init(void)
1577 dll_fixup_heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
1578 list_init(&dll_fixups);
1581 /* called from DLL_PROCESS_DETACH */
1582 void runtimehost_uninit(void)
1584 struct dll_fixup *fixup, *fixup2;
1586 HeapDestroy(dll_fixup_heap);
1587 LIST_FOR_EACH_ENTRY_SAFE(fixup, fixup2, &dll_fixups, struct dll_fixup, entry)
1589 HeapFree(GetProcessHeap(), 0, fixup->tokens);
1590 HeapFree(GetProcessHeap(), 0, fixup);
1594 HRESULT RuntimeHost_Construct(CLRRuntimeInfo *runtime_version, RuntimeHost** result)
1596 RuntimeHost *This;
1598 This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1599 if ( !This )
1600 return E_OUTOFMEMORY;
1602 This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
1603 This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
1605 This->ref = 1;
1606 This->version = runtime_version;
1607 InitializeCriticalSection(&This->lock);
1608 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
1610 *result = This;
1612 return S_OK;
1615 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
1617 IUnknown *unk;
1618 HRESULT hr;
1620 if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
1622 unk = (IUnknown*)&This->ICorRuntimeHost_iface;
1623 IUnknown_AddRef(unk);
1625 else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
1627 unk = (IUnknown*)&This->ICLRRuntimeHost_iface;
1628 IUnknown_AddRef(unk);
1630 else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
1631 IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
1633 hr = MetaDataDispenser_CreateInstance(&unk);
1634 if (FAILED(hr))
1635 return hr;
1637 else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
1639 hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
1640 if (FAILED(hr))
1641 return hr;
1643 else
1644 unk = NULL;
1646 if (unk)
1648 hr = IUnknown_QueryInterface(unk, riid, ppv);
1650 IUnknown_Release(unk);
1652 return hr;
1654 else
1655 FIXME("not implemented for class %s\n", debugstr_guid(clsid));
1657 return CLASS_E_CLASSNOTAVAILABLE;
1660 static BOOL try_create_registration_free_com(REFIID clsid, WCHAR *classname, UINT classname_size, WCHAR *filename, UINT filename_size)
1662 ACTCTX_SECTION_KEYED_DATA guid_info = { sizeof(ACTCTX_SECTION_KEYED_DATA) };
1663 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *assembly_info = NULL;
1664 SIZE_T bytes_assembly_info;
1665 struct comclassredirect_data *redirect_data;
1666 struct clrclass_data *class_data;
1667 void *ptr_name;
1668 const WCHAR *ptr_path_start, *ptr_path_end;
1669 WCHAR path[MAX_PATH] = {0};
1670 WCHAR str_dll[] = {'.','d','l','l',0};
1671 BOOL ret = FALSE;
1673 if (!FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, 0, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, clsid, &guid_info))
1675 DWORD error = GetLastError();
1676 if (error != ERROR_SXS_KEY_NOT_FOUND)
1677 ERR("Failed to find guid: %d\n", error);
1678 goto end;
1681 QueryActCtxW(0, guid_info.hActCtx, &guid_info.ulAssemblyRosterIndex, AssemblyDetailedInformationInActivationContext, NULL, 0, &bytes_assembly_info);
1682 assembly_info = heap_alloc(bytes_assembly_info);
1683 if (!QueryActCtxW(0, guid_info.hActCtx, &guid_info.ulAssemblyRosterIndex,
1684 AssemblyDetailedInformationInActivationContext, assembly_info, bytes_assembly_info, &bytes_assembly_info))
1686 ERR("QueryActCtxW failed: %d!\n", GetLastError());
1687 goto end;
1690 redirect_data = guid_info.lpData;
1691 class_data = (void *)((char *)redirect_data + redirect_data->clrdata_offset);
1693 ptr_name = (char *)class_data + class_data->name_offset;
1694 if (lstrlenW(ptr_name) + 1 > classname_size) /* Include null-terminator */
1696 ERR("Buffer is too small\n");
1697 goto end;
1699 lstrcpyW(classname, ptr_name);
1701 ptr_path_start = assembly_info->lpAssemblyEncodedAssemblyIdentity;
1702 ptr_path_end = wcschr(ptr_path_start, ',');
1703 memcpy(path, ptr_path_start, (char*)ptr_path_end - (char*)ptr_path_start);
1705 GetModuleFileNameW(NULL, filename, filename_size);
1706 PathRemoveFileSpecW(filename);
1708 if (lstrlenW(filename) + lstrlenW(path) + ARRAY_SIZE(str_dll) + 1 > filename_size) /* Include blackslash */
1710 ERR("Buffer is too small\n");
1711 goto end;
1714 PathAppendW(filename, path);
1715 lstrcatW(filename, str_dll);
1717 ret = TRUE;
1719 end:
1720 heap_free(assembly_info);
1722 if (guid_info.hActCtx)
1723 ReleaseActCtx(guid_info.hActCtx);
1725 return ret;
1728 #define CHARS_IN_GUID 39
1730 HRESULT create_monodata(REFIID riid, LPVOID *ppObj )
1732 static const WCHAR wszAssembly[] = {'A','s','s','e','m','b','l','y',0};
1733 static const WCHAR wszCodebase[] = {'C','o','d','e','B','a','s','e',0};
1734 static const WCHAR wszClass[] = {'C','l','a','s','s',0};
1735 static const WCHAR wszFileSlash[] = {'f','i','l','e',':','/','/','/',0};
1736 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1737 static const WCHAR wszInprocServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1738 static const WCHAR wszDLL[] = {'.','d','l','l',0};
1739 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(wszCLSIDSlash) + ARRAY_SIZE(wszInprocServer32) - 1];
1740 MonoDomain *domain;
1741 MonoAssembly *assembly;
1742 ICLRRuntimeInfo *info = NULL;
1743 RuntimeHost *host;
1744 HRESULT hr;
1745 HKEY key, subkey;
1746 LONG res;
1747 int offset = 0;
1748 HANDLE file = INVALID_HANDLE_VALUE;
1749 DWORD numKeys, keyLength;
1750 WCHAR codebase[MAX_PATH + 8];
1751 WCHAR classname[350], subkeyName[256];
1752 WCHAR filename[MAX_PATH];
1754 DWORD dwBufLen = 350;
1756 lstrcpyW(path, wszCLSIDSlash);
1757 StringFromGUID2(riid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
1758 lstrcatW(path, wszInprocServer32);
1760 TRACE("Registry key: %s\n", debugstr_w(path));
1762 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key);
1763 if (res != ERROR_FILE_NOT_FOUND)
1765 res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen);
1766 if(res != ERROR_SUCCESS)
1768 WARN("Class value cannot be found.\n");
1769 hr = CLASS_E_CLASSNOTAVAILABLE;
1770 goto cleanup;
1773 TRACE("classname (%s)\n", debugstr_w(classname));
1775 dwBufLen = MAX_PATH + 8;
1776 res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen);
1777 if(res == ERROR_SUCCESS)
1779 /* Strip file:/// */
1780 if(wcsncmp(codebase, wszFileSlash, lstrlenW(wszFileSlash)) == 0)
1781 offset = lstrlenW(wszFileSlash);
1783 lstrcpyW(filename, codebase + offset);
1785 file = CreateFileW(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
1788 if (file != INVALID_HANDLE_VALUE)
1789 CloseHandle(file);
1790 else
1792 WCHAR assemblyname[MAX_PATH + 8];
1794 hr = CLASS_E_CLASSNOTAVAILABLE;
1795 WARN("CodeBase value cannot be found, trying Assembly.\n");
1796 /* get the last subkey of InprocServer32 */
1797 res = RegQueryInfoKeyW(key, 0, 0, 0, &numKeys, 0, 0, 0, 0, 0, 0, 0);
1798 if (res != ERROR_SUCCESS)
1799 goto cleanup;
1800 if (numKeys > 0)
1802 numKeys--;
1803 keyLength = ARRAY_SIZE(subkeyName);
1804 res = RegEnumKeyExW(key, numKeys, subkeyName, &keyLength, 0, 0, 0, 0);
1805 if (res != ERROR_SUCCESS)
1806 goto cleanup;
1807 res = RegOpenKeyExW(key, subkeyName, 0, KEY_READ, &subkey);
1808 if (res != ERROR_SUCCESS)
1809 goto cleanup;
1810 dwBufLen = MAX_PATH + 8;
1811 res = RegGetValueW(subkey, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen);
1812 RegCloseKey(subkey);
1813 if (res != ERROR_SUCCESS)
1814 goto cleanup;
1816 else
1818 dwBufLen = MAX_PATH + 8;
1819 res = RegGetValueW(key, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen);
1820 if (res != ERROR_SUCCESS)
1821 goto cleanup;
1824 hr = get_file_from_strongname(assemblyname, filename, MAX_PATH);
1825 if (FAILED(hr))
1828 * The registry doesn't have a CodeBase entry or the file isn't there, and it's not in the GAC.
1830 * Use the Assembly Key to retrieve the filename.
1831 * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null
1833 WCHAR *ns;
1835 WARN("Attempt to load from the application directory.\n");
1836 GetModuleFileNameW(NULL, filename, MAX_PATH);
1837 ns = wcsrchr(filename, '\\');
1838 *(ns+1) = '\0';
1840 ns = wcschr(assemblyname, ',');
1841 *(ns) = '\0';
1842 lstrcatW(filename, assemblyname);
1843 *(ns) = '.';
1844 lstrcatW(filename, wszDLL);
1848 else
1850 if (!try_create_registration_free_com(riid, classname, ARRAY_SIZE(classname), filename, ARRAY_SIZE(filename)))
1851 return CLASS_E_CLASSNOTAVAILABLE;
1853 TRACE("classname (%s)\n", debugstr_w(classname));
1856 TRACE("filename (%s)\n", debugstr_w(filename));
1858 *ppObj = NULL;
1861 hr = get_runtime_info(filename, NULL, NULL, NULL, 0, 0, FALSE, &info);
1862 if (SUCCEEDED(hr))
1864 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1866 if (SUCCEEDED(hr))
1867 hr = RuntimeHost_GetDefaultDomain(host, NULL, &domain);
1869 if (SUCCEEDED(hr))
1871 MonoImage *image;
1872 MonoClass *klass;
1873 MonoObject *result;
1874 MonoDomain *prev_domain;
1875 MonoImageOpenStatus status;
1876 IUnknown *unk = NULL;
1877 char *filenameA, *ns;
1878 char *classA;
1880 hr = CLASS_E_CLASSNOTAVAILABLE;
1882 prev_domain = domain_attach(domain);
1884 filenameA = WtoA(filename);
1885 assembly = mono_assembly_open(filenameA, &status);
1886 HeapFree(GetProcessHeap(), 0, filenameA);
1887 if (!assembly)
1889 ERR("Cannot open assembly %s, status=%i\n", filenameA, status);
1890 domain_restore(prev_domain);
1891 goto cleanup;
1894 image = mono_assembly_get_image(assembly);
1895 if (!image)
1897 ERR("Couldn't get assembly image\n");
1898 domain_restore(prev_domain);
1899 goto cleanup;
1902 classA = WtoA(classname);
1903 ns = strrchr(classA, '.');
1904 *ns = '\0';
1906 klass = mono_class_from_name(image, classA, ns+1);
1907 HeapFree(GetProcessHeap(), 0, classA);
1908 if (!klass)
1910 ERR("Couldn't get class from image\n");
1911 domain_restore(prev_domain);
1912 goto cleanup;
1916 * Use the default constructor for the .NET class.
1918 result = mono_object_new(domain, klass);
1919 mono_runtime_object_init(result);
1921 hr = RuntimeHost_GetIUnknownForObject(host, result, &unk);
1922 if (SUCCEEDED(hr))
1924 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj);
1926 IUnknown_Release(unk);
1928 else
1929 hr = CLASS_E_CLASSNOTAVAILABLE;
1931 domain_restore(prev_domain);
1933 else
1934 hr = CLASS_E_CLASSNOTAVAILABLE;
1936 else
1937 hr = CLASS_E_CLASSNOTAVAILABLE;
1939 cleanup:
1940 if(info)
1941 ICLRRuntimeInfo_Release(info);
1943 RegCloseKey(key);
1945 return hr;