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 HRESULT
RuntimeHost_AddDomain(RuntimeHost
*This
, MonoDomain
**result
)
73 struct DomainEntry
*entry
;
76 EnterCriticalSection(&This
->lock
);
78 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
85 /* FIXME: Use exe filename to name the domain? */
86 entry
->domain
= mono_jit_init_version("mscorlib.dll", "v4.0.30319");
90 HeapFree(GetProcessHeap(), 0, entry
);
95 is_mono_started
= TRUE
;
97 list_add_tail(&This
->domains
, &entry
->entry
);
99 *result
= entry
->domain
;
102 LeaveCriticalSection(&This
->lock
);
107 static HRESULT
RuntimeHost_GetDefaultDomain(RuntimeHost
*This
, MonoDomain
**result
)
111 EnterCriticalSection(&This
->lock
);
113 if (This
->default_domain
) goto end
;
115 res
= RuntimeHost_AddDomain(This
, &This
->default_domain
);
118 *result
= This
->default_domain
;
120 LeaveCriticalSection(&This
->lock
);
125 static void RuntimeHost_DeleteDomain(RuntimeHost
*This
, MonoDomain
*domain
)
127 struct DomainEntry
*entry
;
129 EnterCriticalSection(&This
->lock
);
131 LIST_FOR_EACH_ENTRY(entry
, &This
->domains
, struct DomainEntry
, entry
)
133 if (entry
->domain
== domain
)
135 list_remove(&entry
->entry
);
136 if (This
->default_domain
== domain
)
137 This
->default_domain
= NULL
;
138 HeapFree(GetProcessHeap(), 0, entry
);
143 LeaveCriticalSection(&This
->lock
);
146 static HRESULT
RuntimeHost_Invoke(RuntimeHost
*This
, MonoDomain
*domain
,
147 const char *assemblyname
, const char *namespace, const char *typename
, const char *methodname
,
148 MonoObject
*obj
, void **args
, int arg_count
, MonoObject
**result
)
150 MonoAssembly
*assembly
;
155 static const char *get_hresult
= "get_HResult";
159 mono_thread_attach(domain
);
161 assembly
= mono_domain_assembly_open(domain
, assemblyname
);
164 ERR("Cannot load assembly\n");
168 image
= mono_assembly_get_image(assembly
);
171 ERR("Couldn't get assembly image\n");
175 klass
= mono_class_from_name(image
, namespace, typename
);
178 ERR("Couldn't get class from image\n");
182 method
= mono_class_get_method_from_name(klass
, methodname
, arg_count
);
185 ERR("Couldn't get method from class\n");
189 *result
= mono_runtime_invoke(method
, obj
, args
, &exc
);
193 MonoObject
*hr_object
;
195 if (methodname
!= get_hresult
)
197 /* Map the exception to an HRESULT. */
198 hr
= RuntimeHost_Invoke(This
, domain
, "mscorlib", "System", "Exception", get_hresult
,
199 exc
, NULL
, 0, &hr_object
);
201 hr
= *(HRESULT
*)mono_object_unbox(hr_object
);
207 ERR("Method %s.%s raised an exception, hr=%x\n", namespace, typename
, hr
);
215 static HRESULT
RuntimeHost_GetIUnknownForDomain(RuntimeHost
*This
, MonoDomain
*domain
, IUnknown
**punk
)
218 MonoObject
*appdomain_object
;
221 hr
= RuntimeHost_Invoke(This
, domain
, "mscorlib", "System", "AppDomain", "get_CurrentDomain",
222 NULL
, NULL
, 0, &appdomain_object
);
225 hr
= RuntimeHost_GetIUnknownForObject(This
, appdomain_object
, &unk
);
229 hr
= IUnknown_QueryInterface(unk
, &IID__AppDomain
, (void**)punk
);
231 IUnknown_Release(unk
);
237 void RuntimeHost_ExitProcess(RuntimeHost
*This
, INT exitcode
)
244 hr
= RuntimeHost_GetDefaultDomain(This
, &domain
);
247 ERR("Cannot get domain, hr=%x\n", hr
);
253 RuntimeHost_Invoke(This
, domain
, "mscorlib", "System", "Environment", "Exit",
254 NULL
, args
, 1, &dummy
);
256 ERR("Process should have exited\n");
259 static inline RuntimeHost
*impl_from_ICLRRuntimeHost( ICLRRuntimeHost
*iface
)
261 return CONTAINING_RECORD(iface
, RuntimeHost
, ICLRRuntimeHost_iface
);
264 static inline RuntimeHost
*impl_from_ICorRuntimeHost( ICorRuntimeHost
*iface
)
266 return CONTAINING_RECORD(iface
, RuntimeHost
, ICorRuntimeHost_iface
);
269 /*** IUnknown methods ***/
270 static HRESULT WINAPI
corruntimehost_QueryInterface(ICorRuntimeHost
* iface
,
274 RuntimeHost
*This
= impl_from_ICorRuntimeHost( iface
);
275 TRACE("%p %s %p\n", This
, debugstr_guid(riid
), ppvObject
);
277 if ( IsEqualGUID( riid
, &IID_ICorRuntimeHost
) ||
278 IsEqualGUID( riid
, &IID_IUnknown
) )
284 FIXME("Unsupported interface %s\n", debugstr_guid(riid
));
285 return E_NOINTERFACE
;
288 ICorRuntimeHost_AddRef( iface
);
293 static ULONG WINAPI
corruntimehost_AddRef(ICorRuntimeHost
* iface
)
295 RuntimeHost
*This
= impl_from_ICorRuntimeHost( iface
);
297 return InterlockedIncrement( &This
->ref
);
300 static ULONG WINAPI
corruntimehost_Release(ICorRuntimeHost
* iface
)
302 RuntimeHost
*This
= impl_from_ICorRuntimeHost( iface
);
305 ref
= InterlockedDecrement( &This
->ref
);
310 /*** ICorRuntimeHost methods ***/
311 static HRESULT WINAPI
corruntimehost_CreateLogicalThreadState(
312 ICorRuntimeHost
* iface
)
314 FIXME("stub %p\n", iface
);
318 static HRESULT WINAPI
corruntimehost_DeleteLogicalThreadState(
319 ICorRuntimeHost
* iface
)
321 FIXME("stub %p\n", iface
);
325 static HRESULT WINAPI
corruntimehost_SwitchInLogicalThreadState(
326 ICorRuntimeHost
* iface
,
329 FIXME("stub %p\n", iface
);
333 static HRESULT WINAPI
corruntimehost_SwitchOutLogicalThreadState(
334 ICorRuntimeHost
* iface
,
337 FIXME("stub %p\n", iface
);
341 static HRESULT WINAPI
corruntimehost_LocksHeldByLogicalThread(
342 ICorRuntimeHost
* iface
,
345 FIXME("stub %p\n", iface
);
349 static HRESULT WINAPI
corruntimehost_MapFile(
350 ICorRuntimeHost
* iface
,
354 FIXME("stub %p\n", iface
);
358 static HRESULT WINAPI
corruntimehost_GetConfiguration(
359 ICorRuntimeHost
* iface
,
360 ICorConfiguration
**pConfiguration
)
362 FIXME("stub %p\n", iface
);
366 static HRESULT WINAPI
corruntimehost_Start(
367 ICorRuntimeHost
* iface
)
369 RuntimeHost
*This
= impl_from_ICorRuntimeHost( iface
);
374 return RuntimeHost_GetDefaultDomain(This
, &dummy
);
377 static HRESULT WINAPI
corruntimehost_Stop(
378 ICorRuntimeHost
* iface
)
380 FIXME("stub %p\n", iface
);
384 static HRESULT WINAPI
corruntimehost_CreateDomain(
385 ICorRuntimeHost
* iface
,
386 LPCWSTR friendlyName
,
387 IUnknown
*identityArray
,
388 IUnknown
**appDomain
)
390 FIXME("stub %p\n", iface
);
394 static HRESULT WINAPI
corruntimehost_GetDefaultDomain(
395 ICorRuntimeHost
* iface
,
396 IUnknown
**pAppDomain
)
398 RuntimeHost
*This
= impl_from_ICorRuntimeHost( iface
);
402 TRACE("(%p)\n", iface
);
404 hr
= RuntimeHost_GetDefaultDomain(This
, &domain
);
408 hr
= RuntimeHost_GetIUnknownForDomain(This
, domain
, pAppDomain
);
414 static HRESULT WINAPI
corruntimehost_EnumDomains(
415 ICorRuntimeHost
* iface
,
418 FIXME("stub %p\n", iface
);
422 static HRESULT WINAPI
corruntimehost_NextDomain(
423 ICorRuntimeHost
* iface
,
425 IUnknown
**appDomain
)
427 FIXME("stub %p\n", iface
);
431 static HRESULT WINAPI
corruntimehost_CloseEnum(
432 ICorRuntimeHost
* iface
,
435 FIXME("stub %p\n", iface
);
439 static HRESULT WINAPI
corruntimehost_CreateDomainEx(
440 ICorRuntimeHost
* iface
,
441 LPCWSTR friendlyName
,
444 IUnknown
**appDomain
)
446 FIXME("stub %p\n", iface
);
450 static HRESULT WINAPI
corruntimehost_CreateDomainSetup(
451 ICorRuntimeHost
* iface
,
452 IUnknown
**appDomainSetup
)
454 RuntimeHost
*This
= impl_from_ICorRuntimeHost( iface
);
458 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};
460 TRACE("(%p)\n", iface
);
462 hr
= RuntimeHost_GetDefaultDomain(This
, &domain
);
465 hr
= RuntimeHost_CreateManagedInstance(This
, classnameW
, domain
, &obj
);
468 hr
= RuntimeHost_GetIUnknownForObject(This
, obj
, appDomainSetup
);
473 static HRESULT WINAPI
corruntimehost_CreateEvidence(
474 ICorRuntimeHost
* iface
,
477 FIXME("stub %p\n", iface
);
481 static HRESULT WINAPI
corruntimehost_UnloadDomain(
482 ICorRuntimeHost
* iface
,
485 FIXME("stub %p\n", iface
);
489 static HRESULT WINAPI
corruntimehost_CurrentDomain(
490 ICorRuntimeHost
* iface
,
491 IUnknown
**appDomain
)
493 FIXME("stub %p\n", iface
);
497 static const struct ICorRuntimeHostVtbl corruntimehost_vtbl
=
499 corruntimehost_QueryInterface
,
500 corruntimehost_AddRef
,
501 corruntimehost_Release
,
502 corruntimehost_CreateLogicalThreadState
,
503 corruntimehost_DeleteLogicalThreadState
,
504 corruntimehost_SwitchInLogicalThreadState
,
505 corruntimehost_SwitchOutLogicalThreadState
,
506 corruntimehost_LocksHeldByLogicalThread
,
507 corruntimehost_MapFile
,
508 corruntimehost_GetConfiguration
,
509 corruntimehost_Start
,
511 corruntimehost_CreateDomain
,
512 corruntimehost_GetDefaultDomain
,
513 corruntimehost_EnumDomains
,
514 corruntimehost_NextDomain
,
515 corruntimehost_CloseEnum
,
516 corruntimehost_CreateDomainEx
,
517 corruntimehost_CreateDomainSetup
,
518 corruntimehost_CreateEvidence
,
519 corruntimehost_UnloadDomain
,
520 corruntimehost_CurrentDomain
523 static HRESULT WINAPI
CLRRuntimeHost_QueryInterface(ICLRRuntimeHost
* iface
,
527 RuntimeHost
*This
= impl_from_ICLRRuntimeHost( iface
);
528 TRACE("%p %s %p\n", This
, debugstr_guid(riid
), ppvObject
);
530 if ( IsEqualGUID( riid
, &IID_ICLRRuntimeHost
) ||
531 IsEqualGUID( riid
, &IID_IUnknown
) )
537 FIXME("Unsupported interface %s\n", debugstr_guid(riid
));
538 return E_NOINTERFACE
;
541 ICLRRuntimeHost_AddRef( iface
);
546 static ULONG WINAPI
CLRRuntimeHost_AddRef(ICLRRuntimeHost
* iface
)
548 RuntimeHost
*This
= impl_from_ICLRRuntimeHost( iface
);
549 return ICorRuntimeHost_AddRef(&This
->ICorRuntimeHost_iface
);
552 static ULONG WINAPI
CLRRuntimeHost_Release(ICLRRuntimeHost
* iface
)
554 RuntimeHost
*This
= impl_from_ICLRRuntimeHost( iface
);
555 return ICorRuntimeHost_Release(&This
->ICorRuntimeHost_iface
);
558 static HRESULT WINAPI
CLRRuntimeHost_Start(ICLRRuntimeHost
* iface
)
560 FIXME("(%p)\n", iface
);
564 static HRESULT WINAPI
CLRRuntimeHost_Stop(ICLRRuntimeHost
* iface
)
566 FIXME("(%p)\n", iface
);
570 static HRESULT WINAPI
CLRRuntimeHost_SetHostControl(ICLRRuntimeHost
* iface
,
571 IHostControl
*pHostControl
)
573 FIXME("(%p,%p)\n", iface
, pHostControl
);
577 static HRESULT WINAPI
CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost
* iface
,
578 ICLRControl
**pCLRControl
)
580 FIXME("(%p,%p)\n", iface
, pCLRControl
);
584 static HRESULT WINAPI
CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost
* iface
,
585 DWORD dwAppDomainId
, BOOL fWaitUntilDone
)
587 FIXME("(%p,%u,%i)\n", iface
, dwAppDomainId
, fWaitUntilDone
);
591 static HRESULT WINAPI
CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost
* iface
,
592 DWORD dwAppDomainId
, FExecuteInAppDomainCallback pCallback
, void *cookie
)
594 FIXME("(%p,%u,%p,%p)\n", iface
, dwAppDomainId
, pCallback
, cookie
);
598 static HRESULT WINAPI
CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost
* iface
,
599 DWORD
*pdwAppDomainId
)
601 FIXME("(%p,%p)\n", iface
, pdwAppDomainId
);
605 static HRESULT WINAPI
CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost
* iface
,
606 LPCWSTR pwzAppFullName
, DWORD dwManifestPaths
, LPCWSTR
*ppwzManifestPaths
,
607 DWORD dwActivationData
, LPCWSTR
*ppwzActivationData
, int *pReturnValue
)
609 FIXME("(%p,%s,%u,%u)\n", iface
, debugstr_w(pwzAppFullName
), dwManifestPaths
, dwActivationData
);
613 static HRESULT WINAPI
CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost
* iface
,
614 LPCWSTR pwzAssemblyPath
, LPCWSTR pwzTypeName
, LPCWSTR pwzMethodName
,
615 LPCWSTR pwzArgument
, DWORD
*pReturnValue
)
617 RuntimeHost
*This
= impl_from_ICLRRuntimeHost( iface
);
622 char *filenameA
= NULL
, *classA
= NULL
, *methodA
= NULL
;
623 char *argsA
= NULL
, *ns
;
625 TRACE("(%p,%s,%s,%s,%s)\n", iface
, debugstr_w(pwzAssemblyPath
),
626 debugstr_w(pwzTypeName
), debugstr_w(pwzMethodName
), debugstr_w(pwzArgument
));
628 hr
= RuntimeHost_GetDefaultDomain(This
, &domain
);
632 mono_thread_attach(domain
);
634 filenameA
= WtoA(pwzAssemblyPath
);
635 if (!filenameA
) hr
= E_OUTOFMEMORY
;
640 classA
= WtoA(pwzTypeName
);
641 if (!classA
) hr
= E_OUTOFMEMORY
;
646 ns
= strrchr(classA
, '.');
655 methodA
= WtoA(pwzMethodName
);
656 if (!methodA
) hr
= E_OUTOFMEMORY
;
659 /* The .NET function we are calling has the following declaration
660 * public static int functionName(String param)
664 argsA
= WtoA(pwzArgument
);
665 if (!argsA
) hr
= E_OUTOFMEMORY
;
670 str
= mono_string_new(domain
, argsA
);
671 if (!str
) hr
= E_OUTOFMEMORY
;
676 hr
= RuntimeHost_Invoke(This
, domain
, filenameA
, classA
, ns
+1, methodA
,
677 NULL
, (void**)&str
, 1, &result
);
681 *pReturnValue
= *(DWORD
*)mono_object_unbox(result
);
683 HeapFree(GetProcessHeap(), 0, filenameA
);
684 HeapFree(GetProcessHeap(), 0, classA
);
685 HeapFree(GetProcessHeap(), 0, argsA
);
686 HeapFree(GetProcessHeap(), 0, methodA
);
691 static const struct ICLRRuntimeHostVtbl CLRHostVtbl
=
693 CLRRuntimeHost_QueryInterface
,
694 CLRRuntimeHost_AddRef
,
695 CLRRuntimeHost_Release
,
696 CLRRuntimeHost_Start
,
698 CLRRuntimeHost_SetHostControl
,
699 CLRRuntimeHost_GetCLRControl
,
700 CLRRuntimeHost_UnloadAppDomain
,
701 CLRRuntimeHost_ExecuteInAppDomain
,
702 CLRRuntimeHost_GetCurrentAppDomainId
,
703 CLRRuntimeHost_ExecuteApplication
,
704 CLRRuntimeHost_ExecuteInDefaultAppDomain
707 /* Create an instance of a type given its name, by calling its constructor with
708 * no arguments. Note that result MUST be in the stack, or the garbage
709 * collector may free it prematurely. */
710 HRESULT
RuntimeHost_CreateManagedInstance(RuntimeHost
*This
, LPCWSTR name
,
711 MonoDomain
*domain
, MonoObject
**result
)
720 hr
= RuntimeHost_GetDefaultDomain(This
, &domain
);
731 mono_thread_attach(domain
);
733 type
= mono_reflection_type_from_name(nameA
, NULL
);
736 ERR("Cannot find type %s\n", debugstr_w(name
));
743 klass
= mono_class_from_mono_type(type
);
746 ERR("Cannot convert type %s to a class\n", debugstr_w(name
));
753 obj
= mono_object_new(domain
, klass
);
756 ERR("Cannot allocate object of type %s\n", debugstr_w(name
));
763 /* FIXME: Detect exceptions from the constructor? */
764 mono_runtime_object_init(obj
);
768 HeapFree(GetProcessHeap(), 0, nameA
);
773 /* Get an IUnknown pointer for a Mono object.
775 * This is just a "light" wrapper around
776 * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
778 * NOTE: The IUnknown* is created with a reference to the object.
779 * Until they have a reference, objects must be in the stack to prevent the
780 * garbage collector from freeing them.
782 * mono_thread_attach must have already been called for this thread. */
783 HRESULT
RuntimeHost_GetIUnknownForObject(RuntimeHost
*This
, MonoObject
*obj
,
790 domain
= mono_object_get_domain(obj
);
792 hr
= RuntimeHost_Invoke(This
, domain
, "mscorlib", "System.Runtime.InteropServices", "Marshal", "GetIUnknownForObject",
793 NULL
, (void**)&obj
, 1, &result
);
796 *ppUnk
= *(IUnknown
**)mono_object_unbox(result
);
803 static void get_utf8_args(int *argc
, char ***argv
)
809 argvw
= CommandLineToArgvW(GetCommandLineW(), argc
);
811 for (i
=0; i
<*argc
; i
++)
813 size
+= sizeof(char*);
814 size
+= WideCharToMultiByte(CP_UTF8
, 0, argvw
[i
], -1, NULL
, 0, NULL
, NULL
);
816 size
+= sizeof(char*);
818 *argv
= HeapAlloc(GetProcessHeap(), 0, size
);
819 current_arg
= (char*)(*argv
+ *argc
+ 1);
821 for (i
=0; i
<*argc
; i
++)
823 (*argv
)[i
] = current_arg
;
824 current_arg
+= WideCharToMultiByte(CP_UTF8
, 0, argvw
[i
], -1, current_arg
, size
, NULL
, NULL
);
827 (*argv
)[*argc
] = NULL
;
829 HeapFree(GetProcessHeap(), 0, argvw
);
834 # define CAN_FIXUP_VTABLE 1
836 #include "pshpack1.h"
838 struct vtable_fixup_thunk
844 /* mov fixup,(%esp) */
846 struct dll_fixup
*fixup
;
847 /* mov function,%eax */
849 void (CDECL
*function
)(struct dll_fixup
*);
856 /* jmp *vtable_entry */
861 static const struct vtable_fixup_thunk thunk_template
= {
877 #else /* !defined(__i386__) */
879 # define CAN_FIXUP_VTABLE 0
881 struct vtable_fixup_thunk
883 struct dll_fixup
*fixup
;
884 void (CDECL
*function
)(struct dll_fixup
*fixup
);
888 static const struct vtable_fixup_thunk thunk_template
= {0};
892 static void CDECL
ReallyFixupVTable(struct dll_fixup
*fixup
)
895 WCHAR filename
[MAX_PATH
];
896 ICLRRuntimeInfo
*info
=NULL
;
899 MonoImage
*image
=NULL
;
900 MonoAssembly
*assembly
=NULL
;
901 MonoImageOpenStatus status
=0;
904 if (fixup
->done
) return;
906 /* It's possible we'll have two threads doing this at once. This is
907 * considered preferable to the potential deadlock if we use a mutex. */
909 GetModuleFileNameW(fixup
->dll
, filename
, MAX_PATH
);
911 TRACE("%p,%p,%s\n", fixup
, fixup
->dll
, debugstr_w(filename
));
913 filenameA
= WtoA(filename
);
918 hr
= get_runtime_info(filename
, NULL
, NULL
, 0, 0, FALSE
, &info
);
921 hr
= ICLRRuntimeInfo_GetRuntimeHost(info
, &host
);
924 hr
= RuntimeHost_GetDefaultDomain(host
, &domain
);
928 mono_thread_attach(domain
);
930 assembly
= mono_assembly_open(filenameA
, &status
);
937 /* Mono needs an image that belongs to an assembly. */
938 image
= mono_assembly_get_image(assembly
);
940 if (fixup
->fixup
->type
& COR_VTABLE_32BIT
)
942 DWORD
*vtable
= fixup
->vtable
;
943 DWORD
*tokens
= fixup
->tokens
;
944 for (i
=0; i
<fixup
->fixup
->count
; i
++)
946 TRACE("%x\n", tokens
[i
]);
947 vtable
[i
] = PtrToUint(mono_marshal_get_vtfixup_ftnptr(
948 image
, tokens
[i
], fixup
->fixup
->type
));
956 ICLRRuntimeInfo_Release(info
);
958 HeapFree(GetProcessHeap(), 0, filenameA
);
962 ERR("unable to fixup vtable, hr=%x, status=%d\n", hr
, status
);
963 /* If we returned now, we'd get an infinite loop. */
968 static void FixupVTableEntry(HMODULE hmodule
, VTableFixup
*vtable_fixup
)
970 /* We can't actually generate code for the functions without loading mono,
971 * and loading mono inside DllMain is a terrible idea. So we make thunks
972 * that call ReallyFixupVTable, which will load the runtime and fill in the
973 * vtable, then do an indirect jump using the (now filled in) vtable. Note
974 * that we have to keep the thunks around forever, as one of them may get
975 * called while we're filling in the table, and we can never be sure all
976 * threads are clear. */
977 struct dll_fixup
*fixup
;
979 fixup
= HeapAlloc(GetProcessHeap(), 0, sizeof(*fixup
));
981 fixup
->dll
= hmodule
;
982 fixup
->thunk_code
= HeapAlloc(dll_fixup_heap
, 0, sizeof(struct vtable_fixup_thunk
) * vtable_fixup
->count
);
983 fixup
->fixup
= vtable_fixup
;
984 fixup
->vtable
= (BYTE
*)hmodule
+ vtable_fixup
->rva
;
987 if (vtable_fixup
->type
& COR_VTABLE_32BIT
)
989 DWORD
*vtable
= fixup
->vtable
;
992 struct vtable_fixup_thunk
*thunks
= fixup
->thunk_code
;
994 if (sizeof(void*) > 4)
995 ERR("32-bit fixup in 64-bit mode; broken image?\n");
997 tokens
= fixup
->tokens
= HeapAlloc(GetProcessHeap(), 0, sizeof(*tokens
) * vtable_fixup
->count
);
998 memcpy(tokens
, vtable
, sizeof(*tokens
) * vtable_fixup
->count
);
999 for (i
=0; i
<vtable_fixup
->count
; i
++)
1001 thunks
[i
] = thunk_template
;
1002 thunks
[i
].fixup
= fixup
;
1003 thunks
[i
].function
= ReallyFixupVTable
;
1004 thunks
[i
].vtable_entry
= &vtable
[i
];
1005 vtable
[i
] = PtrToUint(&thunks
[i
]);
1010 ERR("unsupported vtable fixup flags %x\n", vtable_fixup
->type
);
1011 HeapFree(dll_fixup_heap
, 0, fixup
->thunk_code
);
1012 HeapFree(GetProcessHeap(), 0, fixup
);
1016 list_add_tail(&dll_fixups
, &fixup
->entry
);
1019 static void FixupVTable(HMODULE hmodule
)
1023 VTableFixup
*vtable_fixups
;
1024 ULONG vtable_fixup_count
, i
;
1026 hr
= assembly_from_hmodule(&assembly
, hmodule
);
1029 hr
= assembly_get_vtable_fixups(assembly
, &vtable_fixups
, &vtable_fixup_count
);
1030 if (CAN_FIXUP_VTABLE
)
1031 for (i
=0; i
<vtable_fixup_count
; i
++)
1032 FixupVTableEntry(hmodule
, &vtable_fixups
[i
]);
1033 else if (vtable_fixup_count
)
1034 FIXME("cannot fixup vtable; expect a crash\n");
1036 assembly_release(assembly
);
1039 ERR("failed to read CLR headers, hr=%x\n", hr
);
1042 __int32 WINAPI
_CorExeMain(void)
1047 MonoDomain
*domain
=NULL
;
1049 MonoImageOpenStatus status
;
1050 MonoAssembly
*assembly
=NULL
;
1051 WCHAR filename
[MAX_PATH
];
1053 ICLRRuntimeInfo
*info
;
1058 get_utf8_args(&argc
, &argv
);
1060 GetModuleFileNameW(NULL
, filename
, MAX_PATH
);
1062 TRACE("%s", debugstr_w(filename
));
1063 for (i
=0; i
<argc
; i
++)
1064 TRACE(" %s", debugstr_a(argv
[i
]));
1067 filenameA
= WtoA(filename
);
1071 FixupVTable(GetModuleHandleW(NULL
));
1073 hr
= get_runtime_info(filename
, NULL
, NULL
, 0, 0, FALSE
, &info
);
1077 hr
= ICLRRuntimeInfo_GetRuntimeHost(info
, &host
);
1080 hr
= RuntimeHost_GetDefaultDomain(host
, &domain
);
1084 image
= mono_image_open_from_module_handle(GetModuleHandleW(NULL
),
1085 filenameA
, 1, &status
);
1088 assembly
= mono_assembly_load_from(image
, filenameA
, &status
);
1092 mono_trace_set_assembly(assembly
);
1094 exit_code
= mono_jit_exec(domain
, assembly
, argc
, argv
);
1098 ERR("couldn't load %s, status=%d\n", debugstr_w(filename
), status
);
1102 RuntimeHost_DeleteDomain(host
, domain
);
1107 ICLRRuntimeInfo_Release(info
);
1112 HeapFree(GetProcessHeap(), 0, argv
);
1116 mono_thread_manage();
1117 mono_runtime_quit();
1123 BOOL WINAPI
_CorDllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
1125 TRACE("(%p, %d, %p)\n", hinstDLL
, fdwReason
, lpvReserved
);
1129 case DLL_PROCESS_ATTACH
:
1130 DisableThreadLibraryCalls(hinstDLL
);
1131 FixupVTable(hinstDLL
);
1133 case DLL_PROCESS_DETACH
:
1134 /* FIXME: clean up the vtables */
1140 /* called from DLL_PROCESS_ATTACH */
1141 void runtimehost_init(void)
1143 dll_fixup_heap
= HeapCreate(HEAP_CREATE_ENABLE_EXECUTE
, 0, 0);
1144 list_init(&dll_fixups
);
1147 /* called from DLL_PROCESS_DETACH */
1148 void runtimehost_uninit(void)
1150 struct dll_fixup
*fixup
, *fixup2
;
1152 HeapDestroy(dll_fixup_heap
);
1153 LIST_FOR_EACH_ENTRY_SAFE(fixup
, fixup2
, &dll_fixups
, struct dll_fixup
, entry
)
1155 HeapFree(GetProcessHeap(), 0, fixup
->tokens
);
1156 HeapFree(GetProcessHeap(), 0, fixup
);
1160 HRESULT
RuntimeHost_Construct(const CLRRuntimeInfo
*runtime_version
, RuntimeHost
** result
)
1164 This
= HeapAlloc( GetProcessHeap(), 0, sizeof *This
);
1166 return E_OUTOFMEMORY
;
1168 This
->ICorRuntimeHost_iface
.lpVtbl
= &corruntimehost_vtbl
;
1169 This
->ICLRRuntimeHost_iface
.lpVtbl
= &CLRHostVtbl
;
1172 This
->version
= runtime_version
;
1173 list_init(&This
->domains
);
1174 This
->default_domain
= NULL
;
1175 InitializeCriticalSection(&This
->lock
);
1176 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": RuntimeHost.lock");
1183 HRESULT
RuntimeHost_GetInterface(RuntimeHost
*This
, REFCLSID clsid
, REFIID riid
, void **ppv
)
1188 if (IsEqualGUID(clsid
, &CLSID_CorRuntimeHost
))
1190 unk
= (IUnknown
*)&This
->ICorRuntimeHost_iface
;
1191 IUnknown_AddRef(unk
);
1193 else if (IsEqualGUID(clsid
, &CLSID_CLRRuntimeHost
))
1195 unk
= (IUnknown
*)&This
->ICLRRuntimeHost_iface
;
1196 IUnknown_AddRef(unk
);
1198 else if (IsEqualGUID(clsid
, &CLSID_CorMetaDataDispenser
) ||
1199 IsEqualGUID(clsid
, &CLSID_CorMetaDataDispenserRuntime
))
1201 hr
= MetaDataDispenser_CreateInstance(&unk
);
1205 else if (IsEqualGUID(clsid
, &CLSID_CLRDebuggingLegacy
))
1207 hr
= CorDebug_Create(&This
->ICLRRuntimeHost_iface
, &unk
);
1216 hr
= IUnknown_QueryInterface(unk
, riid
, ppv
);
1218 IUnknown_Release(unk
);
1223 FIXME("not implemented for class %s\n", debugstr_guid(clsid
));
1225 return CLASS_E_CLASSNOTAVAILABLE
;
1228 #define CHARS_IN_GUID 39
1229 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
1231 HRESULT
create_monodata(REFIID riid
, LPVOID
*ppObj
)
1233 static const WCHAR wszAssembly
[] = {'A','s','s','e','m','b','l','y',0};
1234 static const WCHAR wszCodebase
[] = {'C','o','d','e','B','a','s','e',0};
1235 static const WCHAR wszClass
[] = {'C','l','a','s','s',0};
1236 static const WCHAR wszFileSlash
[] = {'f','i','l','e',':','/','/','/',0};
1237 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
1238 static const WCHAR wszInprocServer32
[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1239 static const WCHAR wszDLL
[] = {'.','d','l','l',0};
1240 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) + ARRAYSIZE(wszInprocServer32
) - 1];
1242 MonoAssembly
*assembly
;
1243 ICLRRuntimeInfo
*info
= NULL
;
1249 DWORD numKeys
, keyLength
;
1250 WCHAR codebase
[MAX_PATH
+ 8];
1251 WCHAR classname
[350], subkeyName
[256];
1252 WCHAR filename
[MAX_PATH
];
1254 DWORD dwBufLen
= 350;
1256 lstrcpyW(path
, wszCLSIDSlash
);
1257 StringFromGUID2(riid
, path
+ lstrlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
1258 lstrcatW(path
, wszInprocServer32
);
1260 TRACE("Registry key: %s\n", debugstr_w(path
));
1262 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, path
, 0, KEY_READ
, &key
);
1263 if (res
== ERROR_FILE_NOT_FOUND
)
1264 return CLASS_E_CLASSNOTAVAILABLE
;
1266 res
= RegGetValueW( key
, NULL
, wszClass
, RRF_RT_REG_SZ
, NULL
, classname
, &dwBufLen
);
1267 if(res
!= ERROR_SUCCESS
)
1269 WARN("Class value cannot be found.\n");
1270 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1274 TRACE("classname (%s)\n", debugstr_w(classname
));
1276 dwBufLen
= MAX_PATH
+ 8;
1277 res
= RegGetValueW( key
, NULL
, wszCodebase
, RRF_RT_REG_SZ
, NULL
, codebase
, &dwBufLen
);
1278 if(res
== ERROR_SUCCESS
)
1280 /* Strip file:/// */
1281 if(strncmpW(codebase
, wszFileSlash
, strlenW(wszFileSlash
)) == 0)
1282 offset
= strlenW(wszFileSlash
);
1284 strcpyW(filename
, codebase
+ offset
);
1288 WCHAR assemblyname
[MAX_PATH
+ 8];
1290 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1291 WARN("CodeBase value cannot be found, trying Assembly.\n");
1292 /* get the last subkey of InprocServer32 */
1293 res
= RegQueryInfoKeyW(key
, 0, 0, 0, &numKeys
, 0, 0, 0, 0, 0, 0, 0);
1294 if (res
!= ERROR_SUCCESS
|| numKeys
== 0)
1297 keyLength
= sizeof(subkeyName
) / sizeof(WCHAR
);
1298 res
= RegEnumKeyExW(key
, numKeys
, subkeyName
, &keyLength
, 0, 0, 0, 0);
1299 if (res
!= ERROR_SUCCESS
)
1301 res
= RegOpenKeyExW(key
, subkeyName
, 0, KEY_READ
, &subkey
);
1302 if (res
!= ERROR_SUCCESS
)
1304 dwBufLen
= MAX_PATH
+ 8;
1305 res
= RegGetValueW(subkey
, NULL
, wszAssembly
, RRF_RT_REG_SZ
, NULL
, assemblyname
, &dwBufLen
);
1306 RegCloseKey(subkey
);
1307 if (res
!= ERROR_SUCCESS
)
1310 hr
= get_file_from_strongname(assemblyname
, filename
, MAX_PATH
);
1314 * The registry doesn't have a CodeBase entry and it's not in the GAC.
1316 * Use the Assembly Key to retrieve the filename.
1317 * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null
1321 WARN("Attempt to load from the application directory.\n");
1322 GetModuleFileNameW(NULL
, filename
, MAX_PATH
);
1323 ns
= strrchrW(filename
, '\\');
1326 ns
= strchrW(assemblyname
, ',');
1328 strcatW(filename
, assemblyname
);
1330 strcatW(filename
, wszDLL
);
1334 TRACE("filename (%s)\n", debugstr_w(filename
));
1339 hr
= get_runtime_info(filename
, NULL
, NULL
, 0, 0, FALSE
, &info
);
1342 hr
= ICLRRuntimeInfo_GetRuntimeHost(info
, &host
);
1345 hr
= RuntimeHost_GetDefaultDomain(host
, &domain
);
1352 IUnknown
*unk
= NULL
;
1353 char *filenameA
, *ns
;
1356 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1358 mono_thread_attach(domain
);
1360 filenameA
= WtoA(filename
);
1361 assembly
= mono_domain_assembly_open(domain
, filenameA
);
1362 HeapFree(GetProcessHeap(), 0, filenameA
);
1365 ERR("Cannot open assembly %s\n", filenameA
);
1369 image
= mono_assembly_get_image(assembly
);
1372 ERR("Couldn't get assembly image\n");
1376 classA
= WtoA(classname
);
1377 ns
= strrchr(classA
, '.');
1380 klass
= mono_class_from_name(image
, classA
, ns
+1);
1381 HeapFree(GetProcessHeap(), 0, classA
);
1384 ERR("Couldn't get class from image\n");
1389 * Use the default constructor for the .NET class.
1391 result
= mono_object_new(domain
, klass
);
1392 mono_runtime_object_init(result
);
1394 hr
= RuntimeHost_GetIUnknownForObject(host
, result
, &unk
);
1397 hr
= IUnknown_QueryInterface(unk
, &IID_IUnknown
, ppObj
);
1399 IUnknown_Release(unk
);
1402 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1405 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1408 hr
= CLASS_E_CLASSNOTAVAILABLE
;
1412 ICLRRuntimeInfo_Release(info
);