mscoree: Factor out common code for calling .NET methods.
[wine.git] / dlls / mscoree / corruntimehost.c
blobce731344e414b73ab570c2b8a7f3644a4233480d
1 /*
3 * Copyright 2008 Alistair Leslie-Hughes
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define COBJMACROS
22 #include <assert.h>
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "ole2.h"
31 #include "shellapi.h"
33 #include "cor.h"
34 #include "mscoree.h"
35 #include "metahost.h"
36 #include "corhdr.h"
37 #include "cordebug.h"
38 #include "wine/list.h"
39 #include "mscoree_private.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
46 #include "initguid.h"
48 DEFINE_GUID(IID__AppDomain, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13);
50 struct DomainEntry
52 struct list entry;
53 MonoDomain *domain;
56 static HANDLE dll_fixup_heap; /* using a separate heap so we can have execute permission */
58 static struct list dll_fixups;
60 struct dll_fixup
62 struct list entry;
63 BOOL done;
64 HMODULE dll;
65 void *thunk_code; /* pointer into dll_fixup_heap */
66 VTableFixup *fixup;
67 void *vtable;
68 void *tokens; /* pointer into process heap */
71 static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, MonoDomain **result)
73 struct DomainEntry *entry;
74 char *mscorlib_path;
75 HRESULT res=S_OK;
77 EnterCriticalSection(&This->lock);
79 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
80 if (!entry)
82 res = E_OUTOFMEMORY;
83 goto end;
86 mscorlib_path = WtoA(This->version->mscorlib_path);
87 if (!mscorlib_path)
89 HeapFree(GetProcessHeap(), 0, entry);
90 res = E_OUTOFMEMORY;
91 goto end;
94 entry->domain = mono_jit_init(mscorlib_path);
96 HeapFree(GetProcessHeap(), 0, mscorlib_path);
98 if (!entry->domain)
100 HeapFree(GetProcessHeap(), 0, entry);
101 res = E_FAIL;
102 goto end;
105 is_mono_started = TRUE;
107 list_add_tail(&This->domains, &entry->entry);
109 *result = entry->domain;
111 end:
112 LeaveCriticalSection(&This->lock);
114 return res;
117 static HRESULT RuntimeHost_GetDefaultDomain(RuntimeHost *This, MonoDomain **result)
119 HRESULT res=S_OK;
121 EnterCriticalSection(&This->lock);
123 if (This->default_domain) goto end;
125 res = RuntimeHost_AddDomain(This, &This->default_domain);
127 end:
128 *result = This->default_domain;
130 LeaveCriticalSection(&This->lock);
132 return res;
135 static void RuntimeHost_DeleteDomain(RuntimeHost *This, MonoDomain *domain)
137 struct DomainEntry *entry;
139 EnterCriticalSection(&This->lock);
141 LIST_FOR_EACH_ENTRY(entry, &This->domains, struct DomainEntry, entry)
143 if (entry->domain == domain)
145 list_remove(&entry->entry);
146 if (This->default_domain == domain)
147 This->default_domain = NULL;
148 HeapFree(GetProcessHeap(), 0, entry);
149 break;
153 LeaveCriticalSection(&This->lock);
156 static HRESULT RuntimeHost_Invoke(RuntimeHost *This, MonoDomain *domain,
157 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
158 MonoObject *obj, void **args, int arg_count, MonoObject **result)
160 MonoAssembly *assembly;
161 MonoImage *image;
162 MonoClass *klass;
163 MonoMethod *method;
164 MonoObject *exc;
165 static const char *get_hresult = "get_HResult";
167 *result = NULL;
169 mono_thread_attach(domain);
171 assembly = mono_domain_assembly_open(domain, assemblyname);
172 if (!assembly)
174 ERR("Cannot load assembly\n");
175 return E_FAIL;
178 image = mono_assembly_get_image(assembly);
179 if (!image)
181 ERR("Couldn't get assembly image\n");
182 return E_FAIL;
185 klass = mono_class_from_name(image, namespace, typename);
186 if (!klass)
188 ERR("Couldn't get class from image\n");
189 return E_FAIL;
192 method = mono_class_get_method_from_name(klass, methodname, arg_count);
193 if (!method)
195 ERR("Couldn't get method from class\n");
196 return E_FAIL;
199 *result = mono_runtime_invoke(method, obj, args, &exc);
200 if (exc)
202 HRESULT hr;
203 MonoObject *hr_object;
205 if (methodname != get_hresult)
207 /* Map the exception to an HRESULT. */
208 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System", "Exception", get_hresult,
209 exc, NULL, 0, &hr_object);
210 if (SUCCEEDED(hr))
211 hr = *(HRESULT*)mono_object_unbox(hr_object);
212 if (SUCCEEDED(hr))
213 hr = E_FAIL;
215 else
216 hr = E_FAIL;
217 ERR("Method %s.%s raised an exception, hr=%x\n", namespace, typename, hr);
218 *result = NULL;
219 return hr;
222 return S_OK;
225 static HRESULT RuntimeHost_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *domain, IUnknown **punk)
227 HRESULT hr;
228 MonoObject *appdomain_object;
229 IUnknown *unk;
231 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System", "AppDomain", "get_CurrentDomain",
232 NULL, NULL, 0, &appdomain_object);
234 if (SUCCEEDED(hr))
235 hr = RuntimeHost_GetIUnknownForObject(This, appdomain_object, &unk);
237 if (SUCCEEDED(hr))
239 hr = IUnknown_QueryInterface(unk, &IID__AppDomain, (void**)punk);
241 IUnknown_Release(unk);
244 return hr;
247 void RuntimeHost_ExitProcess(RuntimeHost *This, INT exitcode)
249 HRESULT hr;
250 void *args[2];
251 MonoDomain *domain;
252 MonoObject *dummy;
254 hr = RuntimeHost_GetDefaultDomain(This, &domain);
255 if (FAILED(hr))
257 ERR("Cannot get domain, hr=%x\n", hr);
258 return;
261 args[0] = &exitcode;
262 args[1] = NULL;
263 RuntimeHost_Invoke(This, domain, "mscorlib", "System", "Environment", "Exit",
264 NULL, args, 1, &dummy);
266 ERR("Process should have exited\n");
269 static inline RuntimeHost *impl_from_ICLRRuntimeHost( ICLRRuntimeHost *iface )
271 return CONTAINING_RECORD(iface, RuntimeHost, ICLRRuntimeHost_iface);
274 static inline RuntimeHost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
276 return CONTAINING_RECORD(iface, RuntimeHost, ICorRuntimeHost_iface);
279 /*** IUnknown methods ***/
280 static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
281 REFIID riid,
282 void **ppvObject)
284 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
285 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
287 if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) ||
288 IsEqualGUID( riid, &IID_IUnknown ) )
290 *ppvObject = iface;
292 else
294 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
295 return E_NOINTERFACE;
298 ICorRuntimeHost_AddRef( iface );
300 return S_OK;
303 static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface)
305 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
307 return InterlockedIncrement( &This->ref );
310 static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface)
312 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
313 ULONG ref;
315 ref = InterlockedDecrement( &This->ref );
317 return ref;
320 /*** ICorRuntimeHost methods ***/
321 static HRESULT WINAPI corruntimehost_CreateLogicalThreadState(
322 ICorRuntimeHost* iface)
324 FIXME("stub %p\n", iface);
325 return E_NOTIMPL;
328 static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState(
329 ICorRuntimeHost* iface)
331 FIXME("stub %p\n", iface);
332 return E_NOTIMPL;
335 static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState(
336 ICorRuntimeHost* iface,
337 DWORD *fiberCookie)
339 FIXME("stub %p\n", iface);
340 return E_NOTIMPL;
343 static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState(
344 ICorRuntimeHost* iface,
345 DWORD **fiberCookie)
347 FIXME("stub %p\n", iface);
348 return E_NOTIMPL;
351 static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread(
352 ICorRuntimeHost* iface,
353 DWORD *pCount)
355 FIXME("stub %p\n", iface);
356 return E_NOTIMPL;
359 static HRESULT WINAPI corruntimehost_MapFile(
360 ICorRuntimeHost* iface,
361 HANDLE hFile,
362 HMODULE *mapAddress)
364 FIXME("stub %p\n", iface);
365 return E_NOTIMPL;
368 static HRESULT WINAPI corruntimehost_GetConfiguration(
369 ICorRuntimeHost* iface,
370 ICorConfiguration **pConfiguration)
372 FIXME("stub %p\n", iface);
373 return E_NOTIMPL;
376 static HRESULT WINAPI corruntimehost_Start(
377 ICorRuntimeHost* iface)
379 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
380 MonoDomain *dummy;
382 TRACE("%p\n", This);
384 return RuntimeHost_GetDefaultDomain(This, &dummy);
387 static HRESULT WINAPI corruntimehost_Stop(
388 ICorRuntimeHost* iface)
390 FIXME("stub %p\n", iface);
391 return E_NOTIMPL;
394 static HRESULT WINAPI corruntimehost_CreateDomain(
395 ICorRuntimeHost* iface,
396 LPCWSTR friendlyName,
397 IUnknown *identityArray,
398 IUnknown **appDomain)
400 FIXME("stub %p\n", iface);
401 return E_NOTIMPL;
404 static HRESULT WINAPI corruntimehost_GetDefaultDomain(
405 ICorRuntimeHost* iface,
406 IUnknown **pAppDomain)
408 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
409 HRESULT hr;
410 MonoDomain *domain;
412 TRACE("(%p)\n", iface);
414 hr = RuntimeHost_GetDefaultDomain(This, &domain);
416 if (SUCCEEDED(hr))
418 hr = RuntimeHost_GetIUnknownForDomain(This, domain, pAppDomain);
421 return hr;
424 static HRESULT WINAPI corruntimehost_EnumDomains(
425 ICorRuntimeHost* iface,
426 HDOMAINENUM *hEnum)
428 FIXME("stub %p\n", iface);
429 return E_NOTIMPL;
432 static HRESULT WINAPI corruntimehost_NextDomain(
433 ICorRuntimeHost* iface,
434 HDOMAINENUM hEnum,
435 IUnknown **appDomain)
437 FIXME("stub %p\n", iface);
438 return E_NOTIMPL;
441 static HRESULT WINAPI corruntimehost_CloseEnum(
442 ICorRuntimeHost* iface,
443 HDOMAINENUM hEnum)
445 FIXME("stub %p\n", iface);
446 return E_NOTIMPL;
449 static HRESULT WINAPI corruntimehost_CreateDomainEx(
450 ICorRuntimeHost* iface,
451 LPCWSTR friendlyName,
452 IUnknown *setup,
453 IUnknown *evidence,
454 IUnknown **appDomain)
456 FIXME("stub %p\n", iface);
457 return E_NOTIMPL;
460 static HRESULT WINAPI corruntimehost_CreateDomainSetup(
461 ICorRuntimeHost* iface,
462 IUnknown **appDomainSetup)
464 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
465 HRESULT hr;
466 MonoDomain *domain;
467 MonoObject *obj;
468 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};
470 TRACE("(%p)\n", iface);
472 hr = RuntimeHost_GetDefaultDomain(This, &domain);
474 if (SUCCEEDED(hr))
475 hr = RuntimeHost_CreateManagedInstance(This, classnameW, domain, &obj);
477 if (SUCCEEDED(hr))
478 hr = RuntimeHost_GetIUnknownForObject(This, obj, appDomainSetup);
480 return hr;
483 static HRESULT WINAPI corruntimehost_CreateEvidence(
484 ICorRuntimeHost* iface,
485 IUnknown **evidence)
487 FIXME("stub %p\n", iface);
488 return E_NOTIMPL;
491 static HRESULT WINAPI corruntimehost_UnloadDomain(
492 ICorRuntimeHost* iface,
493 IUnknown *appDomain)
495 FIXME("stub %p\n", iface);
496 return E_NOTIMPL;
499 static HRESULT WINAPI corruntimehost_CurrentDomain(
500 ICorRuntimeHost* iface,
501 IUnknown **appDomain)
503 FIXME("stub %p\n", iface);
504 return E_NOTIMPL;
507 static const struct ICorRuntimeHostVtbl corruntimehost_vtbl =
509 corruntimehost_QueryInterface,
510 corruntimehost_AddRef,
511 corruntimehost_Release,
512 corruntimehost_CreateLogicalThreadState,
513 corruntimehost_DeleteLogicalThreadState,
514 corruntimehost_SwitchInLogicalThreadState,
515 corruntimehost_SwitchOutLogicalThreadState,
516 corruntimehost_LocksHeldByLogicalThread,
517 corruntimehost_MapFile,
518 corruntimehost_GetConfiguration,
519 corruntimehost_Start,
520 corruntimehost_Stop,
521 corruntimehost_CreateDomain,
522 corruntimehost_GetDefaultDomain,
523 corruntimehost_EnumDomains,
524 corruntimehost_NextDomain,
525 corruntimehost_CloseEnum,
526 corruntimehost_CreateDomainEx,
527 corruntimehost_CreateDomainSetup,
528 corruntimehost_CreateEvidence,
529 corruntimehost_UnloadDomain,
530 corruntimehost_CurrentDomain
533 static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface,
534 REFIID riid,
535 void **ppvObject)
537 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
538 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
540 if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) ||
541 IsEqualGUID( riid, &IID_IUnknown ) )
543 *ppvObject = iface;
545 else
547 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
548 return E_NOINTERFACE;
551 ICLRRuntimeHost_AddRef( iface );
553 return S_OK;
556 static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface)
558 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
559 return ICorRuntimeHost_AddRef(&This->ICorRuntimeHost_iface);
562 static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface)
564 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
565 return ICorRuntimeHost_Release(&This->ICorRuntimeHost_iface);
568 static HRESULT WINAPI CLRRuntimeHost_Start(ICLRRuntimeHost* iface)
570 FIXME("(%p)\n", iface);
571 return E_NOTIMPL;
574 static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
576 FIXME("(%p)\n", iface);
577 return E_NOTIMPL;
580 static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
581 IHostControl *pHostControl)
583 FIXME("(%p,%p)\n", iface, pHostControl);
584 return E_NOTIMPL;
587 static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
588 ICLRControl **pCLRControl)
590 FIXME("(%p,%p)\n", iface, pCLRControl);
591 return E_NOTIMPL;
594 static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
595 DWORD dwAppDomainId, BOOL fWaitUntilDone)
597 FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
598 return E_NOTIMPL;
601 static HRESULT WINAPI CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost* iface,
602 DWORD dwAppDomainId, FExecuteInAppDomainCallback pCallback, void *cookie)
604 FIXME("(%p,%u,%p,%p)\n", iface, dwAppDomainId, pCallback, cookie);
605 return E_NOTIMPL;
608 static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
609 DWORD *pdwAppDomainId)
611 FIXME("(%p,%p)\n", iface, pdwAppDomainId);
612 return E_NOTIMPL;
615 static HRESULT WINAPI CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost* iface,
616 LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR *ppwzManifestPaths,
617 DWORD dwActivationData, LPCWSTR *ppwzActivationData, int *pReturnValue)
619 FIXME("(%p,%s,%u,%u)\n", iface, debugstr_w(pwzAppFullName), dwManifestPaths, dwActivationData);
620 return E_NOTIMPL;
623 static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* iface,
624 LPCWSTR pwzAssemblyPath, LPCWSTR pwzTypeName, LPCWSTR pwzMethodName,
625 LPCWSTR pwzArgument, DWORD *pReturnValue)
627 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
628 HRESULT hr;
629 MonoDomain *domain;
630 MonoObject *result;
631 MonoString *str;
632 char *filenameA = NULL, *classA = NULL, *methodA = NULL;
633 char *argsA = NULL, *ns;
635 TRACE("(%p,%s,%s,%s,%s)\n", iface, debugstr_w(pwzAssemblyPath),
636 debugstr_w(pwzTypeName), debugstr_w(pwzMethodName), debugstr_w(pwzArgument));
638 hr = RuntimeHost_GetDefaultDomain(This, &domain);
640 if (SUCCEEDED(hr))
642 mono_thread_attach(domain);
644 filenameA = WtoA(pwzAssemblyPath);
645 if (!filenameA) hr = E_OUTOFMEMORY;
648 if (SUCCEEDED(hr))
650 classA = WtoA(pwzTypeName);
651 if (!classA) hr = E_OUTOFMEMORY;
654 if (SUCCEEDED(hr))
656 ns = strrchr(classA, '.');
657 if (ns)
658 *ns = '\0';
659 else
660 hr = E_INVALIDARG;
663 if (SUCCEEDED(hr))
665 methodA = WtoA(pwzMethodName);
666 if (!methodA) hr = E_OUTOFMEMORY;
669 /* The .NET function we are calling has the following declaration
670 * public static int functionName(String param)
672 if (SUCCEEDED(hr))
674 argsA = WtoA(pwzArgument);
675 if (!argsA) hr = E_OUTOFMEMORY;
678 if (SUCCEEDED(hr))
680 str = mono_string_new(domain, argsA);
681 if (!str) hr = E_OUTOFMEMORY;
684 if (SUCCEEDED(hr))
686 hr = RuntimeHost_Invoke(This, domain, filenameA, classA, ns+1, methodA,
687 NULL, (void**)&str, 1, &result);
690 if (SUCCEEDED(hr))
691 *pReturnValue = *(DWORD*)mono_object_unbox(result);
693 HeapFree(GetProcessHeap(), 0, filenameA);
694 HeapFree(GetProcessHeap(), 0, classA);
695 HeapFree(GetProcessHeap(), 0, argsA);
696 HeapFree(GetProcessHeap(), 0, methodA);
698 return hr;
701 static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
703 CLRRuntimeHost_QueryInterface,
704 CLRRuntimeHost_AddRef,
705 CLRRuntimeHost_Release,
706 CLRRuntimeHost_Start,
707 CLRRuntimeHost_Stop,
708 CLRRuntimeHost_SetHostControl,
709 CLRRuntimeHost_GetCLRControl,
710 CLRRuntimeHost_UnloadAppDomain,
711 CLRRuntimeHost_ExecuteInAppDomain,
712 CLRRuntimeHost_GetCurrentAppDomainId,
713 CLRRuntimeHost_ExecuteApplication,
714 CLRRuntimeHost_ExecuteInDefaultAppDomain
717 /* Create an instance of a type given its name, by calling its constructor with
718 * no arguments. Note that result MUST be in the stack, or the garbage
719 * collector may free it prematurely. */
720 HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
721 MonoDomain *domain, MonoObject **result)
723 HRESULT hr=S_OK;
724 char *nameA=NULL;
725 MonoType *type;
726 MonoClass *klass;
727 MonoObject *obj;
729 if (!domain)
730 hr = RuntimeHost_GetDefaultDomain(This, &domain);
732 if (SUCCEEDED(hr))
734 nameA = WtoA(name);
735 if (!nameA)
736 hr = E_OUTOFMEMORY;
739 if (SUCCEEDED(hr))
741 mono_thread_attach(domain);
743 type = mono_reflection_type_from_name(nameA, NULL);
744 if (!type)
746 ERR("Cannot find type %s\n", debugstr_w(name));
747 hr = E_FAIL;
751 if (SUCCEEDED(hr))
753 klass = mono_class_from_mono_type(type);
754 if (!klass)
756 ERR("Cannot convert type %s to a class\n", debugstr_w(name));
757 hr = E_FAIL;
761 if (SUCCEEDED(hr))
763 obj = mono_object_new(domain, klass);
764 if (!obj)
766 ERR("Cannot allocate object of type %s\n", debugstr_w(name));
767 hr = E_FAIL;
771 if (SUCCEEDED(hr))
773 /* FIXME: Detect exceptions from the constructor? */
774 mono_runtime_object_init(obj);
775 *result = obj;
778 HeapFree(GetProcessHeap(), 0, nameA);
780 return hr;
783 /* Get an IUnknown pointer for a Mono object.
785 * This is just a "light" wrapper around
786 * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
788 * NOTE: The IUnknown* is created with a reference to the object.
789 * Until they have a reference, objects must be in the stack to prevent the
790 * garbage collector from freeing them.
792 * mono_thread_attach must have already been called for this thread. */
793 HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj,
794 IUnknown **ppUnk)
796 MonoDomain *domain;
797 MonoObject *result;
798 HRESULT hr;
800 domain = mono_object_get_domain(obj);
802 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System.Runtime.InteropServices", "Marshal", "GetIUnknownForObject",
803 NULL, (void**)&obj, 1, &result);
805 if (SUCCEEDED(hr))
806 *ppUnk = *(IUnknown**)mono_object_unbox(result);
807 else
808 *ppUnk = NULL;
810 return hr;
813 static void get_utf8_args(int *argc, char ***argv)
815 WCHAR **argvw;
816 int size=0, i;
817 char *current_arg;
819 argvw = CommandLineToArgvW(GetCommandLineW(), argc);
821 for (i=0; i<*argc; i++)
823 size += sizeof(char*);
824 size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
826 size += sizeof(char*);
828 *argv = HeapAlloc(GetProcessHeap(), 0, size);
829 current_arg = (char*)(*argv + *argc + 1);
831 for (i=0; i<*argc; i++)
833 (*argv)[i] = current_arg;
834 current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
837 (*argv)[*argc] = NULL;
839 HeapFree(GetProcessHeap(), 0, argvw);
842 #if __i386__
844 # define CAN_FIXUP_VTABLE 1
846 #include "pshpack1.h"
848 struct vtable_fixup_thunk
850 /* push %ecx */
851 BYTE i7;
852 /* sub $0x4,%esp */
853 BYTE i1[3];
854 /* mov fixup,(%esp) */
855 BYTE i2[3];
856 struct dll_fixup *fixup;
857 /* mov function,%eax */
858 BYTE i3;
859 void (CDECL *function)(struct dll_fixup *);
860 /* call *%eax */
861 BYTE i4[2];
862 /* pop %eax */
863 BYTE i5;
864 /* pop %ecx */
865 BYTE i8;
866 /* jmp *vtable_entry */
867 BYTE i6[2];
868 void *vtable_entry;
871 static const struct vtable_fixup_thunk thunk_template = {
872 0x51,
873 {0x83,0xec,0x04},
874 {0xc7,0x04,0x24},
875 NULL,
876 0xb8,
877 NULL,
878 {0xff,0xd0},
879 0x58,
880 0x59,
881 {0xff,0x25},
882 NULL
885 #include "poppack.h"
887 #else /* !defined(__i386__) */
889 # define CAN_FIXUP_VTABLE 0
891 struct vtable_fixup_thunk
893 struct dll_fixup *fixup;
894 void (CDECL *function)(struct dll_fixup *fixup);
895 void *vtable_entry;
898 static const struct vtable_fixup_thunk thunk_template = {0};
900 #endif
902 static void CDECL ReallyFixupVTable(struct dll_fixup *fixup)
904 HRESULT hr=S_OK;
905 WCHAR filename[MAX_PATH];
906 ICLRRuntimeInfo *info=NULL;
907 RuntimeHost *host;
908 char *filenameA;
909 MonoImage *image=NULL;
910 MonoAssembly *assembly=NULL;
911 MonoImageOpenStatus status=0;
912 MonoDomain *domain;
914 if (fixup->done) return;
916 /* It's possible we'll have two threads doing this at once. This is
917 * considered preferable to the potential deadlock if we use a mutex. */
919 GetModuleFileNameW(fixup->dll, filename, MAX_PATH);
921 TRACE("%p,%p,%s\n", fixup, fixup->dll, debugstr_w(filename));
923 filenameA = WtoA(filename);
924 if (!filenameA)
925 hr = E_OUTOFMEMORY;
927 if (SUCCEEDED(hr))
928 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
930 if (SUCCEEDED(hr))
931 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
933 if (SUCCEEDED(hr))
934 hr = RuntimeHost_GetDefaultDomain(host, &domain);
936 if (SUCCEEDED(hr))
938 mono_thread_attach(domain);
940 assembly = mono_assembly_open(filenameA, &status);
943 if (assembly)
945 int i;
947 /* Mono needs an image that belongs to an assembly. */
948 image = mono_assembly_get_image(assembly);
950 if (fixup->fixup->type & COR_VTABLE_32BIT)
952 DWORD *vtable = fixup->vtable;
953 DWORD *tokens = fixup->tokens;
954 for (i=0; i<fixup->fixup->count; i++)
956 TRACE("%x\n", tokens[i]);
957 vtable[i] = PtrToUint(mono_marshal_get_vtfixup_ftnptr(
958 image, tokens[i], fixup->fixup->type));
962 fixup->done = TRUE;
965 if (info != NULL)
966 ICLRRuntimeInfo_Release(info);
968 HeapFree(GetProcessHeap(), 0, filenameA);
970 if (!fixup->done)
972 ERR("unable to fixup vtable, hr=%x, status=%d\n", hr, status);
973 /* If we returned now, we'd get an infinite loop. */
974 assert(0);
978 static void FixupVTableEntry(HMODULE hmodule, VTableFixup *vtable_fixup)
980 /* We can't actually generate code for the functions without loading mono,
981 * and loading mono inside DllMain is a terrible idea. So we make thunks
982 * that call ReallyFixupVTable, which will load the runtime and fill in the
983 * vtable, then do an indirect jump using the (now filled in) vtable. Note
984 * that we have to keep the thunks around forever, as one of them may get
985 * called while we're filling in the table, and we can never be sure all
986 * threads are clear. */
987 struct dll_fixup *fixup;
989 fixup = HeapAlloc(GetProcessHeap(), 0, sizeof(*fixup));
991 fixup->dll = hmodule;
992 fixup->thunk_code = HeapAlloc(dll_fixup_heap, 0, sizeof(struct vtable_fixup_thunk) * vtable_fixup->count);
993 fixup->fixup = vtable_fixup;
994 fixup->vtable = (BYTE*)hmodule + vtable_fixup->rva;
995 fixup->done = FALSE;
997 if (vtable_fixup->type & COR_VTABLE_32BIT)
999 DWORD *vtable = fixup->vtable;
1000 DWORD *tokens;
1001 int i;
1002 struct vtable_fixup_thunk *thunks = fixup->thunk_code;
1004 if (sizeof(void*) > 4)
1005 ERR("32-bit fixup in 64-bit mode; broken image?\n");
1007 tokens = fixup->tokens = HeapAlloc(GetProcessHeap(), 0, sizeof(*tokens) * vtable_fixup->count);
1008 memcpy(tokens, vtable, sizeof(*tokens) * vtable_fixup->count);
1009 for (i=0; i<vtable_fixup->count; i++)
1011 thunks[i] = thunk_template;
1012 thunks[i].fixup = fixup;
1013 thunks[i].function = ReallyFixupVTable;
1014 thunks[i].vtable_entry = &vtable[i];
1015 vtable[i] = PtrToUint(&thunks[i]);
1018 else
1020 ERR("unsupported vtable fixup flags %x\n", vtable_fixup->type);
1021 HeapFree(dll_fixup_heap, 0, fixup->thunk_code);
1022 HeapFree(GetProcessHeap(), 0, fixup);
1023 return;
1026 list_add_tail(&dll_fixups, &fixup->entry);
1029 static void FixupVTable(HMODULE hmodule)
1031 ASSEMBLY *assembly;
1032 HRESULT hr;
1033 VTableFixup *vtable_fixups;
1034 ULONG vtable_fixup_count, i;
1036 hr = assembly_from_hmodule(&assembly, hmodule);
1037 if (SUCCEEDED(hr))
1039 hr = assembly_get_vtable_fixups(assembly, &vtable_fixups, &vtable_fixup_count);
1040 if (CAN_FIXUP_VTABLE)
1041 for (i=0; i<vtable_fixup_count; i++)
1042 FixupVTableEntry(hmodule, &vtable_fixups[i]);
1043 else if (vtable_fixup_count)
1044 FIXME("cannot fixup vtable; expect a crash\n");
1046 assembly_release(assembly);
1048 else
1049 ERR("failed to read CLR headers, hr=%x\n", hr);
1052 __int32 WINAPI _CorExeMain(void)
1054 int exit_code;
1055 int argc;
1056 char **argv;
1057 MonoDomain *domain=NULL;
1058 MonoImage *image;
1059 MonoImageOpenStatus status;
1060 MonoAssembly *assembly=NULL;
1061 WCHAR filename[MAX_PATH];
1062 char *filenameA;
1063 ICLRRuntimeInfo *info;
1064 RuntimeHost *host;
1065 HRESULT hr;
1066 int i;
1068 get_utf8_args(&argc, &argv);
1070 GetModuleFileNameW(NULL, filename, MAX_PATH);
1072 TRACE("%s", debugstr_w(filename));
1073 for (i=0; i<argc; i++)
1074 TRACE(" %s", debugstr_a(argv[i]));
1075 TRACE("\n");
1077 filenameA = WtoA(filename);
1078 if (!filenameA)
1079 return -1;
1081 FixupVTable(GetModuleHandleW(NULL));
1083 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1085 if (SUCCEEDED(hr))
1087 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1089 if (SUCCEEDED(hr))
1090 hr = RuntimeHost_GetDefaultDomain(host, &domain);
1092 if (SUCCEEDED(hr))
1094 image = mono_image_open_from_module_handle(GetModuleHandleW(NULL),
1095 filenameA, 1, &status);
1097 if (image)
1098 assembly = mono_assembly_load_from(image, filenameA, &status);
1100 if (assembly)
1102 mono_trace_set_assembly(assembly);
1104 exit_code = mono_jit_exec(domain, assembly, argc, argv);
1106 else
1108 ERR("couldn't load %s, status=%d\n", debugstr_w(filename), status);
1109 exit_code = -1;
1112 RuntimeHost_DeleteDomain(host, domain);
1114 else
1115 exit_code = -1;
1117 ICLRRuntimeInfo_Release(info);
1119 else
1120 exit_code = -1;
1122 HeapFree(GetProcessHeap(), 0, argv);
1124 if (domain)
1126 mono_thread_manage();
1127 mono_jit_cleanup(domain);
1130 return exit_code;
1133 BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1135 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1137 switch (fdwReason)
1139 case DLL_PROCESS_ATTACH:
1140 DisableThreadLibraryCalls(hinstDLL);
1141 FixupVTable(hinstDLL);
1142 break;
1143 case DLL_PROCESS_DETACH:
1144 /* FIXME: clean up the vtables */
1145 break;
1147 return TRUE;
1150 /* called from DLL_PROCESS_ATTACH */
1151 void runtimehost_init(void)
1153 dll_fixup_heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
1154 list_init(&dll_fixups);
1157 /* called from DLL_PROCESS_DETACH */
1158 void runtimehost_uninit(void)
1160 struct dll_fixup *fixup, *fixup2;
1162 HeapDestroy(dll_fixup_heap);
1163 LIST_FOR_EACH_ENTRY_SAFE(fixup, fixup2, &dll_fixups, struct dll_fixup, entry)
1165 HeapFree(GetProcessHeap(), 0, fixup->tokens);
1166 HeapFree(GetProcessHeap(), 0, fixup);
1170 HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version, RuntimeHost** result)
1172 RuntimeHost *This;
1174 This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1175 if ( !This )
1176 return E_OUTOFMEMORY;
1178 This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
1179 This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
1181 This->ref = 1;
1182 This->version = runtime_version;
1183 list_init(&This->domains);
1184 This->default_domain = NULL;
1185 InitializeCriticalSection(&This->lock);
1186 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
1188 *result = This;
1190 return S_OK;
1193 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
1195 IUnknown *unk;
1196 HRESULT hr;
1198 if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
1200 unk = (IUnknown*)&This->ICorRuntimeHost_iface;
1201 IUnknown_AddRef(unk);
1203 else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
1205 unk = (IUnknown*)&This->ICLRRuntimeHost_iface;
1206 IUnknown_AddRef(unk);
1208 else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
1209 IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
1211 hr = MetaDataDispenser_CreateInstance(&unk);
1212 if (FAILED(hr))
1213 return hr;
1215 else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
1217 hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
1218 if (FAILED(hr))
1219 return hr;
1221 else
1222 unk = NULL;
1224 if (unk)
1226 hr = IUnknown_QueryInterface(unk, riid, ppv);
1228 IUnknown_Release(unk);
1230 return hr;
1232 else
1233 FIXME("not implemented for class %s\n", debugstr_guid(clsid));
1235 return CLASS_E_CLASSNOTAVAILABLE;
1238 #define CHARS_IN_GUID 39
1239 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
1241 HRESULT create_monodata(REFIID riid, LPVOID *ppObj )
1243 static const WCHAR wszAssembly[] = {'A','s','s','e','m','b','l','y',0};
1244 static const WCHAR wszCodebase[] = {'C','o','d','e','B','a','s','e',0};
1245 static const WCHAR wszClass[] = {'C','l','a','s','s',0};
1246 static const WCHAR wszFileSlash[] = {'f','i','l','e',':','/','/','/',0};
1247 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1248 static const WCHAR wszInprocServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1249 static const WCHAR wszDLL[] = {'.','d','l','l',0};
1250 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) + ARRAYSIZE(wszInprocServer32) - 1];
1251 MonoDomain *domain;
1252 MonoAssembly *assembly;
1253 ICLRRuntimeInfo *info = NULL;
1254 RuntimeHost *host;
1255 HRESULT hr;
1256 HKEY key, subkey;
1257 LONG res;
1258 int offset = 0;
1259 DWORD numKeys, keyLength;
1260 WCHAR codebase[MAX_PATH + 8];
1261 WCHAR classname[350], subkeyName[256];
1262 WCHAR filename[MAX_PATH];
1264 DWORD dwBufLen = 350;
1266 lstrcpyW(path, wszCLSIDSlash);
1267 StringFromGUID2(riid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
1268 lstrcatW(path, wszInprocServer32);
1270 TRACE("Registry key: %s\n", debugstr_w(path));
1272 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key);
1273 if (res == ERROR_FILE_NOT_FOUND)
1274 return CLASS_E_CLASSNOTAVAILABLE;
1276 res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen);
1277 if(res != ERROR_SUCCESS)
1279 WARN("Class value cannot be found.\n");
1280 hr = CLASS_E_CLASSNOTAVAILABLE;
1281 goto cleanup;
1284 TRACE("classname (%s)\n", debugstr_w(classname));
1286 dwBufLen = MAX_PATH + 8;
1287 res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen);
1288 if(res == ERROR_SUCCESS)
1290 /* Strip file:/// */
1291 if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0)
1292 offset = strlenW(wszFileSlash);
1294 strcpyW(filename, codebase + offset);
1296 else
1298 WCHAR assemblyname[MAX_PATH + 8];
1300 hr = CLASS_E_CLASSNOTAVAILABLE;
1301 WARN("CodeBase value cannot be found, trying Assembly.\n");
1302 /* get the last subkey of InprocServer32 */
1303 res = RegQueryInfoKeyW(key, 0, 0, 0, &numKeys, 0, 0, 0, 0, 0, 0, 0);
1304 if (res != ERROR_SUCCESS || numKeys == 0)
1305 goto cleanup;
1306 numKeys--;
1307 keyLength = sizeof(subkeyName) / sizeof(WCHAR);
1308 res = RegEnumKeyExW(key, numKeys, subkeyName, &keyLength, 0, 0, 0, 0);
1309 if (res != ERROR_SUCCESS)
1310 goto cleanup;
1311 res = RegOpenKeyExW(key, subkeyName, 0, KEY_READ, &subkey);
1312 if (res != ERROR_SUCCESS)
1313 goto cleanup;
1314 dwBufLen = MAX_PATH + 8;
1315 res = RegGetValueW(subkey, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen);
1316 RegCloseKey(subkey);
1317 if (res != ERROR_SUCCESS)
1318 goto cleanup;
1320 hr = get_file_from_strongname(assemblyname, filename, MAX_PATH);
1321 if (!SUCCEEDED(hr))
1324 * The registry doesn't have a CodeBase entry and it's not in the GAC.
1326 * Use the Assembly Key to retrieve the filename.
1327 * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null
1329 WCHAR *ns;
1331 WARN("Attempt to load from the application directory.\n");
1332 GetModuleFileNameW(NULL, filename, MAX_PATH);
1333 ns = strrchrW(filename, '\\');
1334 *(ns+1) = '\0';
1336 ns = strchrW(assemblyname, ',');
1337 *(ns) = '\0';
1338 strcatW(filename, assemblyname);
1339 *(ns) = '.';
1340 strcatW(filename, wszDLL);
1344 TRACE("filename (%s)\n", debugstr_w(filename));
1346 *ppObj = NULL;
1349 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1350 if (SUCCEEDED(hr))
1352 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1354 if (SUCCEEDED(hr))
1355 hr = RuntimeHost_GetDefaultDomain(host, &domain);
1357 if (SUCCEEDED(hr))
1359 MonoImage *image;
1360 MonoClass *klass;
1361 MonoObject *result;
1362 IUnknown *unk = NULL;
1363 char *filenameA, *ns;
1364 char *classA;
1366 hr = CLASS_E_CLASSNOTAVAILABLE;
1368 mono_thread_attach(domain);
1370 filenameA = WtoA(filename);
1371 assembly = mono_domain_assembly_open(domain, filenameA);
1372 HeapFree(GetProcessHeap(), 0, filenameA);
1373 if (!assembly)
1375 ERR("Cannot open assembly %s\n", filenameA);
1376 goto cleanup;
1379 image = mono_assembly_get_image(assembly);
1380 if (!image)
1382 ERR("Couldn't get assembly image\n");
1383 goto cleanup;
1386 classA = WtoA(classname);
1387 ns = strrchr(classA, '.');
1388 *ns = '\0';
1390 klass = mono_class_from_name(image, classA, ns+1);
1391 HeapFree(GetProcessHeap(), 0, classA);
1392 if (!klass)
1394 ERR("Couldn't get class from image\n");
1395 goto cleanup;
1399 * Use the default constructor for the .NET class.
1401 result = mono_object_new(domain, klass);
1402 mono_runtime_object_init(result);
1404 hr = RuntimeHost_GetIUnknownForObject(host, result, &unk);
1405 if (SUCCEEDED(hr))
1407 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj);
1409 IUnknown_Release(unk);
1411 else
1412 hr = CLASS_E_CLASSNOTAVAILABLE;
1414 else
1415 hr = CLASS_E_CLASSNOTAVAILABLE;
1417 else
1418 hr = CLASS_E_CLASSNOTAVAILABLE;
1420 cleanup:
1421 if(info)
1422 ICLRRuntimeInfo_Release(info);
1424 RegCloseKey(key);
1426 return hr;