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
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
);
48 DEFINE_GUID(IID__AppDomain
, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13);
56 static HANDLE dll_fixup_heap
; /* using a separate heap so we can have execute permission */
58 static struct list dll_fixups
;
65 void *thunk_code
; /* pointer into dll_fixup_heap */
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. */
79 mono_thread_attach(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
;
95 EnterCriticalSection(&This
->lock
);
97 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
104 /* FIXME: Use exe filename to name the domain? */
105 entry
->domain
= mono_jit_init_version("mscorlib.dll", "v4.0.30319");
109 HeapFree(GetProcessHeap(), 0, entry
);
114 is_mono_started
= TRUE
;
116 list_add_tail(&This
->domains
, &entry
->entry
);
118 *result
= entry
->domain
;
121 LeaveCriticalSection(&This
->lock
);
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
;
133 EnterCriticalSection(&This
->lock
);
135 if (This
->default_domain
) goto end
;
137 res
= RuntimeHost_AddDefaultDomain(This
, &This
->default_domain
);
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
,
150 lstrcatW(config_dir
, machine_configW
);
152 config_path
= config_dir
;
155 config_pathA
= WtoA(config_path
);
162 GetModuleFileNameW(NULL
, base_dir
, sizeof(base_dir
) / sizeof(*base_dir
));
163 base_dirA
= WtoA(base_dir
);
166 HeapFree(GetProcessHeap(), 0, config_pathA
);
171 slash
= strrchr(base_dirA
, '\\');
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
);
182 *result
= This
->default_domain
;
184 LeaveCriticalSection(&This
->lock
);
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
);
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
,
214 MonoAssembly
*assembly
;
218 assembly
= mono_domain_assembly_open(domain
, assemblyname
);
221 ERR("Cannot load assembly %s\n", assemblyname
);
225 image
= mono_assembly_get_image(assembly
);
228 ERR("Couldn't get assembly image for %s\n", assemblyname
);
232 klass
= mono_class_from_name(image
, namespace, typename
);
235 ERR("Couldn't get class %s.%s from image\n", namespace, typename
);
239 *method
= mono_class_get_method_from_name(klass
, methodname
, arg_count
);
242 ERR("Couldn't get method %s from class %s.%s\n", methodname
, namespace, typename
);
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
)
257 static const char *get_hresult
= "get_HResult";
259 *result
= mono_runtime_invoke(method
, obj
, args
, &exc
);
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
);
271 hr
= *(HRESULT
*)mono_object_unbox(hr_object
);
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
)
289 MonoDomain
*prev_domain
;
294 prev_domain
= domain_attach(domain
);
296 if (!RuntimeHost_GetMethod(domain
, assemblyname
, namespace, typename
, methodname
,
299 domain_restore(prev_domain
);
303 hr
= RuntimeHost_DoInvoke(This
, domain
, methodname
, method
, obj
, args
, result
);
306 ERR("Method %s.%s:%s raised an exception, hr=%x\n", namespace, typename
, methodname
, hr
);
309 domain_restore(prev_domain
);
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
)
319 MonoDomain
*prev_domain
;
326 ERR("\"this\" object cannot be null\n");
330 prev_domain
= domain_attach(domain
);
332 if (!RuntimeHost_GetMethod(domain
, assemblyname
, namespace, typename
, methodname
,
335 domain_restore(prev_domain
);
339 method
= mono_object_get_virtual_method(obj
, method
);
342 ERR("Object %p does not support method %s.%s:%s\n", obj
, namespace, typename
, methodname
);
343 domain_restore(prev_domain
);
347 hr
= RuntimeHost_DoInvoke(This
, domain
, methodname
, method
, obj
, args
, result
);
350 ERR("Method %s.%s:%s raised an exception, hr=%x\n", namespace, typename
, methodname
, hr
);
353 domain_restore(prev_domain
);
358 static HRESULT
RuntimeHost_GetObjectForIUnknown(RuntimeHost
*This
, MonoDomain
*domain
,
359 IUnknown
*unk
, MonoObject
**obj
)
366 hr
= RuntimeHost_Invoke(This
, domain
, "mscorlib", "System.Runtime.InteropServices", "Marshal", "GetObjectForIUnknown",
367 NULL
, args
, 1, &result
);
376 static HRESULT
RuntimeHost_AddDomain(RuntimeHost
*This
, const WCHAR
*name
, IUnknown
*setup
,
377 IUnknown
*evidence
, MonoDomain
**result
)
383 MonoObject
*new_domain
, *id
;
385 res
= RuntimeHost_GetDefaultDomain(This
, NULL
, &domain
);
394 return E_OUTOFMEMORY
;
397 args
[0] = mono_string_new(domain
, nameA
);
398 HeapFree(GetProcessHeap(), 0, nameA
);
402 return E_OUTOFMEMORY
;
407 res
= RuntimeHost_GetObjectForIUnknown(This
, domain
, evidence
, (MonoObject
**)&args
[1]);
420 res
= RuntimeHost_GetObjectForIUnknown(This
, domain
, setup
, (MonoObject
**)&args
[2]);
431 res
= RuntimeHost_Invoke(This
, domain
, "mscorlib", "System", "AppDomain", "CreateDomain",
432 NULL
, args
, 3, &new_domain
);
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
);
453 TRACE("returning domain id %d\n", *(int *)mono_object_unbox(id
));
455 *result
= mono_domain_get_by_id(*(int *)mono_object_unbox(id
));
460 static HRESULT
RuntimeHost_GetIUnknownForDomain(RuntimeHost
*This
, MonoDomain
*domain
, IUnknown
**punk
)
463 MonoObject
*appdomain_object
;
466 hr
= RuntimeHost_Invoke(This
, domain
, "mscorlib", "System", "AppDomain", "get_CurrentDomain",
467 NULL
, NULL
, 0, &appdomain_object
);
470 hr
= RuntimeHost_GetIUnknownForObject(This
, appdomain_object
, &unk
);
474 hr
= IUnknown_QueryInterface(unk
, &IID__AppDomain
, (void**)punk
);
476 IUnknown_Release(unk
);
482 void RuntimeHost_ExitProcess(RuntimeHost
*This
, INT exitcode
)
489 hr
= RuntimeHost_GetDefaultDomain(This
, NULL
, &domain
);
492 ERR("Cannot get domain, hr=%x\n", hr
);
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
,
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
) )
529 FIXME("Unsupported interface %s\n", debugstr_guid(riid
));
530 return E_NOINTERFACE
;
533 ICorRuntimeHost_AddRef( iface
);
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
);
550 ref
= InterlockedDecrement( &This
->ref
);
555 /*** ICorRuntimeHost methods ***/
556 static HRESULT WINAPI
corruntimehost_CreateLogicalThreadState(
557 ICorRuntimeHost
* iface
)
559 FIXME("stub %p\n", iface
);
563 static HRESULT WINAPI
corruntimehost_DeleteLogicalThreadState(
564 ICorRuntimeHost
* iface
)
566 FIXME("stub %p\n", iface
);
570 static HRESULT WINAPI
corruntimehost_SwitchInLogicalThreadState(
571 ICorRuntimeHost
* iface
,
574 FIXME("stub %p\n", iface
);
578 static HRESULT WINAPI
corruntimehost_SwitchOutLogicalThreadState(
579 ICorRuntimeHost
* iface
,
582 FIXME("stub %p\n", iface
);
586 static HRESULT WINAPI
corruntimehost_LocksHeldByLogicalThread(
587 ICorRuntimeHost
* iface
,
590 FIXME("stub %p\n", iface
);
594 static HRESULT WINAPI
corruntimehost_MapFile(
595 ICorRuntimeHost
* iface
,
599 FIXME("stub %p\n", iface
);
603 static HRESULT WINAPI
corruntimehost_GetConfiguration(
604 ICorRuntimeHost
* iface
,
605 ICorConfiguration
**pConfiguration
)
607 FIXME("stub %p\n", iface
);
611 static HRESULT WINAPI
corruntimehost_Start(
612 ICorRuntimeHost
* iface
)
614 RuntimeHost
*This
= impl_from_ICorRuntimeHost( iface
);
619 return RuntimeHost_GetDefaultDomain(This
, NULL
, &dummy
);
622 static HRESULT WINAPI
corruntimehost_Stop(
623 ICorRuntimeHost
* iface
)
625 FIXME("stub %p\n", iface
);
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
);
646 TRACE("(%p)\n", iface
);
648 hr
= RuntimeHost_GetDefaultDomain(This
, NULL
, &domain
);
652 hr
= RuntimeHost_GetIUnknownForDomain(This
, domain
, pAppDomain
);
658 static HRESULT WINAPI
corruntimehost_EnumDomains(
659 ICorRuntimeHost
* iface
,
662 FIXME("stub %p\n", iface
);
666 static HRESULT WINAPI
corruntimehost_NextDomain(
667 ICorRuntimeHost
* iface
,
669 IUnknown
**appDomain
)
671 FIXME("stub %p\n", iface
);
675 static HRESULT WINAPI
corruntimehost_CloseEnum(
676 ICorRuntimeHost
* iface
,
679 FIXME("stub %p\n", iface
);
683 static HRESULT WINAPI
corruntimehost_CreateDomainEx(
684 ICorRuntimeHost
* iface
,
685 LPCWSTR friendlyName
,
688 IUnknown
**appDomain
)
690 RuntimeHost
*This
= impl_from_ICorRuntimeHost( iface
);
694 if (!friendlyName
|| !appDomain
)
698 if (!is_mono_started
)
703 TRACE("(%p)\n", iface
);
705 hr
= RuntimeHost_AddDomain(This
, friendlyName
, setup
, evidence
, &domain
);
709 hr
= RuntimeHost_GetIUnknownForDomain(This
, domain
, appDomain
);
715 static HRESULT WINAPI
corruntimehost_CreateDomainSetup(
716 ICorRuntimeHost
* iface
,
717 IUnknown
**appDomainSetup
)
719 RuntimeHost
*This
= impl_from_ICorRuntimeHost( iface
);
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
);
730 hr
= RuntimeHost_CreateManagedInstance(This
, classnameW
, domain
, &obj
);
733 hr
= RuntimeHost_GetIUnknownForObject(This
, obj
, appDomainSetup
);
738 static HRESULT WINAPI
corruntimehost_CreateEvidence(
739 ICorRuntimeHost
* iface
,
742 FIXME("stub %p\n", iface
);
746 static HRESULT WINAPI
corruntimehost_UnloadDomain(
747 ICorRuntimeHost
* iface
,
750 FIXME("stub %p\n", iface
);
754 static HRESULT WINAPI
corruntimehost_CurrentDomain(
755 ICorRuntimeHost
* iface
,
756 IUnknown
**appDomain
)
758 FIXME("stub %p\n", iface
);
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
,
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
,
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
) )
802 FIXME("Unsupported interface %s\n", debugstr_guid(riid
));
803 return E_NOINTERFACE
;
806 ICLRRuntimeHost_AddRef( iface
);
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
);
829 static HRESULT WINAPI
CLRRuntimeHost_Stop(ICLRRuntimeHost
* iface
)
831 FIXME("(%p)\n", iface
);
835 static HRESULT WINAPI
CLRRuntimeHost_SetHostControl(ICLRRuntimeHost
* iface
,
836 IHostControl
*pHostControl
)
838 FIXME("(%p,%p)\n", iface
, pHostControl
);
842 static HRESULT WINAPI
CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost
* iface
,
843 ICLRControl
**pCLRControl
)
845 FIXME("(%p,%p)\n", iface
, pCLRControl
);
849 static HRESULT WINAPI
CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost
* iface
,
850 DWORD dwAppDomainId
, BOOL fWaitUntilDone
)
852 FIXME("(%p,%u,%i)\n", iface
, dwAppDomainId
, fWaitUntilDone
);
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
);
863 static HRESULT WINAPI
CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost
* iface
,
864 DWORD
*pdwAppDomainId
)
866 FIXME("(%p,%p)\n", iface
, pdwAppDomainId
);
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
);
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
);
884 MonoDomain
*domain
, *prev_domain
;
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
);
898 prev_domain
= domain_attach(domain
);
902 filenameA
= WtoA(pwzAssemblyPath
);
903 if (!filenameA
) hr
= E_OUTOFMEMORY
;
908 classA
= WtoA(pwzTypeName
);
909 if (!classA
) hr
= E_OUTOFMEMORY
;
914 ns
= strrchr(classA
, '.');
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)
932 argsA
= WtoA(pwzArgument
);
933 if (!argsA
) hr
= E_OUTOFMEMORY
;
938 str
= mono_string_new(domain
, argsA
);
939 if (!str
) hr
= E_OUTOFMEMORY
;
944 hr
= RuntimeHost_Invoke(This
, domain
, filenameA
, classA
, ns
+1, methodA
,
945 NULL
, (void**)&str
, 1, &result
);
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
);
961 static const struct ICLRRuntimeHostVtbl CLRHostVtbl
=
963 CLRRuntimeHost_QueryInterface
,
964 CLRRuntimeHost_AddRef
,
965 CLRRuntimeHost_Release
,
966 CLRRuntimeHost_Start
,
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
)
988 MonoDomain
*prev_domain
;
991 hr
= RuntimeHost_GetDefaultDomain(This
, NULL
, &domain
);
996 prev_domain
= domain_attach(domain
);
1007 type
= mono_reflection_type_from_name(nameA
, NULL
);
1010 ERR("Cannot find type %s\n", debugstr_w(name
));
1017 klass
= mono_class_from_mono_type(type
);
1020 ERR("Cannot convert type %s to a class\n", debugstr_w(name
));
1027 obj
= mono_object_new(domain
, klass
);
1030 ERR("Cannot allocate object of type %s\n", debugstr_w(name
));
1037 /* FIXME: Detect exceptions from the constructor? */
1038 mono_runtime_object_init(obj
);
1042 domain_restore(prev_domain
);
1044 HeapFree(GetProcessHeap(), 0, nameA
);
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
,
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
);
1070 *ppUnk
= *(IUnknown
**)mono_object_unbox(result
);
1077 static void get_utf8_args(int *argc
, char ***argv
)
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
);
1108 # define CAN_FIXUP_VTABLE 1
1110 #include "pshpack1.h"
1112 struct vtable_fixup_thunk
1118 /* mov fixup,(%esp) */
1120 struct dll_fixup
*fixup
;
1121 /* mov function,%eax */
1123 void (CDECL
*function
)(struct dll_fixup
*);
1130 /* jmp *vtable_entry */
1135 static const struct vtable_fixup_thunk thunk_template
= {
1149 #include "poppack.h"
1151 #elif __x86_64__ /* !__i386__ */
1153 # define CAN_FIXUP_VTABLE 1
1155 #include "pshpack1.h"
1157 struct vtable_fixup_thunk
1161 sub $0x80, %rsp ; 0x8*4 + 0x10*4 + 0x20
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)
1169 /* mov function,%rax */
1171 void (CDECL
*function
)(struct dll_fixup
*);
1172 /* mov fixup,%rcx */
1174 struct dll_fixup
*fixup
;
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
1186 /* mov vtable_entry, %rax */
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,
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},
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
);
1230 static const struct vtable_fixup_thunk thunk_template
= {0};
1234 static void CDECL
ReallyFixupVTable(struct dll_fixup
*fixup
)
1237 WCHAR filename
[MAX_PATH
];
1238 ICLRRuntimeInfo
*info
=NULL
;
1241 MonoImage
*image
=NULL
;
1242 MonoAssembly
*assembly
=NULL
;
1243 MonoImageOpenStatus status
=0;
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
);
1260 hr
= get_runtime_info(filename
, NULL
, NULL
, 0, 0, FALSE
, &info
);
1263 hr
= ICLRRuntimeInfo_GetRuntimeHost(info
, &host
);
1266 hr
= RuntimeHost_GetDefaultDomain(host
, NULL
, &domain
);
1270 MonoDomain
*prev_domain
;
1272 prev_domain
= domain_attach(domain
);
1274 assembly
= mono_assembly_open(filenameA
, &status
);
1280 /* Mono needs an image that belongs to an assembly. */
1281 image
= mono_assembly_get_image(assembly
);
1284 if (fixup
->fixup
->type
& COR_VTABLE_64BIT
)
1286 if (fixup
->fixup
->type
& COR_VTABLE_32BIT
)
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
);
1302 domain_restore(prev_domain
);
1306 ICLRRuntimeInfo_Release(info
);
1308 HeapFree(GetProcessHeap(), 0, filenameA
);
1312 ERR("unable to fixup vtable, hr=%x, status=%d\n", hr
, status
);
1313 /* If we returned now, we'd get an infinite loop. */
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
);
1339 if (vtable_fixup
->type
& COR_VTABLE_64BIT
)
1341 if (vtable_fixup
->type
& COR_VTABLE_32BIT
)
1344 void **vtable
= fixup
->vtable
;
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
];
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
);
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
)
1389 hr
= assembly_from_hmodule(&assembly
, hmodule
);
1392 FixupVTable_Assembly(hmodule
, assembly
);
1393 assembly_release(assembly
);
1396 ERR("failed to read CLR headers, hr=%x\n", hr
);
1399 __int32 WINAPI
_CorExeMain(void)
1404 MonoDomain
*domain
=NULL
;
1406 MonoImageOpenStatus status
;
1407 MonoAssembly
*assembly
=NULL
;
1408 WCHAR filename
[MAX_PATH
];
1410 ICLRRuntimeInfo
*info
;
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
]));
1424 filenameA
= WtoA(filename
);
1428 FixupVTable(GetModuleHandleW(NULL
));
1430 hr
= get_runtime_info(filename
, NULL
, NULL
, 0, 0, FALSE
, &info
);
1434 hr
= ICLRRuntimeInfo_GetRuntimeHost(info
, &host
);
1438 WCHAR config_file
[MAX_PATH
];
1439 static const WCHAR dotconfig
[] = {'.','c','o','n','f','i','g',0};
1441 strcpyW(config_file
, filename
);
1442 strcatW(config_file
, dotconfig
);
1444 hr
= RuntimeHost_GetDefaultDomain(host
, config_file
, &domain
);
1449 image
= mono_image_open_from_module_handle(GetModuleHandleW(NULL
),
1450 filenameA
, 1, &status
);
1453 assembly
= mono_assembly_load_from(image
, filenameA
, &status
);
1457 mono_trace_set_assembly(assembly
);
1459 exit_code
= mono_jit_exec(domain
, assembly
, argc
, argv
);
1463 ERR("couldn't load %s, status=%d\n", debugstr_w(filename
), status
);
1467 RuntimeHost_DeleteDomain(host
, domain
);
1472 ICLRRuntimeInfo_Release(info
);
1477 HeapFree(GetProcessHeap(), 0, argv
);
1481 mono_thread_manage();
1482 mono_runtime_quit();
1488 BOOL WINAPI
_CorDllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
1490 ASSEMBLY
*assembly
=NULL
;
1493 TRACE("(%p, %d, %p)\n", hinstDLL
, fdwReason
, lpvReserved
);
1495 hr
= assembly_from_hmodule(&assembly
, hinstDLL
);
1498 NativeEntryPointFunc NativeEntryPoint
=NULL
;
1500 assembly_get_native_entrypoint(assembly
, &NativeEntryPoint
);
1501 if (fdwReason
== DLL_PROCESS_ATTACH
)
1503 if (!NativeEntryPoint
)
1504 DisableThreadLibraryCalls(hinstDLL
);
1505 FixupVTable_Assembly(hinstDLL
,assembly
);
1507 assembly_release(assembly
);
1508 /* FIXME: clean up the vtables on DLL_PROCESS_DETACH */
1509 if (NativeEntryPoint
)
1510 return NativeEntryPoint(hinstDLL
, fdwReason
, lpvReserved
);
1513 ERR("failed to read CLR headers, hr=%x\n", hr
);
1518 /* called from DLL_PROCESS_ATTACH */
1519 void runtimehost_init(void)
1521 dll_fixup_heap
= HeapCreate(HEAP_CREATE_ENABLE_EXECUTE
, 0, 0);
1522 list_init(&dll_fixups
);
1525 /* called from DLL_PROCESS_DETACH */
1526 void runtimehost_uninit(void)
1528 struct dll_fixup
*fixup
, *fixup2
;
1530 HeapDestroy(dll_fixup_heap
);
1531 LIST_FOR_EACH_ENTRY_SAFE(fixup
, fixup2
, &dll_fixups
, struct dll_fixup
, entry
)
1533 HeapFree(GetProcessHeap(), 0, fixup
->tokens
);
1534 HeapFree(GetProcessHeap(), 0, fixup
);
1538 HRESULT
RuntimeHost_Construct(CLRRuntimeInfo
*runtime_version
, RuntimeHost
** result
)
1542 This
= HeapAlloc( GetProcessHeap(), 0, sizeof *This
);
1544 return E_OUTOFMEMORY
;
1546 This
->ICorRuntimeHost_iface
.lpVtbl
= &corruntimehost_vtbl
;
1547 This
->ICLRRuntimeHost_iface
.lpVtbl
= &CLRHostVtbl
;
1550 This
->version
= runtime_version
;
1551 list_init(&This
->domains
);
1552 This
->default_domain
= NULL
;
1553 InitializeCriticalSection(&This
->lock
);
1554 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": RuntimeHost.lock");
1561 HRESULT
RuntimeHost_GetInterface(RuntimeHost
*This
, REFCLSID clsid
, REFIID riid
, void **ppv
)
1566 if (IsEqualGUID(clsid
, &CLSID_CorRuntimeHost
))
1568 unk
= (IUnknown
*)&This
->ICorRuntimeHost_iface
;
1569 IUnknown_AddRef(unk
);
1571 else if (IsEqualGUID(clsid
, &CLSID_CLRRuntimeHost
))
1573 unk
= (IUnknown
*)&This
->ICLRRuntimeHost_iface
;
1574 IUnknown_AddRef(unk
);
1576 else if (IsEqualGUID(clsid
, &CLSID_CorMetaDataDispenser
) ||
1577 IsEqualGUID(clsid
, &CLSID_CorMetaDataDispenserRuntime
))
1579 hr
= MetaDataDispenser_CreateInstance(&unk
);
1583 else if (IsEqualGUID(clsid
, &CLSID_CLRDebuggingLegacy
))
1585 hr
= CorDebug_Create(&This
->ICLRRuntimeHost_iface
, &unk
);
1594 hr
= IUnknown_QueryInterface(unk
, riid
, ppv
);
1596 IUnknown_Release(unk
);
1601 FIXME("not implemented for class %s\n", debugstr_guid(clsid
));
1603 return CLASS_E_CLASSNOTAVAILABLE
;
1606 #define CHARS_IN_GUID 39
1607 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
1609 HRESULT
create_monodata(REFIID riid
, LPVOID
*ppObj
)
1611 static const WCHAR wszAssembly
[] = {'A','s','s','e','m','b','l','y',0};
1612 static const WCHAR wszCodebase
[] = {'C','o','d','e','B','a','s','e',0};
1613 static const WCHAR wszClass
[] = {'C','l','a','s','s',0};
1614 static const WCHAR wszFileSlash
[] = {'f','i','l','e',':','/','/','/',0};
1615 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
1616 static const WCHAR wszInprocServer32
[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1617 static const WCHAR wszDLL
[] = {'.','d','l','l',0};
1618 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) + ARRAYSIZE(wszInprocServer32
) - 1];
1620 MonoAssembly
*assembly
;
1621 ICLRRuntimeInfo
*info
= NULL
;
1627 DWORD numKeys
, keyLength
;
1628 WCHAR codebase
[MAX_PATH
+ 8];
1629 WCHAR classname
[350], subkeyName
[256];
1630 WCHAR filename
[MAX_PATH
];
1632 DWORD dwBufLen
= 350;
1634 lstrcpyW(path
, wszCLSIDSlash
);
1635 StringFromGUID2(riid
, path
+ lstrlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
1636 lstrcatW(path
, wszInprocServer32
);
1638 TRACE("Registry key: %s\n", debugstr_w(path
));
1640 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, path
, 0, KEY_READ
, &key
);
1641 if (res
== ERROR_FILE_NOT_FOUND
)
1642 return CLASS_E_CLASSNOTAVAILABLE
;
1644 res
= RegGetValueW( key
, NULL
, wszClass
, RRF_RT_REG_SZ
, NULL
, classname
, &dwBufLen
);
1645 if(res
!= ERROR_SUCCESS
)
1647 WARN("Class value cannot be found.\n");
1648 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1652 TRACE("classname (%s)\n", debugstr_w(classname
));
1654 dwBufLen
= MAX_PATH
+ 8;
1655 res
= RegGetValueW( key
, NULL
, wszCodebase
, RRF_RT_REG_SZ
, NULL
, codebase
, &dwBufLen
);
1656 if(res
== ERROR_SUCCESS
)
1658 /* Strip file:/// */
1659 if(strncmpW(codebase
, wszFileSlash
, strlenW(wszFileSlash
)) == 0)
1660 offset
= strlenW(wszFileSlash
);
1662 strcpyW(filename
, codebase
+ offset
);
1666 WCHAR assemblyname
[MAX_PATH
+ 8];
1668 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1669 WARN("CodeBase value cannot be found, trying Assembly.\n");
1670 /* get the last subkey of InprocServer32 */
1671 res
= RegQueryInfoKeyW(key
, 0, 0, 0, &numKeys
, 0, 0, 0, 0, 0, 0, 0);
1672 if (res
!= ERROR_SUCCESS
|| numKeys
== 0)
1675 keyLength
= sizeof(subkeyName
) / sizeof(WCHAR
);
1676 res
= RegEnumKeyExW(key
, numKeys
, subkeyName
, &keyLength
, 0, 0, 0, 0);
1677 if (res
!= ERROR_SUCCESS
)
1679 res
= RegOpenKeyExW(key
, subkeyName
, 0, KEY_READ
, &subkey
);
1680 if (res
!= ERROR_SUCCESS
)
1682 dwBufLen
= MAX_PATH
+ 8;
1683 res
= RegGetValueW(subkey
, NULL
, wszAssembly
, RRF_RT_REG_SZ
, NULL
, assemblyname
, &dwBufLen
);
1684 RegCloseKey(subkey
);
1685 if (res
!= ERROR_SUCCESS
)
1688 hr
= get_file_from_strongname(assemblyname
, filename
, MAX_PATH
);
1692 * The registry doesn't have a CodeBase entry and it's not in the GAC.
1694 * Use the Assembly Key to retrieve the filename.
1695 * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null
1699 WARN("Attempt to load from the application directory.\n");
1700 GetModuleFileNameW(NULL
, filename
, MAX_PATH
);
1701 ns
= strrchrW(filename
, '\\');
1704 ns
= strchrW(assemblyname
, ',');
1706 strcatW(filename
, assemblyname
);
1708 strcatW(filename
, wszDLL
);
1712 TRACE("filename (%s)\n", debugstr_w(filename
));
1717 hr
= get_runtime_info(filename
, NULL
, NULL
, 0, 0, FALSE
, &info
);
1720 hr
= ICLRRuntimeInfo_GetRuntimeHost(info
, &host
);
1723 hr
= RuntimeHost_GetDefaultDomain(host
, NULL
, &domain
);
1730 MonoDomain
*prev_domain
;
1731 IUnknown
*unk
= NULL
;
1732 char *filenameA
, *ns
;
1735 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1737 prev_domain
= domain_attach(domain
);
1739 filenameA
= WtoA(filename
);
1740 assembly
= mono_domain_assembly_open(domain
, filenameA
);
1741 HeapFree(GetProcessHeap(), 0, filenameA
);
1744 ERR("Cannot open assembly %s\n", filenameA
);
1745 domain_restore(prev_domain
);
1749 image
= mono_assembly_get_image(assembly
);
1752 ERR("Couldn't get assembly image\n");
1753 domain_restore(prev_domain
);
1757 classA
= WtoA(classname
);
1758 ns
= strrchr(classA
, '.');
1761 klass
= mono_class_from_name(image
, classA
, ns
+1);
1762 HeapFree(GetProcessHeap(), 0, classA
);
1765 ERR("Couldn't get class from image\n");
1766 domain_restore(prev_domain
);
1771 * Use the default constructor for the .NET class.
1773 result
= mono_object_new(domain
, klass
);
1774 mono_runtime_object_init(result
);
1776 hr
= RuntimeHost_GetIUnknownForObject(host
, result
, &unk
);
1779 hr
= IUnknown_QueryInterface(unk
, &IID_IUnknown
, ppObj
);
1781 IUnknown_Release(unk
);
1784 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1786 domain_restore(prev_domain
);
1789 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1792 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1796 ICLRRuntimeInfo_Release(info
);