TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / mscoree / corruntimehost.c
blobec9d54d644afb38b4614ff222e1471eb433ce8cb
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 HRESULT res=S_OK;
76 EnterCriticalSection(&This->lock);
78 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
79 if (!entry)
81 res = E_OUTOFMEMORY;
82 goto end;
85 /* FIXME: Use exe filename to name the domain? */
86 entry->domain = mono_jit_init_version("mscorlib.dll", "v4.0.30319");
88 if (!entry->domain)
90 HeapFree(GetProcessHeap(), 0, entry);
91 res = E_FAIL;
92 goto end;
95 is_mono_started = TRUE;
97 list_add_tail(&This->domains, &entry->entry);
99 *result = entry->domain;
101 end:
102 LeaveCriticalSection(&This->lock);
104 return res;
107 static HRESULT RuntimeHost_GetDefaultDomain(RuntimeHost *This, MonoDomain **result)
109 HRESULT res=S_OK;
111 EnterCriticalSection(&This->lock);
113 if (This->default_domain) goto end;
115 res = RuntimeHost_AddDomain(This, &This->default_domain);
117 end:
118 *result = This->default_domain;
120 LeaveCriticalSection(&This->lock);
122 return res;
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);
139 break;
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;
151 MonoImage *image;
152 MonoClass *klass;
153 MonoMethod *method;
154 MonoObject *exc;
155 static const char *get_hresult = "get_HResult";
157 *result = NULL;
159 mono_thread_attach(domain);
161 assembly = mono_domain_assembly_open(domain, assemblyname);
162 if (!assembly)
164 ERR("Cannot load assembly\n");
165 return E_FAIL;
168 image = mono_assembly_get_image(assembly);
169 if (!image)
171 ERR("Couldn't get assembly image\n");
172 return E_FAIL;
175 klass = mono_class_from_name(image, namespace, typename);
176 if (!klass)
178 ERR("Couldn't get class from image\n");
179 return E_FAIL;
182 method = mono_class_get_method_from_name(klass, methodname, arg_count);
183 if (!method)
185 ERR("Couldn't get method from class\n");
186 return E_FAIL;
189 *result = mono_runtime_invoke(method, obj, args, &exc);
190 if (exc)
192 HRESULT hr;
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);
200 if (SUCCEEDED(hr))
201 hr = *(HRESULT*)mono_object_unbox(hr_object);
202 if (SUCCEEDED(hr))
203 hr = E_FAIL;
205 else
206 hr = E_FAIL;
207 ERR("Method %s.%s raised an exception, hr=%x\n", namespace, typename, hr);
208 *result = NULL;
209 return hr;
212 return S_OK;
215 static HRESULT RuntimeHost_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *domain, IUnknown **punk)
217 HRESULT hr;
218 MonoObject *appdomain_object;
219 IUnknown *unk;
221 hr = RuntimeHost_Invoke(This, domain, "mscorlib", "System", "AppDomain", "get_CurrentDomain",
222 NULL, NULL, 0, &appdomain_object);
224 if (SUCCEEDED(hr))
225 hr = RuntimeHost_GetIUnknownForObject(This, appdomain_object, &unk);
227 if (SUCCEEDED(hr))
229 hr = IUnknown_QueryInterface(unk, &IID__AppDomain, (void**)punk);
231 IUnknown_Release(unk);
234 return hr;
237 void RuntimeHost_ExitProcess(RuntimeHost *This, INT exitcode)
239 HRESULT hr;
240 void *args[2];
241 MonoDomain *domain;
242 MonoObject *dummy;
244 hr = RuntimeHost_GetDefaultDomain(This, &domain);
245 if (FAILED(hr))
247 ERR("Cannot get domain, hr=%x\n", hr);
248 return;
251 args[0] = &exitcode;
252 args[1] = NULL;
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,
271 REFIID riid,
272 void **ppvObject)
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 ) )
280 *ppvObject = iface;
282 else
284 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
285 return E_NOINTERFACE;
288 ICorRuntimeHost_AddRef( iface );
290 return S_OK;
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 );
303 ULONG ref;
305 ref = InterlockedDecrement( &This->ref );
307 return ref;
310 /*** ICorRuntimeHost methods ***/
311 static HRESULT WINAPI corruntimehost_CreateLogicalThreadState(
312 ICorRuntimeHost* iface)
314 FIXME("stub %p\n", iface);
315 return E_NOTIMPL;
318 static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState(
319 ICorRuntimeHost* iface)
321 FIXME("stub %p\n", iface);
322 return E_NOTIMPL;
325 static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState(
326 ICorRuntimeHost* iface,
327 DWORD *fiberCookie)
329 FIXME("stub %p\n", iface);
330 return E_NOTIMPL;
333 static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState(
334 ICorRuntimeHost* iface,
335 DWORD **fiberCookie)
337 FIXME("stub %p\n", iface);
338 return E_NOTIMPL;
341 static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread(
342 ICorRuntimeHost* iface,
343 DWORD *pCount)
345 FIXME("stub %p\n", iface);
346 return E_NOTIMPL;
349 static HRESULT WINAPI corruntimehost_MapFile(
350 ICorRuntimeHost* iface,
351 HANDLE hFile,
352 HMODULE *mapAddress)
354 FIXME("stub %p\n", iface);
355 return E_NOTIMPL;
358 static HRESULT WINAPI corruntimehost_GetConfiguration(
359 ICorRuntimeHost* iface,
360 ICorConfiguration **pConfiguration)
362 FIXME("stub %p\n", iface);
363 return E_NOTIMPL;
366 static HRESULT WINAPI corruntimehost_Start(
367 ICorRuntimeHost* iface)
369 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
370 MonoDomain *dummy;
372 TRACE("%p\n", This);
374 return RuntimeHost_GetDefaultDomain(This, &dummy);
377 static HRESULT WINAPI corruntimehost_Stop(
378 ICorRuntimeHost* iface)
380 FIXME("stub %p\n", iface);
381 return E_NOTIMPL;
384 static HRESULT WINAPI corruntimehost_CreateDomain(
385 ICorRuntimeHost* iface,
386 LPCWSTR friendlyName,
387 IUnknown *identityArray,
388 IUnknown **appDomain)
390 FIXME("stub %p\n", iface);
391 return E_NOTIMPL;
394 static HRESULT WINAPI corruntimehost_GetDefaultDomain(
395 ICorRuntimeHost* iface,
396 IUnknown **pAppDomain)
398 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
399 HRESULT hr;
400 MonoDomain *domain;
402 TRACE("(%p)\n", iface);
404 hr = RuntimeHost_GetDefaultDomain(This, &domain);
406 if (SUCCEEDED(hr))
408 hr = RuntimeHost_GetIUnknownForDomain(This, domain, pAppDomain);
411 return hr;
414 static HRESULT WINAPI corruntimehost_EnumDomains(
415 ICorRuntimeHost* iface,
416 HDOMAINENUM *hEnum)
418 FIXME("stub %p\n", iface);
419 return E_NOTIMPL;
422 static HRESULT WINAPI corruntimehost_NextDomain(
423 ICorRuntimeHost* iface,
424 HDOMAINENUM hEnum,
425 IUnknown **appDomain)
427 FIXME("stub %p\n", iface);
428 return E_NOTIMPL;
431 static HRESULT WINAPI corruntimehost_CloseEnum(
432 ICorRuntimeHost* iface,
433 HDOMAINENUM hEnum)
435 FIXME("stub %p\n", iface);
436 return E_NOTIMPL;
439 static HRESULT WINAPI corruntimehost_CreateDomainEx(
440 ICorRuntimeHost* iface,
441 LPCWSTR friendlyName,
442 IUnknown *setup,
443 IUnknown *evidence,
444 IUnknown **appDomain)
446 FIXME("stub %p\n", iface);
447 return E_NOTIMPL;
450 static HRESULT WINAPI corruntimehost_CreateDomainSetup(
451 ICorRuntimeHost* iface,
452 IUnknown **appDomainSetup)
454 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
455 HRESULT hr;
456 MonoDomain *domain;
457 MonoObject *obj;
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);
464 if (SUCCEEDED(hr))
465 hr = RuntimeHost_CreateManagedInstance(This, classnameW, domain, &obj);
467 if (SUCCEEDED(hr))
468 hr = RuntimeHost_GetIUnknownForObject(This, obj, appDomainSetup);
470 return hr;
473 static HRESULT WINAPI corruntimehost_CreateEvidence(
474 ICorRuntimeHost* iface,
475 IUnknown **evidence)
477 FIXME("stub %p\n", iface);
478 return E_NOTIMPL;
481 static HRESULT WINAPI corruntimehost_UnloadDomain(
482 ICorRuntimeHost* iface,
483 IUnknown *appDomain)
485 FIXME("stub %p\n", iface);
486 return E_NOTIMPL;
489 static HRESULT WINAPI corruntimehost_CurrentDomain(
490 ICorRuntimeHost* iface,
491 IUnknown **appDomain)
493 FIXME("stub %p\n", iface);
494 return E_NOTIMPL;
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,
510 corruntimehost_Stop,
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,
524 REFIID riid,
525 void **ppvObject)
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 ) )
533 *ppvObject = iface;
535 else
537 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
538 return E_NOINTERFACE;
541 ICLRRuntimeHost_AddRef( iface );
543 return S_OK;
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);
561 return E_NOTIMPL;
564 static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
566 FIXME("(%p)\n", iface);
567 return E_NOTIMPL;
570 static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
571 IHostControl *pHostControl)
573 FIXME("(%p,%p)\n", iface, pHostControl);
574 return E_NOTIMPL;
577 static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
578 ICLRControl **pCLRControl)
580 FIXME("(%p,%p)\n", iface, pCLRControl);
581 return E_NOTIMPL;
584 static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
585 DWORD dwAppDomainId, BOOL fWaitUntilDone)
587 FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
588 return E_NOTIMPL;
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);
595 return E_NOTIMPL;
598 static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
599 DWORD *pdwAppDomainId)
601 FIXME("(%p,%p)\n", iface, pdwAppDomainId);
602 return E_NOTIMPL;
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);
610 return E_NOTIMPL;
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 );
618 HRESULT hr;
619 MonoDomain *domain;
620 MonoObject *result;
621 MonoString *str;
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);
630 if (SUCCEEDED(hr))
632 mono_thread_attach(domain);
634 filenameA = WtoA(pwzAssemblyPath);
635 if (!filenameA) hr = E_OUTOFMEMORY;
638 if (SUCCEEDED(hr))
640 classA = WtoA(pwzTypeName);
641 if (!classA) hr = E_OUTOFMEMORY;
644 if (SUCCEEDED(hr))
646 ns = strrchr(classA, '.');
647 if (ns)
648 *ns = '\0';
649 else
650 hr = E_INVALIDARG;
653 if (SUCCEEDED(hr))
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)
662 if (SUCCEEDED(hr))
664 argsA = WtoA(pwzArgument);
665 if (!argsA) hr = E_OUTOFMEMORY;
668 if (SUCCEEDED(hr))
670 str = mono_string_new(domain, argsA);
671 if (!str) hr = E_OUTOFMEMORY;
674 if (SUCCEEDED(hr))
676 hr = RuntimeHost_Invoke(This, domain, filenameA, classA, ns+1, methodA,
677 NULL, (void**)&str, 1, &result);
680 if (SUCCEEDED(hr))
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);
688 return hr;
691 static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
693 CLRRuntimeHost_QueryInterface,
694 CLRRuntimeHost_AddRef,
695 CLRRuntimeHost_Release,
696 CLRRuntimeHost_Start,
697 CLRRuntimeHost_Stop,
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)
713 HRESULT hr=S_OK;
714 char *nameA=NULL;
715 MonoType *type;
716 MonoClass *klass;
717 MonoObject *obj;
719 if (!domain)
720 hr = RuntimeHost_GetDefaultDomain(This, &domain);
722 if (SUCCEEDED(hr))
724 nameA = WtoA(name);
725 if (!nameA)
726 hr = E_OUTOFMEMORY;
729 if (SUCCEEDED(hr))
731 mono_thread_attach(domain);
733 type = mono_reflection_type_from_name(nameA, NULL);
734 if (!type)
736 ERR("Cannot find type %s\n", debugstr_w(name));
737 hr = E_FAIL;
741 if (SUCCEEDED(hr))
743 klass = mono_class_from_mono_type(type);
744 if (!klass)
746 ERR("Cannot convert type %s to a class\n", debugstr_w(name));
747 hr = E_FAIL;
751 if (SUCCEEDED(hr))
753 obj = mono_object_new(domain, klass);
754 if (!obj)
756 ERR("Cannot allocate object of type %s\n", debugstr_w(name));
757 hr = E_FAIL;
761 if (SUCCEEDED(hr))
763 /* FIXME: Detect exceptions from the constructor? */
764 mono_runtime_object_init(obj);
765 *result = obj;
768 HeapFree(GetProcessHeap(), 0, nameA);
770 return hr;
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,
784 IUnknown **ppUnk)
786 MonoDomain *domain;
787 MonoObject *result;
788 HRESULT hr;
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);
795 if (SUCCEEDED(hr))
796 *ppUnk = *(IUnknown**)mono_object_unbox(result);
797 else
798 *ppUnk = NULL;
800 return hr;
803 static void get_utf8_args(int *argc, char ***argv)
805 WCHAR **argvw;
806 int size=0, i;
807 char *current_arg;
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);
832 #if __i386__
834 # define CAN_FIXUP_VTABLE 1
836 #include "pshpack1.h"
838 struct vtable_fixup_thunk
840 /* push %ecx */
841 BYTE i7;
842 /* sub $0x4,%esp */
843 BYTE i1[3];
844 /* mov fixup,(%esp) */
845 BYTE i2[3];
846 struct dll_fixup *fixup;
847 /* mov function,%eax */
848 BYTE i3;
849 void (CDECL *function)(struct dll_fixup *);
850 /* call *%eax */
851 BYTE i4[2];
852 /* pop %eax */
853 BYTE i5;
854 /* pop %ecx */
855 BYTE i8;
856 /* jmp *vtable_entry */
857 BYTE i6[2];
858 void *vtable_entry;
861 static const struct vtable_fixup_thunk thunk_template = {
862 0x51,
863 {0x83,0xec,0x04},
864 {0xc7,0x04,0x24},
865 NULL,
866 0xb8,
867 NULL,
868 {0xff,0xd0},
869 0x58,
870 0x59,
871 {0xff,0x25},
872 NULL
875 #include "poppack.h"
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);
885 void *vtable_entry;
888 static const struct vtable_fixup_thunk thunk_template = {0};
890 #endif
892 static void CDECL ReallyFixupVTable(struct dll_fixup *fixup)
894 HRESULT hr=S_OK;
895 WCHAR filename[MAX_PATH];
896 ICLRRuntimeInfo *info=NULL;
897 RuntimeHost *host;
898 char *filenameA;
899 MonoImage *image=NULL;
900 MonoAssembly *assembly=NULL;
901 MonoImageOpenStatus status=0;
902 MonoDomain *domain;
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);
914 if (!filenameA)
915 hr = E_OUTOFMEMORY;
917 if (SUCCEEDED(hr))
918 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
920 if (SUCCEEDED(hr))
921 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
923 if (SUCCEEDED(hr))
924 hr = RuntimeHost_GetDefaultDomain(host, &domain);
926 if (SUCCEEDED(hr))
928 mono_thread_attach(domain);
930 assembly = mono_assembly_open(filenameA, &status);
933 if (assembly)
935 int i;
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));
952 fixup->done = TRUE;
955 if (info != NULL)
956 ICLRRuntimeInfo_Release(info);
958 HeapFree(GetProcessHeap(), 0, filenameA);
960 if (!fixup->done)
962 ERR("unable to fixup vtable, hr=%x, status=%d\n", hr, status);
963 /* If we returned now, we'd get an infinite loop. */
964 assert(0);
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;
985 fixup->done = FALSE;
987 if (vtable_fixup->type & COR_VTABLE_32BIT)
989 DWORD *vtable = fixup->vtable;
990 DWORD *tokens;
991 int i;
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]);
1008 else
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);
1013 return;
1016 list_add_tail(&dll_fixups, &fixup->entry);
1019 static void FixupVTable(HMODULE hmodule)
1021 ASSEMBLY *assembly;
1022 HRESULT hr;
1023 VTableFixup *vtable_fixups;
1024 ULONG vtable_fixup_count, i;
1026 hr = assembly_from_hmodule(&assembly, hmodule);
1027 if (SUCCEEDED(hr))
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);
1038 else
1039 ERR("failed to read CLR headers, hr=%x\n", hr);
1042 __int32 WINAPI _CorExeMain(void)
1044 int exit_code;
1045 int argc;
1046 char **argv;
1047 MonoDomain *domain=NULL;
1048 MonoImage *image;
1049 MonoImageOpenStatus status;
1050 MonoAssembly *assembly=NULL;
1051 WCHAR filename[MAX_PATH];
1052 char *filenameA;
1053 ICLRRuntimeInfo *info;
1054 RuntimeHost *host;
1055 HRESULT hr;
1056 int i;
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]));
1065 TRACE("\n");
1067 filenameA = WtoA(filename);
1068 if (!filenameA)
1069 return -1;
1071 FixupVTable(GetModuleHandleW(NULL));
1073 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1075 if (SUCCEEDED(hr))
1077 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1079 if (SUCCEEDED(hr))
1080 hr = RuntimeHost_GetDefaultDomain(host, &domain);
1082 if (SUCCEEDED(hr))
1084 image = mono_image_open_from_module_handle(GetModuleHandleW(NULL),
1085 filenameA, 1, &status);
1087 if (image)
1088 assembly = mono_assembly_load_from(image, filenameA, &status);
1090 if (assembly)
1092 mono_trace_set_assembly(assembly);
1094 exit_code = mono_jit_exec(domain, assembly, argc, argv);
1096 else
1098 ERR("couldn't load %s, status=%d\n", debugstr_w(filename), status);
1099 exit_code = -1;
1102 RuntimeHost_DeleteDomain(host, domain);
1104 else
1105 exit_code = -1;
1107 ICLRRuntimeInfo_Release(info);
1109 else
1110 exit_code = -1;
1112 HeapFree(GetProcessHeap(), 0, argv);
1114 if (domain)
1116 mono_thread_manage();
1117 mono_runtime_quit();
1120 return exit_code;
1123 BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1125 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1127 switch (fdwReason)
1129 case DLL_PROCESS_ATTACH:
1130 DisableThreadLibraryCalls(hinstDLL);
1131 FixupVTable(hinstDLL);
1132 break;
1133 case DLL_PROCESS_DETACH:
1134 /* FIXME: clean up the vtables */
1135 break;
1137 return TRUE;
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)
1162 RuntimeHost *This;
1164 This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1165 if ( !This )
1166 return E_OUTOFMEMORY;
1168 This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
1169 This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
1171 This->ref = 1;
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");
1178 *result = This;
1180 return S_OK;
1183 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
1185 IUnknown *unk;
1186 HRESULT hr;
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);
1202 if (FAILED(hr))
1203 return hr;
1205 else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
1207 hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
1208 if (FAILED(hr))
1209 return hr;
1211 else
1212 unk = NULL;
1214 if (unk)
1216 hr = IUnknown_QueryInterface(unk, riid, ppv);
1218 IUnknown_Release(unk);
1220 return hr;
1222 else
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];
1241 MonoDomain *domain;
1242 MonoAssembly *assembly;
1243 ICLRRuntimeInfo *info = NULL;
1244 RuntimeHost *host;
1245 HRESULT hr;
1246 HKEY key, subkey;
1247 LONG res;
1248 int offset = 0;
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;
1271 goto cleanup;
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);
1286 else
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)
1295 goto cleanup;
1296 numKeys--;
1297 keyLength = sizeof(subkeyName) / sizeof(WCHAR);
1298 res = RegEnumKeyExW(key, numKeys, subkeyName, &keyLength, 0, 0, 0, 0);
1299 if (res != ERROR_SUCCESS)
1300 goto cleanup;
1301 res = RegOpenKeyExW(key, subkeyName, 0, KEY_READ, &subkey);
1302 if (res != ERROR_SUCCESS)
1303 goto cleanup;
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)
1308 goto cleanup;
1310 hr = get_file_from_strongname(assemblyname, filename, MAX_PATH);
1311 if (FAILED(hr))
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
1319 WCHAR *ns;
1321 WARN("Attempt to load from the application directory.\n");
1322 GetModuleFileNameW(NULL, filename, MAX_PATH);
1323 ns = strrchrW(filename, '\\');
1324 *(ns+1) = '\0';
1326 ns = strchrW(assemblyname, ',');
1327 *(ns) = '\0';
1328 strcatW(filename, assemblyname);
1329 *(ns) = '.';
1330 strcatW(filename, wszDLL);
1334 TRACE("filename (%s)\n", debugstr_w(filename));
1336 *ppObj = NULL;
1339 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1340 if (SUCCEEDED(hr))
1342 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1344 if (SUCCEEDED(hr))
1345 hr = RuntimeHost_GetDefaultDomain(host, &domain);
1347 if (SUCCEEDED(hr))
1349 MonoImage *image;
1350 MonoClass *klass;
1351 MonoObject *result;
1352 IUnknown *unk = NULL;
1353 char *filenameA, *ns;
1354 char *classA;
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);
1363 if (!assembly)
1365 ERR("Cannot open assembly %s\n", filenameA);
1366 goto cleanup;
1369 image = mono_assembly_get_image(assembly);
1370 if (!image)
1372 ERR("Couldn't get assembly image\n");
1373 goto cleanup;
1376 classA = WtoA(classname);
1377 ns = strrchr(classA, '.');
1378 *ns = '\0';
1380 klass = mono_class_from_name(image, classA, ns+1);
1381 HeapFree(GetProcessHeap(), 0, classA);
1382 if (!klass)
1384 ERR("Couldn't get class from image\n");
1385 goto cleanup;
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);
1395 if (SUCCEEDED(hr))
1397 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj);
1399 IUnknown_Release(unk);
1401 else
1402 hr = CLASS_E_CLASSNOTAVAILABLE;
1404 else
1405 hr = CLASS_E_CLASSNOTAVAILABLE;
1407 else
1408 hr = CLASS_E_CLASSNOTAVAILABLE;
1410 cleanup:
1411 if(info)
1412 ICLRRuntimeInfo_Release(info);
1414 RegCloseKey(key);
1416 return hr;