vbscript: Added support for title and type arguments of MsgBox.
[wine.git] / dlls / mscoree / corruntimehost.c
blobb0a8b9dd9284a7dcee84609427dd4b06ed243589
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_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *domain, IUnknown **punk)
158 HRESULT hr;
159 void *args[1];
160 MonoAssembly *assembly;
161 MonoImage *image;
162 MonoClass *klass;
163 MonoMethod *method;
164 MonoObject *appdomain_object;
165 IUnknown *unk;
167 mono_thread_attach(domain);
169 assembly = mono_domain_assembly_open(domain, "mscorlib");
170 if (!assembly)
172 ERR("Cannot load mscorlib\n");
173 return E_FAIL;
176 image = mono_assembly_get_image(assembly);
177 if (!image)
179 ERR("Couldn't get assembly image\n");
180 return E_FAIL;
183 klass = mono_class_from_name(image, "System", "AppDomain");
184 if (!klass)
186 ERR("Couldn't get class from image\n");
187 return E_FAIL;
190 method = mono_class_get_method_from_name(klass, "get_CurrentDomain", 0);
191 if (!method)
193 ERR("Couldn't get method from class\n");
194 return E_FAIL;
197 args[0] = NULL;
198 appdomain_object = mono_runtime_invoke(method, NULL, args, NULL);
199 if (!appdomain_object)
201 ERR("Couldn't get result pointer\n");
202 return E_FAIL;
205 hr = RuntimeHost_GetIUnknownForObject(This, appdomain_object, &unk);
207 if (SUCCEEDED(hr))
209 hr = IUnknown_QueryInterface(unk, &IID__AppDomain, (void**)punk);
211 IUnknown_Release(unk);
214 return hr;
217 void RuntimeHost_ExitProcess(RuntimeHost *This, INT exitcode)
219 HRESULT hr;
220 void *args[2];
221 MonoDomain *domain;
222 MonoAssembly *assembly;
223 MonoImage *image;
224 MonoClass *klass;
225 MonoMethod *method;
227 hr = RuntimeHost_GetDefaultDomain(This, &domain);
228 if (FAILED(hr))
230 ERR("Cannot get domain, hr=%x\n", hr);
231 return;
234 mono_thread_attach(domain);
236 assembly = mono_domain_assembly_open(domain, "mscorlib");
237 if (!assembly)
239 ERR("Cannot load mscorlib\n");
240 return;
243 image = mono_assembly_get_image(assembly);
244 if (!image)
246 ERR("Couldn't get assembly image\n");
247 return;
250 klass = mono_class_from_name(image, "System", "Environment");
251 if (!klass)
253 ERR("Couldn't get class from image\n");
254 return;
257 method = mono_class_get_method_from_name(klass, "Exit", 1);
258 if (!method)
260 ERR("Couldn't get method from class\n");
261 return;
264 args[0] = &exitcode;
265 args[1] = NULL;
266 mono_runtime_invoke(method, NULL, args, NULL);
268 ERR("Process should have exited\n");
271 static inline RuntimeHost *impl_from_ICLRRuntimeHost( ICLRRuntimeHost *iface )
273 return CONTAINING_RECORD(iface, RuntimeHost, ICLRRuntimeHost_iface);
276 static inline RuntimeHost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
278 return CONTAINING_RECORD(iface, RuntimeHost, ICorRuntimeHost_iface);
281 /*** IUnknown methods ***/
282 static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
283 REFIID riid,
284 void **ppvObject)
286 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
287 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
289 if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) ||
290 IsEqualGUID( riid, &IID_IUnknown ) )
292 *ppvObject = iface;
294 else
296 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
297 return E_NOINTERFACE;
300 ICorRuntimeHost_AddRef( iface );
302 return S_OK;
305 static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface)
307 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
309 return InterlockedIncrement( &This->ref );
312 static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface)
314 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
315 ULONG ref;
317 ref = InterlockedDecrement( &This->ref );
319 return ref;
322 /*** ICorRuntimeHost methods ***/
323 static HRESULT WINAPI corruntimehost_CreateLogicalThreadState(
324 ICorRuntimeHost* iface)
326 FIXME("stub %p\n", iface);
327 return E_NOTIMPL;
330 static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState(
331 ICorRuntimeHost* iface)
333 FIXME("stub %p\n", iface);
334 return E_NOTIMPL;
337 static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState(
338 ICorRuntimeHost* iface,
339 DWORD *fiberCookie)
341 FIXME("stub %p\n", iface);
342 return E_NOTIMPL;
345 static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState(
346 ICorRuntimeHost* iface,
347 DWORD **fiberCookie)
349 FIXME("stub %p\n", iface);
350 return E_NOTIMPL;
353 static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread(
354 ICorRuntimeHost* iface,
355 DWORD *pCount)
357 FIXME("stub %p\n", iface);
358 return E_NOTIMPL;
361 static HRESULT WINAPI corruntimehost_MapFile(
362 ICorRuntimeHost* iface,
363 HANDLE hFile,
364 HMODULE *mapAddress)
366 FIXME("stub %p\n", iface);
367 return E_NOTIMPL;
370 static HRESULT WINAPI corruntimehost_GetConfiguration(
371 ICorRuntimeHost* iface,
372 ICorConfiguration **pConfiguration)
374 FIXME("stub %p\n", iface);
375 return E_NOTIMPL;
378 static HRESULT WINAPI corruntimehost_Start(
379 ICorRuntimeHost* iface)
381 FIXME("stub %p\n", iface);
382 return S_OK;
385 static HRESULT WINAPI corruntimehost_Stop(
386 ICorRuntimeHost* iface)
388 FIXME("stub %p\n", iface);
389 return E_NOTIMPL;
392 static HRESULT WINAPI corruntimehost_CreateDomain(
393 ICorRuntimeHost* iface,
394 LPCWSTR friendlyName,
395 IUnknown *identityArray,
396 IUnknown **appDomain)
398 FIXME("stub %p\n", iface);
399 return E_NOTIMPL;
402 static HRESULT WINAPI corruntimehost_GetDefaultDomain(
403 ICorRuntimeHost* iface,
404 IUnknown **pAppDomain)
406 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
407 HRESULT hr;
408 MonoDomain *domain;
410 TRACE("(%p)\n", iface);
412 hr = RuntimeHost_GetDefaultDomain(This, &domain);
414 if (SUCCEEDED(hr))
416 hr = RuntimeHost_GetIUnknownForDomain(This, domain, pAppDomain);
419 return hr;
422 static HRESULT WINAPI corruntimehost_EnumDomains(
423 ICorRuntimeHost* iface,
424 HDOMAINENUM *hEnum)
426 FIXME("stub %p\n", iface);
427 return E_NOTIMPL;
430 static HRESULT WINAPI corruntimehost_NextDomain(
431 ICorRuntimeHost* iface,
432 HDOMAINENUM hEnum,
433 IUnknown **appDomain)
435 FIXME("stub %p\n", iface);
436 return E_NOTIMPL;
439 static HRESULT WINAPI corruntimehost_CloseEnum(
440 ICorRuntimeHost* iface,
441 HDOMAINENUM hEnum)
443 FIXME("stub %p\n", iface);
444 return E_NOTIMPL;
447 static HRESULT WINAPI corruntimehost_CreateDomainEx(
448 ICorRuntimeHost* iface,
449 LPCWSTR friendlyName,
450 IUnknown *setup,
451 IUnknown *evidence,
452 IUnknown **appDomain)
454 FIXME("stub %p\n", iface);
455 return E_NOTIMPL;
458 static HRESULT WINAPI corruntimehost_CreateDomainSetup(
459 ICorRuntimeHost* iface,
460 IUnknown **appDomainSetup)
462 FIXME("stub %p\n", iface);
463 return E_NOTIMPL;
466 static HRESULT WINAPI corruntimehost_CreateEvidence(
467 ICorRuntimeHost* iface,
468 IUnknown **evidence)
470 FIXME("stub %p\n", iface);
471 return E_NOTIMPL;
474 static HRESULT WINAPI corruntimehost_UnloadDomain(
475 ICorRuntimeHost* iface,
476 IUnknown *appDomain)
478 FIXME("stub %p\n", iface);
479 return E_NOTIMPL;
482 static HRESULT WINAPI corruntimehost_CurrentDomain(
483 ICorRuntimeHost* iface,
484 IUnknown **appDomain)
486 FIXME("stub %p\n", iface);
487 return E_NOTIMPL;
490 static const struct ICorRuntimeHostVtbl corruntimehost_vtbl =
492 corruntimehost_QueryInterface,
493 corruntimehost_AddRef,
494 corruntimehost_Release,
495 corruntimehost_CreateLogicalThreadState,
496 corruntimehost_DeleteLogicalThreadState,
497 corruntimehost_SwitchInLogicalThreadState,
498 corruntimehost_SwitchOutLogicalThreadState,
499 corruntimehost_LocksHeldByLogicalThread,
500 corruntimehost_MapFile,
501 corruntimehost_GetConfiguration,
502 corruntimehost_Start,
503 corruntimehost_Stop,
504 corruntimehost_CreateDomain,
505 corruntimehost_GetDefaultDomain,
506 corruntimehost_EnumDomains,
507 corruntimehost_NextDomain,
508 corruntimehost_CloseEnum,
509 corruntimehost_CreateDomainEx,
510 corruntimehost_CreateDomainSetup,
511 corruntimehost_CreateEvidence,
512 corruntimehost_UnloadDomain,
513 corruntimehost_CurrentDomain
516 static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface,
517 REFIID riid,
518 void **ppvObject)
520 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
521 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
523 if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) ||
524 IsEqualGUID( riid, &IID_IUnknown ) )
526 *ppvObject = iface;
528 else
530 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
531 return E_NOINTERFACE;
534 ICLRRuntimeHost_AddRef( iface );
536 return S_OK;
539 static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface)
541 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
542 return ICorRuntimeHost_AddRef(&This->ICorRuntimeHost_iface);
545 static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface)
547 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
548 return ICorRuntimeHost_Release(&This->ICorRuntimeHost_iface);
551 static HRESULT WINAPI CLRRuntimeHost_Start(ICLRRuntimeHost* iface)
553 FIXME("(%p)\n", iface);
554 return E_NOTIMPL;
557 static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
559 FIXME("(%p)\n", iface);
560 return E_NOTIMPL;
563 static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
564 IHostControl *pHostControl)
566 FIXME("(%p,%p)\n", iface, pHostControl);
567 return E_NOTIMPL;
570 static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
571 ICLRControl **pCLRControl)
573 FIXME("(%p,%p)\n", iface, pCLRControl);
574 return E_NOTIMPL;
577 static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
578 DWORD dwAppDomainId, BOOL fWaitUntilDone)
580 FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
581 return E_NOTIMPL;
584 static HRESULT WINAPI CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost* iface,
585 DWORD dwAppDomainId, FExecuteInAppDomainCallback pCallback, void *cookie)
587 FIXME("(%p,%u,%p,%p)\n", iface, dwAppDomainId, pCallback, cookie);
588 return E_NOTIMPL;
591 static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
592 DWORD *pdwAppDomainId)
594 FIXME("(%p,%p)\n", iface, pdwAppDomainId);
595 return E_NOTIMPL;
598 static HRESULT WINAPI CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost* iface,
599 LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR *ppwzManifestPaths,
600 DWORD dwActivationData, LPCWSTR *ppwzActivationData, int *pReturnValue)
602 FIXME("(%p,%s,%u,%u)\n", iface, debugstr_w(pwzAppFullName), dwManifestPaths, dwActivationData);
603 return E_NOTIMPL;
606 static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* iface,
607 LPCWSTR pwzAssemblyPath, LPCWSTR pwzTypeName, LPCWSTR pwzMethodName,
608 LPCWSTR pwzArgument, DWORD *pReturnValue)
610 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
611 HRESULT hr;
612 MonoDomain *domain;
613 MonoAssembly *assembly;
614 MonoImage *image;
615 MonoClass *klass;
616 MonoMethod *method;
617 MonoObject *result;
618 MonoString *str;
619 void *args[2];
620 char *filenameA = NULL, *classA = NULL, *methodA = NULL;
621 char *argsA = NULL, *ns;
623 TRACE("(%p,%s,%s,%s,%s)\n", iface, debugstr_w(pwzAssemblyPath),
624 debugstr_w(pwzTypeName), debugstr_w(pwzMethodName), debugstr_w(pwzArgument));
626 hr = RuntimeHost_GetDefaultDomain(This, &domain);
627 if(hr != S_OK)
629 ERR("Couldn't get Default Domain\n");
630 return hr;
633 hr = E_FAIL;
635 mono_thread_attach(domain);
637 filenameA = WtoA(pwzAssemblyPath);
638 assembly = mono_domain_assembly_open(domain, filenameA);
639 if (!assembly)
641 ERR("Cannot open assembly %s\n", filenameA);
642 goto cleanup;
645 image = mono_assembly_get_image(assembly);
646 if (!image)
648 ERR("Couldn't get assembly image\n");
649 goto cleanup;
652 classA = WtoA(pwzTypeName);
653 ns = strrchr(classA, '.');
654 *ns = '\0';
655 klass = mono_class_from_name(image, classA, ns+1);
656 if (!klass)
658 ERR("Couldn't get class from image\n");
659 goto cleanup;
662 methodA = WtoA(pwzMethodName);
663 method = mono_class_get_method_from_name(klass, methodA, 1);
664 if (!method)
666 ERR("Couldn't get method from class\n");
667 goto cleanup;
670 /* The .NET function we are calling has the following declaration
671 * public static int functionName(String param)
673 argsA = WtoA(pwzArgument);
674 str = mono_string_new(domain, argsA);
675 args[0] = str;
676 args[1] = NULL;
677 result = mono_runtime_invoke(method, NULL, args, NULL);
678 if (!result)
679 ERR("Couldn't get result pointer\n");
680 else
682 *pReturnValue = *(DWORD*)mono_object_unbox(result);
683 hr = S_OK;
686 cleanup:
687 HeapFree(GetProcessHeap(), 0, filenameA);
688 HeapFree(GetProcessHeap(), 0, classA);
689 HeapFree(GetProcessHeap(), 0, argsA);
690 HeapFree(GetProcessHeap(), 0, methodA);
692 return hr;
695 static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
697 CLRRuntimeHost_QueryInterface,
698 CLRRuntimeHost_AddRef,
699 CLRRuntimeHost_Release,
700 CLRRuntimeHost_Start,
701 CLRRuntimeHost_Stop,
702 CLRRuntimeHost_SetHostControl,
703 CLRRuntimeHost_GetCLRControl,
704 CLRRuntimeHost_UnloadAppDomain,
705 CLRRuntimeHost_ExecuteInAppDomain,
706 CLRRuntimeHost_GetCurrentAppDomainId,
707 CLRRuntimeHost_ExecuteApplication,
708 CLRRuntimeHost_ExecuteInDefaultAppDomain
711 /* Create an instance of a type given its name, by calling its constructor with
712 * no arguments. Note that result MUST be in the stack, or the garbage
713 * collector may free it prematurely. */
714 HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
715 MonoDomain *domain, MonoObject **result)
717 HRESULT hr=S_OK;
718 char *nameA=NULL;
719 MonoType *type;
720 MonoClass *klass;
721 MonoObject *obj;
723 if (!domain)
724 hr = RuntimeHost_GetDefaultDomain(This, &domain);
726 if (SUCCEEDED(hr))
728 nameA = WtoA(name);
729 if (!nameA)
730 hr = E_OUTOFMEMORY;
733 if (SUCCEEDED(hr))
735 mono_thread_attach(domain);
737 type = mono_reflection_type_from_name(nameA, NULL);
738 if (!type)
740 ERR("Cannot find type %s\n", debugstr_w(name));
741 hr = E_FAIL;
745 if (SUCCEEDED(hr))
747 klass = mono_class_from_mono_type(type);
748 if (!klass)
750 ERR("Cannot convert type %s to a class\n", debugstr_w(name));
751 hr = E_FAIL;
755 if (SUCCEEDED(hr))
757 obj = mono_object_new(domain, klass);
758 if (!obj)
760 ERR("Cannot allocate object of type %s\n", debugstr_w(name));
761 hr = E_FAIL;
765 if (SUCCEEDED(hr))
767 /* FIXME: Detect exceptions from the constructor? */
768 mono_runtime_object_init(obj);
769 *result = obj;
772 HeapFree(GetProcessHeap(), 0, nameA);
774 return hr;
777 /* Get an IUnknown pointer for a Mono object.
779 * This is just a "light" wrapper around
780 * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
782 * NOTE: The IUnknown* is created with a reference to the object.
783 * Until they have a reference, objects must be in the stack to prevent the
784 * garbage collector from freeing them.
786 * mono_thread_attach must have already been called for this thread. */
787 HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj,
788 IUnknown **ppUnk)
790 MonoDomain *domain;
791 MonoAssembly *assembly;
792 MonoImage *image;
793 MonoClass *klass;
794 MonoMethod *method;
795 MonoObject *result;
796 void *args[2];
798 domain = mono_object_get_domain(obj);
800 assembly = mono_domain_assembly_open(domain, "mscorlib");
801 if (!assembly)
803 ERR("Cannot load mscorlib\n");
804 return E_FAIL;
807 image = mono_assembly_get_image(assembly);
808 if (!image)
810 ERR("Couldn't get assembly image\n");
811 return E_FAIL;
814 klass = mono_class_from_name(image, "System.Runtime.InteropServices", "Marshal");
815 if (!klass)
817 ERR("Couldn't get class from image\n");
818 return E_FAIL;
821 method = mono_class_get_method_from_name(klass, "GetIUnknownForObject", 1);
822 if (!method)
824 ERR("Couldn't get method from class\n");
825 return E_FAIL;
828 args[0] = obj;
829 args[1] = NULL;
830 result = mono_runtime_invoke(method, NULL, args, NULL);
831 if (!result)
833 ERR("Couldn't get result pointer\n");
834 return E_FAIL;
837 *ppUnk = *(IUnknown**)mono_object_unbox(result);
838 if (!*ppUnk)
840 ERR("GetIUnknownForObject returned 0\n");
841 return E_FAIL;
844 return S_OK;
847 static void get_utf8_args(int *argc, char ***argv)
849 WCHAR **argvw;
850 int size=0, i;
851 char *current_arg;
853 argvw = CommandLineToArgvW(GetCommandLineW(), argc);
855 for (i=0; i<*argc; i++)
857 size += sizeof(char*);
858 size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
860 size += sizeof(char*);
862 *argv = HeapAlloc(GetProcessHeap(), 0, size);
863 current_arg = (char*)(*argv + *argc + 1);
865 for (i=0; i<*argc; i++)
867 (*argv)[i] = current_arg;
868 current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
871 (*argv)[*argc] = NULL;
873 HeapFree(GetProcessHeap(), 0, argvw);
876 #if __i386__
878 # define CAN_FIXUP_VTABLE 1
880 #include "pshpack1.h"
882 struct vtable_fixup_thunk
884 /* push %ecx */
885 BYTE i7;
886 /* sub $0x4,%esp */
887 BYTE i1[3];
888 /* mov fixup,(%esp) */
889 BYTE i2[3];
890 struct dll_fixup *fixup;
891 /* mov function,%eax */
892 BYTE i3;
893 void (CDECL *function)(struct dll_fixup *);
894 /* call *%eax */
895 BYTE i4[2];
896 /* pop %eax */
897 BYTE i5;
898 /* pop %ecx */
899 BYTE i8;
900 /* jmp *vtable_entry */
901 BYTE i6[2];
902 void *vtable_entry;
905 static const struct vtable_fixup_thunk thunk_template = {
906 0x51,
907 {0x83,0xec,0x04},
908 {0xc7,0x04,0x24},
909 NULL,
910 0xb8,
911 NULL,
912 {0xff,0xd0},
913 0x58,
914 0x59,
915 {0xff,0x25},
916 NULL
919 #include "poppack.h"
921 #else /* !defined(__i386__) */
923 # define CAN_FIXUP_VTABLE 0
925 struct vtable_fixup_thunk
927 struct dll_fixup *fixup;
928 void (CDECL *function)(struct dll_fixup *fixup);
929 void *vtable_entry;
932 static const struct vtable_fixup_thunk thunk_template = {0};
934 #endif
936 static void CDECL ReallyFixupVTable(struct dll_fixup *fixup)
938 HRESULT hr=S_OK;
939 WCHAR filename[MAX_PATH];
940 ICLRRuntimeInfo *info=NULL;
941 RuntimeHost *host;
942 char *filenameA;
943 MonoImage *image=NULL;
944 MonoAssembly *assembly=NULL;
945 MonoImageOpenStatus status=0;
946 MonoDomain *domain;
948 if (fixup->done) return;
950 /* It's possible we'll have two threads doing this at once. This is
951 * considered preferable to the potential deadlock if we use a mutex. */
953 GetModuleFileNameW(fixup->dll, filename, MAX_PATH);
955 TRACE("%p,%p,%s\n", fixup, fixup->dll, debugstr_w(filename));
957 filenameA = WtoA(filename);
958 if (!filenameA)
959 hr = E_OUTOFMEMORY;
961 if (SUCCEEDED(hr))
962 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
964 if (SUCCEEDED(hr))
965 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
967 if (SUCCEEDED(hr))
968 hr = RuntimeHost_GetDefaultDomain(host, &domain);
970 if (SUCCEEDED(hr))
972 mono_thread_attach(domain);
974 assembly = mono_assembly_open(filenameA, &status);
977 if (assembly)
979 int i;
981 /* Mono needs an image that belongs to an assembly. */
982 image = mono_assembly_get_image(assembly);
984 if (fixup->fixup->type & COR_VTABLE_32BIT)
986 DWORD *vtable = fixup->vtable;
987 DWORD *tokens = fixup->tokens;
988 for (i=0; i<fixup->fixup->count; i++)
990 TRACE("%x\n", tokens[i]);
991 vtable[i] = PtrToUint(mono_marshal_get_vtfixup_ftnptr(
992 image, tokens[i], fixup->fixup->type));
996 fixup->done = TRUE;
999 if (info != NULL)
1000 ICLRRuntimeInfo_Release(info);
1002 HeapFree(GetProcessHeap(), 0, filenameA);
1004 if (!fixup->done)
1006 ERR("unable to fixup vtable, hr=%x, status=%d\n", hr, status);
1007 /* If we returned now, we'd get an infinite loop. */
1008 assert(0);
1012 static void FixupVTableEntry(HMODULE hmodule, VTableFixup *vtable_fixup)
1014 /* We can't actually generate code for the functions without loading mono,
1015 * and loading mono inside DllMain is a terrible idea. So we make thunks
1016 * that call ReallyFixupVTable, which will load the runtime and fill in the
1017 * vtable, then do an indirect jump using the (now filled in) vtable. Note
1018 * that we have to keep the thunks around forever, as one of them may get
1019 * called while we're filling in the table, and we can never be sure all
1020 * threads are clear. */
1021 struct dll_fixup *fixup;
1023 fixup = HeapAlloc(GetProcessHeap(), 0, sizeof(*fixup));
1025 fixup->dll = hmodule;
1026 fixup->thunk_code = HeapAlloc(dll_fixup_heap, 0, sizeof(struct vtable_fixup_thunk) * vtable_fixup->count);
1027 fixup->fixup = vtable_fixup;
1028 fixup->vtable = (BYTE*)hmodule + vtable_fixup->rva;
1029 fixup->done = FALSE;
1031 if (vtable_fixup->type & COR_VTABLE_32BIT)
1033 DWORD *vtable = fixup->vtable;
1034 DWORD *tokens;
1035 int i;
1036 struct vtable_fixup_thunk *thunks = fixup->thunk_code;
1038 if (sizeof(void*) > 4)
1039 ERR("32-bit fixup in 64-bit mode; broken image?\n");
1041 tokens = fixup->tokens = HeapAlloc(GetProcessHeap(), 0, sizeof(*tokens) * vtable_fixup->count);
1042 memcpy(tokens, vtable, sizeof(*tokens) * vtable_fixup->count);
1043 for (i=0; i<vtable_fixup->count; i++)
1045 thunks[i] = thunk_template;
1046 thunks[i].fixup = fixup;
1047 thunks[i].function = ReallyFixupVTable;
1048 thunks[i].vtable_entry = &vtable[i];
1049 vtable[i] = PtrToUint(&thunks[i]);
1052 else
1054 ERR("unsupported vtable fixup flags %x\n", vtable_fixup->type);
1055 HeapFree(dll_fixup_heap, 0, fixup->thunk_code);
1056 HeapFree(GetProcessHeap(), 0, fixup);
1057 return;
1060 list_add_tail(&dll_fixups, &fixup->entry);
1063 static void FixupVTable(HMODULE hmodule)
1065 ASSEMBLY *assembly;
1066 HRESULT hr;
1067 VTableFixup *vtable_fixups;
1068 ULONG vtable_fixup_count, i;
1070 hr = assembly_from_hmodule(&assembly, hmodule);
1071 if (SUCCEEDED(hr))
1073 hr = assembly_get_vtable_fixups(assembly, &vtable_fixups, &vtable_fixup_count);
1074 if (CAN_FIXUP_VTABLE)
1075 for (i=0; i<vtable_fixup_count; i++)
1076 FixupVTableEntry(hmodule, &vtable_fixups[i]);
1077 else if (vtable_fixup_count)
1078 FIXME("cannot fixup vtable; expect a crash\n");
1080 assembly_release(assembly);
1082 else
1083 ERR("failed to read CLR headers, hr=%x\n", hr);
1086 __int32 WINAPI _CorExeMain(void)
1088 int exit_code;
1089 int argc;
1090 char **argv;
1091 MonoDomain *domain=NULL;
1092 MonoImage *image;
1093 MonoImageOpenStatus status;
1094 MonoAssembly *assembly=NULL;
1095 WCHAR filename[MAX_PATH];
1096 char *filenameA;
1097 ICLRRuntimeInfo *info;
1098 RuntimeHost *host;
1099 HRESULT hr;
1100 int i;
1102 get_utf8_args(&argc, &argv);
1104 GetModuleFileNameW(NULL, filename, MAX_PATH);
1106 TRACE("%s", debugstr_w(filename));
1107 for (i=0; i<argc; i++)
1108 TRACE(" %s", debugstr_a(argv[i]));
1109 TRACE("\n");
1111 filenameA = WtoA(filename);
1112 if (!filenameA)
1113 return -1;
1115 FixupVTable(GetModuleHandleW(NULL));
1117 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1119 if (SUCCEEDED(hr))
1121 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1123 if (SUCCEEDED(hr))
1124 hr = RuntimeHost_GetDefaultDomain(host, &domain);
1126 if (SUCCEEDED(hr))
1128 image = mono_image_open_from_module_handle(GetModuleHandleW(NULL),
1129 filenameA, 1, &status);
1131 if (image)
1132 assembly = mono_assembly_load_from(image, filenameA, &status);
1134 if (assembly)
1136 mono_trace_set_assembly(assembly);
1138 exit_code = mono_jit_exec(domain, assembly, argc, argv);
1140 else
1142 ERR("couldn't load %s, status=%d\n", debugstr_w(filename), status);
1143 exit_code = -1;
1146 RuntimeHost_DeleteDomain(host, domain);
1148 else
1149 exit_code = -1;
1151 ICLRRuntimeInfo_Release(info);
1153 else
1154 exit_code = -1;
1156 HeapFree(GetProcessHeap(), 0, argv);
1158 if (domain)
1160 mono_thread_manage();
1161 mono_jit_cleanup(domain);
1164 return exit_code;
1167 BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1169 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1171 switch (fdwReason)
1173 case DLL_PROCESS_ATTACH:
1174 DisableThreadLibraryCalls(hinstDLL);
1175 FixupVTable(hinstDLL);
1176 break;
1177 case DLL_PROCESS_DETACH:
1178 /* FIXME: clean up the vtables */
1179 break;
1181 return TRUE;
1184 /* called from DLL_PROCESS_ATTACH */
1185 void runtimehost_init(void)
1187 dll_fixup_heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
1188 list_init(&dll_fixups);
1191 /* called from DLL_PROCESS_DETACH */
1192 void runtimehost_uninit(void)
1194 struct dll_fixup *fixup, *fixup2;
1196 HeapDestroy(dll_fixup_heap);
1197 LIST_FOR_EACH_ENTRY_SAFE(fixup, fixup2, &dll_fixups, struct dll_fixup, entry)
1199 HeapFree(GetProcessHeap(), 0, fixup->tokens);
1200 HeapFree(GetProcessHeap(), 0, fixup);
1204 HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version, RuntimeHost** result)
1206 RuntimeHost *This;
1208 This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1209 if ( !This )
1210 return E_OUTOFMEMORY;
1212 This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
1213 This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
1215 This->ref = 1;
1216 This->version = runtime_version;
1217 list_init(&This->domains);
1218 This->default_domain = NULL;
1219 InitializeCriticalSection(&This->lock);
1220 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
1222 *result = This;
1224 return S_OK;
1227 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
1229 IUnknown *unk;
1230 HRESULT hr;
1232 if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
1234 unk = (IUnknown*)&This->ICorRuntimeHost_iface;
1235 IUnknown_AddRef(unk);
1237 else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
1239 unk = (IUnknown*)&This->ICLRRuntimeHost_iface;
1240 IUnknown_AddRef(unk);
1242 else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
1243 IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
1245 hr = MetaDataDispenser_CreateInstance(&unk);
1246 if (FAILED(hr))
1247 return hr;
1249 else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
1251 hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
1252 if (FAILED(hr))
1253 return hr;
1255 else
1256 unk = NULL;
1258 if (unk)
1260 hr = IUnknown_QueryInterface(unk, riid, ppv);
1262 IUnknown_Release(unk);
1264 return hr;
1266 else
1267 FIXME("not implemented for class %s\n", debugstr_guid(clsid));
1269 return CLASS_E_CLASSNOTAVAILABLE;
1272 #define CHARS_IN_GUID 39
1273 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
1275 HRESULT create_monodata(REFIID riid, LPVOID *ppObj )
1277 static const WCHAR wszAssembly[] = {'A','s','s','e','m','b','l','y',0};
1278 static const WCHAR wszCodebase[] = {'C','o','d','e','B','a','s','e',0};
1279 static const WCHAR wszClass[] = {'C','l','a','s','s',0};
1280 static const WCHAR wszFileSlash[] = {'f','i','l','e',':','/','/','/',0};
1281 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1282 static const WCHAR wszInprocServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1283 static const WCHAR wszDLL[] = {'.','d','l','l',0};
1284 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) + ARRAYSIZE(wszInprocServer32) - 1];
1285 MonoDomain *domain;
1286 MonoAssembly *assembly;
1287 ICLRRuntimeInfo *info = NULL;
1288 RuntimeHost *host;
1289 HRESULT hr;
1290 HKEY key, subkey;
1291 LONG res;
1292 int offset = 0;
1293 DWORD numKeys, keyLength;
1294 WCHAR codebase[MAX_PATH + 8];
1295 WCHAR classname[350], subkeyName[256];
1296 WCHAR filename[MAX_PATH];
1298 DWORD dwBufLen = 350;
1300 lstrcpyW(path, wszCLSIDSlash);
1301 StringFromGUID2(riid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
1302 lstrcatW(path, wszInprocServer32);
1304 TRACE("Registry key: %s\n", debugstr_w(path));
1306 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key);
1307 if (res == ERROR_FILE_NOT_FOUND)
1308 return CLASS_E_CLASSNOTAVAILABLE;
1310 res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen);
1311 if(res != ERROR_SUCCESS)
1313 WARN("Class value cannot be found.\n");
1314 hr = CLASS_E_CLASSNOTAVAILABLE;
1315 goto cleanup;
1318 TRACE("classname (%s)\n", debugstr_w(classname));
1320 dwBufLen = MAX_PATH + 8;
1321 res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen);
1322 if(res == ERROR_SUCCESS)
1324 /* Strip file:/// */
1325 if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0)
1326 offset = strlenW(wszFileSlash);
1328 strcpyW(filename, codebase + offset);
1330 else
1332 WCHAR assemblyname[MAX_PATH + 8];
1334 hr = CLASS_E_CLASSNOTAVAILABLE;
1335 WARN("CodeBase value cannot be found, trying Assembly.\n");
1336 /* get the last subkey of InprocServer32 */
1337 res = RegQueryInfoKeyW(key, 0, 0, 0, &numKeys, 0, 0, 0, 0, 0, 0, 0);
1338 if (res != ERROR_SUCCESS || numKeys == 0)
1339 goto cleanup;
1340 numKeys--;
1341 keyLength = sizeof(subkeyName) / sizeof(WCHAR);
1342 res = RegEnumKeyExW(key, numKeys, subkeyName, &keyLength, 0, 0, 0, 0);
1343 if (res != ERROR_SUCCESS)
1344 goto cleanup;
1345 res = RegOpenKeyExW(key, subkeyName, 0, KEY_READ, &subkey);
1346 if (res != ERROR_SUCCESS)
1347 goto cleanup;
1348 dwBufLen = MAX_PATH + 8;
1349 res = RegGetValueW(subkey, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen);
1350 RegCloseKey(subkey);
1351 if (res != ERROR_SUCCESS)
1352 goto cleanup;
1354 hr = get_file_from_strongname(assemblyname, filename, MAX_PATH);
1355 if (!SUCCEEDED(hr))
1358 * The registry doesn't have a CodeBase entry and it's not in the GAC.
1360 * Use the Assembly Key to retrieve the filename.
1361 * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null
1363 WCHAR *ns;
1365 WARN("Attempt to load from the application directory.\n");
1366 GetModuleFileNameW(NULL, filename, MAX_PATH);
1367 ns = strrchrW(filename, '\\');
1368 *(ns+1) = '\0';
1370 ns = strchrW(assemblyname, ',');
1371 *(ns) = '\0';
1372 strcatW(filename, assemblyname);
1373 *(ns) = '.';
1374 strcatW(filename, wszDLL);
1378 TRACE("filename (%s)\n", debugstr_w(filename));
1380 *ppObj = NULL;
1383 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1384 if (SUCCEEDED(hr))
1386 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1388 if (SUCCEEDED(hr))
1389 hr = RuntimeHost_GetDefaultDomain(host, &domain);
1391 if (SUCCEEDED(hr))
1393 MonoImage *image;
1394 MonoClass *klass;
1395 MonoObject *result;
1396 IUnknown *unk = NULL;
1397 char *filenameA, *ns;
1398 char *classA;
1400 hr = CLASS_E_CLASSNOTAVAILABLE;
1402 mono_thread_attach(domain);
1404 filenameA = WtoA(filename);
1405 assembly = mono_domain_assembly_open(domain, filenameA);
1406 HeapFree(GetProcessHeap(), 0, filenameA);
1407 if (!assembly)
1409 ERR("Cannot open assembly %s\n", filenameA);
1410 goto cleanup;
1413 image = mono_assembly_get_image(assembly);
1414 if (!image)
1416 ERR("Couldn't get assembly image\n");
1417 goto cleanup;
1420 classA = WtoA(classname);
1421 ns = strrchr(classA, '.');
1422 *ns = '\0';
1424 klass = mono_class_from_name(image, classA, ns+1);
1425 HeapFree(GetProcessHeap(), 0, classA);
1426 if (!klass)
1428 ERR("Couldn't get class from image\n");
1429 goto cleanup;
1433 * Use the default constructor for the .NET class.
1435 result = mono_object_new(domain, klass);
1436 mono_runtime_object_init(result);
1438 hr = RuntimeHost_GetIUnknownForObject(host, result, &unk);
1439 if (SUCCEEDED(hr))
1441 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj);
1443 IUnknown_Release(unk);
1445 else
1446 hr = CLASS_E_CLASSNOTAVAILABLE;
1448 else
1449 hr = CLASS_E_CLASSNOTAVAILABLE;
1451 else
1452 hr = CLASS_E_CLASSNOTAVAILABLE;
1454 cleanup:
1455 if(info)
1456 ICLRRuntimeInfo_Release(info);
1458 RegCloseKey(key);
1460 return hr;