winedump: Dump MSC's S_UNAMESPACE entries.
[wine.git] / dlls / mscoree / corruntimehost.c
blobec06717be85fc8b79bfe0e369c4d7dea81ca2ff8
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"
32 #include "shlwapi.h"
34 #include "cor.h"
35 #include "mscoree.h"
36 #include "metahost.h"
37 #include "corhdr.h"
38 #include "cordebug.h"
39 #include "wine/list.h"
40 #include "mscoree_private.h"
42 #include "wine/debug.h"
43 #include "wine/heap.h"
45 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
47 #include "initguid.h"
49 DEFINE_GUID(IID__AppDomain, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13);
51 struct DomainEntry
53 struct list entry;
54 MonoDomain *domain;
57 static HANDLE dll_fixup_heap; /* using a separate heap so we can have execute permission */
59 static CRITICAL_SECTION fixup_list_cs;
60 static CRITICAL_SECTION_DEBUG fixup_list_cs_debug =
62 0, 0, &fixup_list_cs,
63 { &fixup_list_cs_debug.ProcessLocksList,
64 &fixup_list_cs_debug.ProcessLocksList },
65 0, 0, { (DWORD_PTR)(__FILE__ ": fixup_list_cs") }
67 static CRITICAL_SECTION fixup_list_cs = { &fixup_list_cs_debug, -1, 0, 0, 0, 0 };
69 static struct list dll_fixups;
71 WCHAR **private_path = NULL;
73 struct dll_fixup
75 struct list entry;
76 BOOL done;
77 HMODULE dll;
78 void *thunk_code; /* pointer into dll_fixup_heap */
79 VTableFixup *fixup;
80 void *vtable;
81 void *tokens; /* pointer into process heap */
84 struct comclassredirect_data
86 ULONG size;
87 ULONG flags;
88 DWORD model;
89 GUID clsid;
90 GUID alias;
91 GUID clsid2;
92 GUID tlbid;
93 ULONG name_len;
94 ULONG name_offset;
95 ULONG progid_len;
96 ULONG progid_offset;
97 ULONG clrdata_len;
98 ULONG clrdata_offset;
99 DWORD miscstatus;
100 DWORD miscstatuscontent;
101 DWORD miscstatusthumbnail;
102 DWORD miscstatusicon;
103 DWORD miscstatusdocprint;
106 struct clrclass_data
108 ULONG size;
109 DWORD res[2];
110 ULONG module_len;
111 ULONG module_offset;
112 ULONG name_len;
113 ULONG name_offset;
114 ULONG version_len;
115 ULONG version_offset;
116 DWORD res2[2];
119 static MonoDomain* domain_attach(MonoDomain *domain)
121 MonoDomain *prev_domain = mono_domain_get();
123 if (prev_domain == domain)
124 /* Do not set or restore domain. */
125 return NULL;
127 mono_thread_attach(domain);
129 return prev_domain;
132 static void domain_restore(MonoDomain *prev_domain)
134 if (prev_domain != NULL)
135 mono_domain_set(prev_domain, FALSE);
138 static HRESULT RuntimeHost_GetDefaultDomain(RuntimeHost *This, const WCHAR *config_path, MonoDomain **result)
140 WCHAR exe_config[MAX_PATH];
141 WCHAR base_dir[MAX_PATH];
142 char *base_dirA, *config_pathA, *slash;
143 HRESULT res=S_OK;
144 static BOOL configured_domain;
146 *result = get_root_domain();
148 EnterCriticalSection(&This->lock);
150 if (configured_domain) goto end;
152 if (!config_path)
154 GetModuleFileNameW(NULL, exe_config, MAX_PATH);
155 lstrcatW(exe_config, L".config");
157 config_path = exe_config;
160 config_pathA = WtoA(config_path);
161 if (!config_pathA)
163 res = E_OUTOFMEMORY;
164 goto end;
167 GetModuleFileNameW(NULL, base_dir, ARRAY_SIZE(base_dir));
168 base_dirA = WtoA(base_dir);
169 if (!base_dirA)
171 HeapFree(GetProcessHeap(), 0, config_pathA);
172 res = E_OUTOFMEMORY;
173 goto end;
176 slash = strrchr(base_dirA, '\\');
177 if (slash)
178 *(slash + 1) = 0;
180 TRACE("setting base_dir: %s, config_path: %s\n", base_dirA, config_pathA);
181 mono_domain_set_config(*result, base_dirA, config_pathA);
183 HeapFree(GetProcessHeap(), 0, config_pathA);
184 HeapFree(GetProcessHeap(), 0, base_dirA);
186 end:
188 configured_domain = TRUE;
190 LeaveCriticalSection(&This->lock);
192 return res;
195 static BOOL RuntimeHost_GetMethod(MonoDomain *domain, const char *assemblyname,
196 const char *namespace, const char *typename, const char *methodname, int arg_count,
197 MonoMethod **method)
199 MonoAssembly *assembly;
200 MonoImage *image;
201 MonoClass *klass;
203 if (!assemblyname)
205 image = mono_get_corlib();
207 else
209 MonoImageOpenStatus status;
210 assembly = mono_assembly_open(assemblyname, &status);
211 if (!assembly)
213 ERR("Cannot load assembly %s, status=%i\n", assemblyname, status);
214 return FALSE;
217 image = mono_assembly_get_image(assembly);
218 if (!image)
220 ERR("Couldn't get assembly image for %s\n", assemblyname);
221 return FALSE;
225 klass = mono_class_from_name(image, namespace, typename);
226 if (!klass)
228 ERR("Couldn't get class %s.%s from image\n", namespace, typename);
229 return FALSE;
232 *method = mono_class_get_method_from_name(klass, methodname, arg_count);
233 if (!*method)
235 ERR("Couldn't get method %s from class %s.%s\n", methodname, namespace, typename);
236 return FALSE;
239 return TRUE;
242 static HRESULT RuntimeHost_Invoke(RuntimeHost *This, MonoDomain *domain,
243 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
244 MonoObject *obj, void **args, int arg_count, MonoObject **result);
246 static HRESULT RuntimeHost_DoInvoke(RuntimeHost *This, MonoDomain *domain,
247 const char *methodname, MonoMethod *method, MonoObject *obj, void **args, MonoObject **result)
249 MonoObject *exc;
250 static const char *get_hresult = "get_HResult";
252 *result = mono_runtime_invoke(method, obj, args, &exc);
253 if (exc)
255 HRESULT hr;
256 MonoObject *hr_object;
258 if (methodname != get_hresult)
260 /* Map the exception to an HRESULT. */
261 hr = RuntimeHost_Invoke(This, domain, NULL, "System", "Exception", get_hresult,
262 exc, NULL, 0, &hr_object);
263 if (SUCCEEDED(hr))
264 hr = *(HRESULT*)mono_object_unbox(hr_object);
265 if (SUCCEEDED(hr))
266 hr = E_FAIL;
268 else
269 hr = E_FAIL;
270 *result = NULL;
271 return hr;
274 return S_OK;
277 static HRESULT RuntimeHost_Invoke(RuntimeHost *This, MonoDomain *domain,
278 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
279 MonoObject *obj, void **args, int arg_count, MonoObject **result)
281 MonoMethod *method;
282 MonoDomain *prev_domain;
283 HRESULT hr;
285 *result = NULL;
287 prev_domain = domain_attach(domain);
289 if (!RuntimeHost_GetMethod(domain, assemblyname, namespace, typename, methodname,
290 arg_count, &method))
292 domain_restore(prev_domain);
293 return E_FAIL;
296 hr = RuntimeHost_DoInvoke(This, domain, methodname, method, obj, args, result);
297 if (FAILED(hr))
299 ERR("Method %s.%s:%s raised an exception, hr=%x\n", namespace, typename, methodname, hr);
302 domain_restore(prev_domain);
304 return hr;
307 static HRESULT RuntimeHost_VirtualInvoke(RuntimeHost *This, MonoDomain *domain,
308 const char *assemblyname, const char *namespace, const char *typename, const char *methodname,
309 MonoObject *obj, void **args, int arg_count, MonoObject **result)
311 MonoMethod *method;
312 MonoDomain *prev_domain;
313 HRESULT hr;
315 *result = NULL;
317 if (!obj)
319 ERR("\"this\" object cannot be null\n");
320 return E_POINTER;
323 prev_domain = domain_attach(domain);
325 if (!RuntimeHost_GetMethod(domain, assemblyname, namespace, typename, methodname,
326 arg_count, &method))
328 domain_restore(prev_domain);
329 return E_FAIL;
332 method = mono_object_get_virtual_method(obj, method);
333 if (!method)
335 ERR("Object %p does not support method %s.%s:%s\n", obj, namespace, typename, methodname);
336 domain_restore(prev_domain);
337 return E_FAIL;
340 hr = RuntimeHost_DoInvoke(This, domain, methodname, method, obj, args, result);
341 if (FAILED(hr))
343 ERR("Method %s.%s:%s raised an exception, hr=%x\n", namespace, typename, methodname, hr);
346 domain_restore(prev_domain);
348 return hr;
351 static HRESULT RuntimeHost_GetObjectForIUnknown(RuntimeHost *This, MonoDomain *domain,
352 IUnknown *unk, MonoObject **obj)
354 HRESULT hr;
355 void *args[1];
356 MonoObject *result;
358 args[0] = &unk;
359 hr = RuntimeHost_Invoke(This, domain, NULL, "System.Runtime.InteropServices", "Marshal", "GetObjectForIUnknown",
360 NULL, args, 1, &result);
362 if (SUCCEEDED(hr))
364 *obj = result;
366 return hr;
369 static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, const WCHAR *name, IUnknown *setup,
370 IUnknown *evidence, MonoDomain **result)
372 HRESULT res;
373 char *nameA;
374 MonoDomain *domain;
375 void *args[3];
376 MonoObject *new_domain, *id;
378 res = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
379 if (FAILED(res))
381 return res;
384 nameA = WtoA(name);
385 if (!nameA)
387 return E_OUTOFMEMORY;
390 args[0] = mono_string_new(domain, nameA);
391 HeapFree(GetProcessHeap(), 0, nameA);
393 if (!args[0])
395 return E_OUTOFMEMORY;
398 if (evidence)
400 res = RuntimeHost_GetObjectForIUnknown(This, domain, evidence, (MonoObject **)&args[1]);
401 if (FAILED(res))
403 return res;
406 else
408 args[1] = NULL;
411 if (setup)
413 res = RuntimeHost_GetObjectForIUnknown(This, domain, setup, (MonoObject **)&args[2]);
414 if (FAILED(res))
416 return res;
419 else
421 args[2] = NULL;
424 res = RuntimeHost_Invoke(This, domain, NULL, "System", "AppDomain", "CreateDomain",
425 NULL, args, 3, &new_domain);
427 if (FAILED(res))
429 return res;
432 /* new_domain is not the AppDomain itself, but a transparent proxy.
433 * So, we'll retrieve its ID, and use that to get the real domain object.
434 * We can't do a regular invoke, because that will bypass the proxy.
435 * Instead, do a vcall.
438 res = RuntimeHost_VirtualInvoke(This, domain, NULL, "System", "AppDomain", "get_Id",
439 new_domain, NULL, 0, &id);
441 if (FAILED(res))
443 return res;
446 TRACE("returning domain id %d\n", *(int *)mono_object_unbox(id));
448 *result = mono_domain_get_by_id(*(int *)mono_object_unbox(id));
450 return S_OK;
453 static HRESULT RuntimeHost_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *domain, IUnknown **punk)
455 HRESULT hr;
456 MonoObject *appdomain_object;
457 IUnknown *unk;
459 hr = RuntimeHost_Invoke(This, domain, NULL, "System", "AppDomain", "get_CurrentDomain",
460 NULL, NULL, 0, &appdomain_object);
462 if (SUCCEEDED(hr))
463 hr = RuntimeHost_GetIUnknownForObject(This, appdomain_object, &unk);
465 if (SUCCEEDED(hr))
467 hr = IUnknown_QueryInterface(unk, &IID__AppDomain, (void**)punk);
469 IUnknown_Release(unk);
472 return hr;
475 void RuntimeHost_ExitProcess(RuntimeHost *This, INT exitcode)
477 HRESULT hr;
478 void *args[2];
479 MonoDomain *domain;
480 MonoObject *dummy;
482 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
483 if (FAILED(hr))
485 ERR("Cannot get domain, hr=%x\n", hr);
486 return;
489 args[0] = &exitcode;
490 args[1] = NULL;
491 RuntimeHost_Invoke(This, domain, NULL, "System", "Environment", "Exit",
492 NULL, args, 1, &dummy);
494 ERR("Process should have exited\n");
497 static inline RuntimeHost *impl_from_ICLRRuntimeHost( ICLRRuntimeHost *iface )
499 return CONTAINING_RECORD(iface, RuntimeHost, ICLRRuntimeHost_iface);
502 static inline RuntimeHost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
504 return CONTAINING_RECORD(iface, RuntimeHost, ICorRuntimeHost_iface);
507 /*** IUnknown methods ***/
508 static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
509 REFIID riid,
510 void **ppvObject)
512 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
513 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
515 if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) ||
516 IsEqualGUID( riid, &IID_IUnknown ) )
518 *ppvObject = iface;
520 else
522 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
523 return E_NOINTERFACE;
526 ICorRuntimeHost_AddRef( iface );
528 return S_OK;
531 static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface)
533 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
535 return InterlockedIncrement( &This->ref );
538 static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface)
540 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
541 ULONG ref;
543 ref = InterlockedDecrement( &This->ref );
545 return ref;
548 /*** ICorRuntimeHost methods ***/
549 static HRESULT WINAPI corruntimehost_CreateLogicalThreadState(
550 ICorRuntimeHost* iface)
552 FIXME("stub %p\n", iface);
553 return E_NOTIMPL;
556 static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState(
557 ICorRuntimeHost* iface)
559 FIXME("stub %p\n", iface);
560 return E_NOTIMPL;
563 static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState(
564 ICorRuntimeHost* iface,
565 DWORD *fiberCookie)
567 FIXME("stub %p\n", iface);
568 return E_NOTIMPL;
571 static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState(
572 ICorRuntimeHost* iface,
573 DWORD **fiberCookie)
575 FIXME("stub %p\n", iface);
576 return E_NOTIMPL;
579 static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread(
580 ICorRuntimeHost* iface,
581 DWORD *pCount)
583 FIXME("stub %p\n", iface);
584 return E_NOTIMPL;
587 static HRESULT WINAPI corruntimehost_MapFile(
588 ICorRuntimeHost* iface,
589 HANDLE hFile,
590 HMODULE *mapAddress)
592 FIXME("stub %p\n", iface);
593 return E_NOTIMPL;
596 static HRESULT WINAPI corruntimehost_GetConfiguration(
597 ICorRuntimeHost* iface,
598 ICorConfiguration **pConfiguration)
600 FIXME("stub %p\n", iface);
601 return E_NOTIMPL;
604 static HRESULT WINAPI corruntimehost_Start(
605 ICorRuntimeHost* iface)
607 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
608 MonoDomain *dummy;
610 TRACE("%p\n", This);
612 return RuntimeHost_GetDefaultDomain(This, NULL, &dummy);
615 static HRESULT WINAPI corruntimehost_Stop(
616 ICorRuntimeHost* iface)
618 FIXME("stub %p\n", iface);
619 return E_NOTIMPL;
622 static HRESULT WINAPI corruntimehost_CreateDomain(
623 ICorRuntimeHost* iface,
624 LPCWSTR friendlyName,
625 IUnknown *identityArray,
626 IUnknown **appDomain)
628 return ICorRuntimeHost_CreateDomainEx(iface, friendlyName, NULL, NULL, appDomain);
631 static HRESULT WINAPI corruntimehost_GetDefaultDomain(
632 ICorRuntimeHost* iface,
633 IUnknown **pAppDomain)
635 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
636 HRESULT hr;
637 MonoDomain *domain;
639 TRACE("(%p)\n", iface);
641 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
643 if (SUCCEEDED(hr))
645 hr = RuntimeHost_GetIUnknownForDomain(This, domain, pAppDomain);
648 return hr;
651 static HRESULT WINAPI corruntimehost_EnumDomains(
652 ICorRuntimeHost* iface,
653 HDOMAINENUM *hEnum)
655 FIXME("stub %p\n", iface);
656 return E_NOTIMPL;
659 static HRESULT WINAPI corruntimehost_NextDomain(
660 ICorRuntimeHost* iface,
661 HDOMAINENUM hEnum,
662 IUnknown **appDomain)
664 FIXME("stub %p\n", iface);
665 return E_NOTIMPL;
668 static HRESULT WINAPI corruntimehost_CloseEnum(
669 ICorRuntimeHost* iface,
670 HDOMAINENUM hEnum)
672 FIXME("stub %p\n", iface);
673 return E_NOTIMPL;
676 static HRESULT WINAPI corruntimehost_CreateDomainEx(
677 ICorRuntimeHost* iface,
678 LPCWSTR friendlyName,
679 IUnknown *setup,
680 IUnknown *evidence,
681 IUnknown **appDomain)
683 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
684 HRESULT hr;
685 MonoDomain *domain;
687 if (!friendlyName || !appDomain)
689 return E_POINTER;
691 if (!is_mono_started)
693 return E_FAIL;
696 TRACE("(%p)\n", iface);
698 hr = RuntimeHost_AddDomain(This, friendlyName, setup, evidence, &domain);
700 if (SUCCEEDED(hr))
702 hr = RuntimeHost_GetIUnknownForDomain(This, domain, appDomain);
705 return hr;
708 static HRESULT WINAPI corruntimehost_CreateDomainSetup(
709 ICorRuntimeHost* iface,
710 IUnknown **appDomainSetup)
712 RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
713 HRESULT hr;
714 MonoDomain *domain;
715 MonoObject *obj;
716 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};
718 TRACE("(%p)\n", iface);
720 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
722 if (SUCCEEDED(hr))
723 hr = RuntimeHost_CreateManagedInstance(This, classnameW, domain, &obj);
725 if (SUCCEEDED(hr))
726 hr = RuntimeHost_GetIUnknownForObject(This, obj, appDomainSetup);
728 return hr;
731 static HRESULT WINAPI corruntimehost_CreateEvidence(
732 ICorRuntimeHost* iface,
733 IUnknown **evidence)
735 FIXME("stub %p\n", iface);
736 return E_NOTIMPL;
739 static HRESULT WINAPI corruntimehost_UnloadDomain(
740 ICorRuntimeHost* iface,
741 IUnknown *appDomain)
743 FIXME("stub %p\n", iface);
744 return E_NOTIMPL;
747 static HRESULT WINAPI corruntimehost_CurrentDomain(
748 ICorRuntimeHost* iface,
749 IUnknown **appDomain)
751 FIXME("stub %p\n", iface);
752 return E_NOTIMPL;
755 static const struct ICorRuntimeHostVtbl corruntimehost_vtbl =
757 corruntimehost_QueryInterface,
758 corruntimehost_AddRef,
759 corruntimehost_Release,
760 corruntimehost_CreateLogicalThreadState,
761 corruntimehost_DeleteLogicalThreadState,
762 corruntimehost_SwitchInLogicalThreadState,
763 corruntimehost_SwitchOutLogicalThreadState,
764 corruntimehost_LocksHeldByLogicalThread,
765 corruntimehost_MapFile,
766 corruntimehost_GetConfiguration,
767 corruntimehost_Start,
768 corruntimehost_Stop,
769 corruntimehost_CreateDomain,
770 corruntimehost_GetDefaultDomain,
771 corruntimehost_EnumDomains,
772 corruntimehost_NextDomain,
773 corruntimehost_CloseEnum,
774 corruntimehost_CreateDomainEx,
775 corruntimehost_CreateDomainSetup,
776 corruntimehost_CreateEvidence,
777 corruntimehost_UnloadDomain,
778 corruntimehost_CurrentDomain
781 static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface,
782 REFIID riid,
783 void **ppvObject)
785 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
786 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
788 if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) ||
789 IsEqualGUID( riid, &IID_IUnknown ) )
791 *ppvObject = iface;
793 else
795 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
796 return E_NOINTERFACE;
799 ICLRRuntimeHost_AddRef( iface );
801 return S_OK;
804 static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface)
806 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
807 return ICorRuntimeHost_AddRef(&This->ICorRuntimeHost_iface);
810 static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface)
812 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
813 return ICorRuntimeHost_Release(&This->ICorRuntimeHost_iface);
816 static HRESULT WINAPI CLRRuntimeHost_Start(ICLRRuntimeHost* iface)
818 FIXME("(%p)\n", iface);
819 return E_NOTIMPL;
822 static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
824 FIXME("(%p)\n", iface);
825 return E_NOTIMPL;
828 static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
829 IHostControl *pHostControl)
831 FIXME("(%p,%p)\n", iface, pHostControl);
832 return E_NOTIMPL;
835 static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
836 ICLRControl **pCLRControl)
838 FIXME("(%p,%p)\n", iface, pCLRControl);
839 return E_NOTIMPL;
842 static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
843 DWORD dwAppDomainId, BOOL fWaitUntilDone)
845 FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
846 return E_NOTIMPL;
849 static HRESULT WINAPI CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost* iface,
850 DWORD dwAppDomainId, FExecuteInAppDomainCallback pCallback, void *cookie)
852 FIXME("(%p,%u,%p,%p)\n", iface, dwAppDomainId, pCallback, cookie);
853 return E_NOTIMPL;
856 static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
857 DWORD *pdwAppDomainId)
859 FIXME("(%p,%p)\n", iface, pdwAppDomainId);
860 return E_NOTIMPL;
863 static HRESULT WINAPI CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost* iface,
864 LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR *ppwzManifestPaths,
865 DWORD dwActivationData, LPCWSTR *ppwzActivationData, int *pReturnValue)
867 FIXME("(%p,%s,%u,%u)\n", iface, debugstr_w(pwzAppFullName), dwManifestPaths, dwActivationData);
868 return E_NOTIMPL;
871 static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* iface,
872 LPCWSTR pwzAssemblyPath, LPCWSTR pwzTypeName, LPCWSTR pwzMethodName,
873 LPCWSTR pwzArgument, DWORD *pReturnValue)
875 RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
876 HRESULT hr;
877 MonoDomain *domain, *prev_domain;
878 MonoObject *result;
879 MonoString *str;
880 char *filenameA = NULL, *classA = NULL, *methodA = NULL;
881 char *argsA = NULL, *ns;
883 TRACE("(%p,%s,%s,%s,%s)\n", iface, debugstr_w(pwzAssemblyPath),
884 debugstr_w(pwzTypeName), debugstr_w(pwzMethodName), debugstr_w(pwzArgument));
886 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
888 if (FAILED(hr))
889 return hr;
891 prev_domain = domain_attach(domain);
893 if (SUCCEEDED(hr))
895 filenameA = WtoA(pwzAssemblyPath);
896 if (!filenameA) hr = E_OUTOFMEMORY;
899 if (SUCCEEDED(hr))
901 classA = WtoA(pwzTypeName);
902 if (!classA) hr = E_OUTOFMEMORY;
905 if (SUCCEEDED(hr))
907 ns = strrchr(classA, '.');
908 if (ns)
909 *ns = '\0';
910 else
911 hr = E_INVALIDARG;
914 if (SUCCEEDED(hr))
916 methodA = WtoA(pwzMethodName);
917 if (!methodA) hr = E_OUTOFMEMORY;
920 /* The .NET function we are calling has the following declaration
921 * public static int functionName(String param)
923 if (SUCCEEDED(hr))
925 argsA = WtoA(pwzArgument);
926 if (!argsA) hr = E_OUTOFMEMORY;
929 if (SUCCEEDED(hr))
931 str = mono_string_new(domain, argsA);
932 if (!str) hr = E_OUTOFMEMORY;
935 if (SUCCEEDED(hr))
937 hr = RuntimeHost_Invoke(This, domain, filenameA, classA, ns+1, methodA,
938 NULL, (void**)&str, 1, &result);
941 if (SUCCEEDED(hr))
942 *pReturnValue = *(DWORD*)mono_object_unbox(result);
944 domain_restore(prev_domain);
946 HeapFree(GetProcessHeap(), 0, filenameA);
947 HeapFree(GetProcessHeap(), 0, classA);
948 HeapFree(GetProcessHeap(), 0, argsA);
949 HeapFree(GetProcessHeap(), 0, methodA);
951 return hr;
954 static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
956 CLRRuntimeHost_QueryInterface,
957 CLRRuntimeHost_AddRef,
958 CLRRuntimeHost_Release,
959 CLRRuntimeHost_Start,
960 CLRRuntimeHost_Stop,
961 CLRRuntimeHost_SetHostControl,
962 CLRRuntimeHost_GetCLRControl,
963 CLRRuntimeHost_UnloadAppDomain,
964 CLRRuntimeHost_ExecuteInAppDomain,
965 CLRRuntimeHost_GetCurrentAppDomainId,
966 CLRRuntimeHost_ExecuteApplication,
967 CLRRuntimeHost_ExecuteInDefaultAppDomain
970 /* Create an instance of a type given its name, by calling its constructor with
971 * no arguments. Note that result MUST be in the stack, or the garbage
972 * collector may free it prematurely. */
973 HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
974 MonoDomain *domain, MonoObject **result)
976 HRESULT hr=S_OK;
977 char *nameA=NULL;
978 MonoType *type;
979 MonoClass *klass;
980 MonoObject *obj;
981 MonoDomain *prev_domain;
983 if (!domain)
984 hr = RuntimeHost_GetDefaultDomain(This, NULL, &domain);
986 if (FAILED(hr))
987 return hr;
989 prev_domain = domain_attach(domain);
991 if (SUCCEEDED(hr))
993 nameA = WtoA(name);
994 if (!nameA)
995 hr = E_OUTOFMEMORY;
998 if (SUCCEEDED(hr))
1000 type = mono_reflection_type_from_name(nameA, NULL);
1001 if (!type)
1003 ERR("Cannot find type %s\n", debugstr_w(name));
1004 hr = E_FAIL;
1008 if (SUCCEEDED(hr))
1010 klass = mono_class_from_mono_type(type);
1011 if (!klass)
1013 ERR("Cannot convert type %s to a class\n", debugstr_w(name));
1014 hr = E_FAIL;
1018 if (SUCCEEDED(hr))
1020 obj = mono_object_new(domain, klass);
1021 if (!obj)
1023 ERR("Cannot allocate object of type %s\n", debugstr_w(name));
1024 hr = E_FAIL;
1028 if (SUCCEEDED(hr))
1030 /* FIXME: Detect exceptions from the constructor? */
1031 mono_runtime_object_init(obj);
1032 *result = obj;
1035 domain_restore(prev_domain);
1037 HeapFree(GetProcessHeap(), 0, nameA);
1039 return hr;
1042 /* Get an IUnknown pointer for a Mono object.
1044 * This is just a "light" wrapper around
1045 * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
1047 * NOTE: The IUnknown* is created with a reference to the object.
1048 * Until they have a reference, objects must be in the stack to prevent the
1049 * garbage collector from freeing them. */
1050 HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj,
1051 IUnknown **ppUnk)
1053 MonoDomain *domain;
1054 MonoObject *result;
1055 HRESULT hr;
1057 domain = mono_object_get_domain(obj);
1059 hr = RuntimeHost_Invoke(This, domain, NULL, "System.Runtime.InteropServices", "Marshal", "GetIUnknownForObject",
1060 NULL, (void**)&obj, 1, &result);
1062 if (SUCCEEDED(hr))
1063 *ppUnk = *(IUnknown**)mono_object_unbox(result);
1064 else
1065 *ppUnk = NULL;
1067 return hr;
1070 static void get_utf8_args(int *argc, char ***argv)
1072 WCHAR **argvw;
1073 int size=0, i;
1074 char *current_arg;
1076 argvw = CommandLineToArgvW(GetCommandLineW(), argc);
1078 for (i=0; i<*argc; i++)
1080 size += sizeof(char*);
1081 size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
1083 size += sizeof(char*);
1085 *argv = HeapAlloc(GetProcessHeap(), 0, size);
1086 current_arg = (char*)(*argv + *argc + 1);
1088 for (i=0; i<*argc; i++)
1090 (*argv)[i] = current_arg;
1091 current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
1094 (*argv)[*argc] = NULL;
1096 HeapFree(GetProcessHeap(), 0, argvw);
1099 #if __i386__
1101 # define CAN_FIXUP_VTABLE 1
1103 #include "pshpack1.h"
1105 struct vtable_fixup_thunk
1107 /* push %ecx */
1108 BYTE i7;
1109 /* sub $0x4,%esp */
1110 BYTE i1[3];
1111 /* mov fixup,(%esp) */
1112 BYTE i2[3];
1113 struct dll_fixup *fixup;
1114 /* mov function,%eax */
1115 BYTE i3;
1116 void (CDECL *function)(struct dll_fixup *);
1117 /* call *%eax */
1118 BYTE i4[2];
1119 /* pop %eax */
1120 BYTE i5;
1121 /* pop %ecx */
1122 BYTE i8;
1123 /* jmp *vtable_entry */
1124 BYTE i6[2];
1125 void *vtable_entry;
1128 static const struct vtable_fixup_thunk thunk_template = {
1129 0x51,
1130 {0x83,0xec,0x04},
1131 {0xc7,0x04,0x24},
1132 NULL,
1133 0xb8,
1134 NULL,
1135 {0xff,0xd0},
1136 0x58,
1137 0x59,
1138 {0xff,0x25},
1139 NULL
1142 #include "poppack.h"
1144 #elif __x86_64__ /* !__i386__ */
1146 # define CAN_FIXUP_VTABLE 1
1148 #include "pshpack1.h"
1150 struct vtable_fixup_thunk
1152 /* push %rbp;
1153 mov %rsp, %rbp
1154 sub $0x80, %rsp ; 0x8*4 + 0x10*4 + 0x20
1156 BYTE i1[11];
1158 mov %rcx, 0x60(%rsp); mov %rdx, 0x68(%rsp); mov %r8, 0x70(%rsp); mov %r9, 0x78(%rsp);
1159 movaps %xmm0,0x20(%rsp); ...; movaps %xmm3,0x50(%esp)
1161 BYTE i2[40];
1162 /* mov function,%rax */
1163 BYTE i3[2];
1164 void (CDECL *function)(struct dll_fixup *);
1165 /* mov fixup,%rcx */
1166 BYTE i4[2];
1167 struct dll_fixup *fixup;
1168 /* call *%rax */
1169 BYTE i5[2];
1171 mov 0x60(%rsp),%rcx; mov 0x68(%rsp),%rdx; mov 0x70(%rsp),%r8; mov 0x78(%rsp),%r9;
1172 movaps 0x20(%rsp),xmm0; ...; movaps 0x50(%esp),xmm3
1174 BYTE i6[40];
1175 /* mov %rbp, %rsp
1176 pop %rbp
1178 BYTE i7[4];
1179 /* mov vtable_entry, %rax */
1180 BYTE i8[2];
1181 void *vtable_entry;
1182 /* mov [%rax],%rax
1183 jmp %rax */
1184 BYTE i9[5];
1187 static const struct vtable_fixup_thunk thunk_template = {
1188 {0x55,0x48,0x89,0xE5, 0x48,0x81,0xEC,0x80,0x00,0x00,0x00},
1189 {0x48,0x89,0x4C,0x24,0x60, 0x48,0x89,0x54,0x24,0x68,
1190 0x4C,0x89,0x44,0x24,0x70, 0x4C,0x89,0x4C,0x24,0x78,
1191 0x0F,0x29,0x44,0x24,0x20, 0x0F,0x29,0x4C,0x24,0x30,
1192 0x0F,0x29,0x54,0x24,0x40, 0x0F,0x29,0x5C,0x24,0x50,
1194 {0x48,0xB8},
1195 NULL,
1196 {0x48,0xB9},
1197 NULL,
1198 {0xFF,0xD0},
1199 {0x48,0x8B,0x4C,0x24,0x60, 0x48,0x8B,0x54,0x24,0x68,
1200 0x4C,0x8B,0x44,0x24,0x70, 0x4C,0x8B,0x4C,0x24,0x78,
1201 0x0F,0x28,0x44,0x24,0x20, 0x0F,0x28,0x4C,0x24,0x30,
1202 0x0F,0x28,0x54,0x24,0x40, 0x0F,0x28,0x5C,0x24,0x50,
1204 {0x48,0x89,0xEC, 0x5D},
1205 {0x48,0xB8},
1206 NULL,
1207 {0x48,0x8B,0x00,0xFF,0xE0}
1210 #include "poppack.h"
1212 #else /* !__i386__ && !__x86_64__ */
1214 # define CAN_FIXUP_VTABLE 0
1216 struct vtable_fixup_thunk
1218 struct dll_fixup *fixup;
1219 void (CDECL *function)(struct dll_fixup *fixup);
1220 void *vtable_entry;
1223 static const struct vtable_fixup_thunk thunk_template = {0};
1225 #endif
1227 DWORD WINAPI GetTokenForVTableEntry(HINSTANCE hinst, BYTE **ppVTEntry)
1229 struct dll_fixup *fixup;
1230 DWORD result = 0;
1231 DWORD rva;
1232 int i;
1234 TRACE("%p,%p\n", hinst, ppVTEntry);
1236 rva = (BYTE*)ppVTEntry - (BYTE*)hinst;
1238 EnterCriticalSection(&fixup_list_cs);
1239 LIST_FOR_EACH_ENTRY(fixup, &dll_fixups, struct dll_fixup, entry)
1241 if (fixup->dll != hinst)
1242 continue;
1243 if (rva < fixup->fixup->rva || (rva - fixup->fixup->rva >= fixup->fixup->count * sizeof(ULONG_PTR)))
1244 continue;
1245 i = (rva - fixup->fixup->rva) / sizeof(ULONG_PTR);
1246 result = ((ULONG_PTR*)fixup->tokens)[i];
1247 break;
1249 LeaveCriticalSection(&fixup_list_cs);
1251 TRACE("<-- %x\n", result);
1252 return result;
1255 static void CDECL ReallyFixupVTable(struct dll_fixup *fixup)
1257 HRESULT hr=S_OK;
1258 WCHAR filename[MAX_PATH];
1259 ICLRRuntimeInfo *info=NULL;
1260 RuntimeHost *host;
1261 char *filenameA;
1262 MonoImage *image=NULL;
1263 MonoAssembly *assembly=NULL;
1264 MonoImageOpenStatus status=0;
1265 MonoDomain *domain;
1267 if (fixup->done) return;
1269 /* It's possible we'll have two threads doing this at once. This is
1270 * considered preferable to the potential deadlock if we use a mutex. */
1272 GetModuleFileNameW(fixup->dll, filename, MAX_PATH);
1274 TRACE("%p,%p,%s\n", fixup, fixup->dll, debugstr_w(filename));
1276 filenameA = WtoA(filename);
1277 if (!filenameA)
1278 hr = E_OUTOFMEMORY;
1280 if (SUCCEEDED(hr))
1281 hr = get_runtime_info(filename, NULL, NULL, NULL, 0, 0, FALSE, &info);
1283 if (SUCCEEDED(hr))
1284 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1286 if (SUCCEEDED(hr))
1287 hr = RuntimeHost_GetDefaultDomain(host, NULL, &domain);
1289 if (SUCCEEDED(hr))
1291 MonoDomain *prev_domain;
1293 prev_domain = domain_attach(domain);
1295 assembly = mono_assembly_open(filenameA, &status);
1297 if (assembly)
1299 int i;
1301 /* Mono needs an image that belongs to an assembly. */
1302 image = mono_assembly_get_image(assembly);
1304 #if __x86_64__
1305 if (fixup->fixup->type & COR_VTABLE_64BIT)
1306 #else
1307 if (fixup->fixup->type & COR_VTABLE_32BIT)
1308 #endif
1310 void **vtable = fixup->vtable;
1311 ULONG_PTR *tokens = fixup->tokens;
1312 for (i=0; i<fixup->fixup->count; i++)
1314 vtable[i] = mono_marshal_get_vtfixup_ftnptr(
1315 image, tokens[i], fixup->fixup->type);
1319 fixup->done = TRUE;
1322 domain_restore(prev_domain);
1325 if (info != NULL)
1326 ICLRRuntimeInfo_Release(info);
1328 HeapFree(GetProcessHeap(), 0, filenameA);
1330 if (!fixup->done)
1332 ERR("unable to fixup vtable, hr=%x, status=%d\n", hr, status);
1333 /* If we returned now, we'd get an infinite loop. */
1334 assert(0);
1338 static void FixupVTableEntry(HMODULE hmodule, VTableFixup *vtable_fixup)
1340 /* We can't actually generate code for the functions without loading mono,
1341 * and loading mono inside DllMain is a terrible idea. So we make thunks
1342 * that call ReallyFixupVTable, which will load the runtime and fill in the
1343 * vtable, then do an indirect jump using the (now filled in) vtable. Note
1344 * that we have to keep the thunks around forever, as one of them may get
1345 * called while we're filling in the table, and we can never be sure all
1346 * threads are clear. */
1347 struct dll_fixup *fixup;
1349 fixup = HeapAlloc(GetProcessHeap(), 0, sizeof(*fixup));
1351 fixup->dll = hmodule;
1352 fixup->thunk_code = HeapAlloc(dll_fixup_heap, 0, sizeof(struct vtable_fixup_thunk) * vtable_fixup->count);
1353 fixup->fixup = vtable_fixup;
1354 fixup->vtable = (BYTE*)hmodule + vtable_fixup->rva;
1355 fixup->done = FALSE;
1357 #if __x86_64__
1358 if (vtable_fixup->type & COR_VTABLE_64BIT)
1359 #else
1360 if (vtable_fixup->type & COR_VTABLE_32BIT)
1361 #endif
1363 void **vtable = fixup->vtable;
1364 ULONG_PTR *tokens;
1365 int i;
1366 struct vtable_fixup_thunk *thunks = fixup->thunk_code;
1368 tokens = fixup->tokens = HeapAlloc(GetProcessHeap(), 0, sizeof(*tokens) * vtable_fixup->count);
1369 memcpy(tokens, vtable, sizeof(*tokens) * vtable_fixup->count);
1370 for (i=0; i<vtable_fixup->count; i++)
1372 thunks[i] = thunk_template;
1373 thunks[i].fixup = fixup;
1374 thunks[i].function = ReallyFixupVTable;
1375 thunks[i].vtable_entry = &vtable[i];
1376 vtable[i] = &thunks[i];
1379 else
1381 ERR("unsupported vtable fixup flags %x\n", vtable_fixup->type);
1382 HeapFree(dll_fixup_heap, 0, fixup->thunk_code);
1383 HeapFree(GetProcessHeap(), 0, fixup);
1384 return;
1387 EnterCriticalSection(&fixup_list_cs);
1388 list_add_tail(&dll_fixups, &fixup->entry);
1389 LeaveCriticalSection(&fixup_list_cs);
1392 static void FixupVTable_Assembly(HMODULE hmodule, ASSEMBLY *assembly)
1394 VTableFixup *vtable_fixups;
1395 ULONG vtable_fixup_count, i;
1397 assembly_get_vtable_fixups(assembly, &vtable_fixups, &vtable_fixup_count);
1398 if (CAN_FIXUP_VTABLE)
1399 for (i=0; i<vtable_fixup_count; i++)
1400 FixupVTableEntry(hmodule, &vtable_fixups[i]);
1401 else if (vtable_fixup_count)
1402 FIXME("cannot fixup vtable; expect a crash\n");
1405 static void FixupVTable(HMODULE hmodule)
1407 ASSEMBLY *assembly;
1408 HRESULT hr;
1410 hr = assembly_from_hmodule(&assembly, hmodule);
1411 if (SUCCEEDED(hr))
1413 FixupVTable_Assembly(hmodule, assembly);
1414 assembly_release(assembly);
1416 else
1417 ERR("failed to read CLR headers, hr=%x\n", hr);
1420 __int32 WINAPI _CorExeMain(void)
1422 static const WCHAR dotconfig[] = {'.','c','o','n','f','i','g',0};
1423 static const WCHAR scW[] = {';',0};
1424 int exit_code;
1425 int argc;
1426 char **argv;
1427 MonoDomain *domain=NULL;
1428 MonoImage *image;
1429 MonoImageOpenStatus status;
1430 MonoAssembly *assembly=NULL;
1431 WCHAR filename[MAX_PATH], config_file[MAX_PATH], *temp, **priv_path;
1432 SIZE_T config_file_dir_size;
1433 char *filenameA;
1434 ICLRRuntimeInfo *info;
1435 RuntimeHost *host;
1436 parsed_config_file parsed_config;
1437 HRESULT hr;
1438 int i, number_of_private_paths = 0;
1440 get_utf8_args(&argc, &argv);
1442 GetModuleFileNameW(NULL, filename, MAX_PATH);
1444 TRACE("%s argc=%i\n", debugstr_w(filename), argc);
1446 filenameA = WtoA(filename);
1447 if (!filenameA)
1449 HeapFree(GetProcessHeap(), 0, argv);
1450 return -1;
1453 FixupVTable(GetModuleHandleW(NULL));
1455 wcscpy(config_file, filename);
1456 wcscat(config_file, dotconfig);
1458 hr = parse_config_file(config_file, &parsed_config);
1459 if (SUCCEEDED(hr) && parsed_config.private_path && parsed_config.private_path[0])
1461 WCHAR *save;
1462 for(i = 0; parsed_config.private_path[i] != 0; i++)
1463 if (parsed_config.private_path[i] == ';') number_of_private_paths++;
1464 if (parsed_config.private_path[wcslen(parsed_config.private_path) - 1] != ';') number_of_private_paths++;
1465 config_file_dir_size = (wcsrchr(config_file, '\\') - config_file) + 1;
1466 priv_path = HeapAlloc(GetProcessHeap(), 0, (number_of_private_paths + 1) * sizeof(WCHAR *));
1467 /* wcstok ignores trailing semicolons */
1468 temp = wcstok_s(parsed_config.private_path, scW, &save);
1469 for (i = 0; i < number_of_private_paths; i++)
1471 priv_path[i] = HeapAlloc(GetProcessHeap(), 0, (config_file_dir_size + wcslen(temp) + 1) * sizeof(WCHAR));
1472 memcpy(priv_path[i], config_file, config_file_dir_size * sizeof(WCHAR));
1473 wcscpy(priv_path[i] + config_file_dir_size, temp);
1474 temp = wcstok_s(NULL, scW, &save);
1476 priv_path[number_of_private_paths] = NULL;
1477 if (InterlockedCompareExchangePointer((void **)&private_path, priv_path, NULL))
1478 ERR("private_path was already set\n");
1481 free_parsed_config_file(&parsed_config);
1483 hr = get_runtime_info(filename, NULL, NULL, NULL, 0, 0, FALSE, &info);
1485 if (SUCCEEDED(hr))
1487 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1489 if (SUCCEEDED(hr))
1490 hr = RuntimeHost_GetDefaultDomain(host, config_file, &domain);
1492 if (SUCCEEDED(hr))
1494 image = mono_image_open_from_module_handle(GetModuleHandleW(NULL),
1495 filenameA, 1, &status);
1497 if (image)
1498 assembly = mono_assembly_load_from(image, filenameA, &status);
1500 if (assembly)
1502 mono_callspec_set_assembly(assembly);
1504 exit_code = mono_jit_exec(domain, assembly, argc, argv);
1506 else
1508 ERR("couldn't load %s, status=%d\n", debugstr_w(filename), status);
1509 exit_code = -1;
1512 else
1513 exit_code = -1;
1515 ICLRRuntimeInfo_Release(info);
1517 else
1518 exit_code = -1;
1520 HeapFree(GetProcessHeap(), 0, argv);
1522 if (domain)
1524 mono_thread_manage();
1525 mono_runtime_quit();
1528 ExitProcess(exit_code);
1530 return exit_code;
1533 BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1535 ASSEMBLY *assembly=NULL;
1536 HRESULT hr;
1538 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1540 hr = assembly_from_hmodule(&assembly, hinstDLL);
1541 if (SUCCEEDED(hr))
1543 NativeEntryPointFunc NativeEntryPoint=NULL;
1545 assembly_get_native_entrypoint(assembly, &NativeEntryPoint);
1546 if (fdwReason == DLL_PROCESS_ATTACH)
1548 if (!NativeEntryPoint)
1549 DisableThreadLibraryCalls(hinstDLL);
1550 FixupVTable_Assembly(hinstDLL,assembly);
1552 assembly_release(assembly);
1553 /* FIXME: clean up the vtables on DLL_PROCESS_DETACH */
1554 if (NativeEntryPoint)
1555 return NativeEntryPoint(hinstDLL, fdwReason, lpvReserved);
1557 else
1558 ERR("failed to read CLR headers, hr=%x\n", hr);
1560 return TRUE;
1563 /* called from DLL_PROCESS_ATTACH */
1564 void runtimehost_init(void)
1566 dll_fixup_heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
1567 list_init(&dll_fixups);
1570 /* called from DLL_PROCESS_DETACH */
1571 void runtimehost_uninit(void)
1573 struct dll_fixup *fixup, *fixup2;
1575 HeapDestroy(dll_fixup_heap);
1576 LIST_FOR_EACH_ENTRY_SAFE(fixup, fixup2, &dll_fixups, struct dll_fixup, entry)
1578 HeapFree(GetProcessHeap(), 0, fixup->tokens);
1579 HeapFree(GetProcessHeap(), 0, fixup);
1583 HRESULT RuntimeHost_Construct(CLRRuntimeInfo *runtime_version, RuntimeHost** result)
1585 RuntimeHost *This;
1587 This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1588 if ( !This )
1589 return E_OUTOFMEMORY;
1591 This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
1592 This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
1594 This->ref = 1;
1595 This->version = runtime_version;
1596 InitializeCriticalSection(&This->lock);
1597 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
1599 *result = This;
1601 return S_OK;
1604 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
1606 IUnknown *unk;
1607 HRESULT hr;
1609 if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
1611 unk = (IUnknown*)&This->ICorRuntimeHost_iface;
1612 IUnknown_AddRef(unk);
1614 else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
1616 unk = (IUnknown*)&This->ICLRRuntimeHost_iface;
1617 IUnknown_AddRef(unk);
1619 else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
1620 IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
1622 hr = MetaDataDispenser_CreateInstance(&unk);
1623 if (FAILED(hr))
1624 return hr;
1626 else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
1628 hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
1629 if (FAILED(hr))
1630 return hr;
1632 else
1633 unk = NULL;
1635 if (unk)
1637 hr = IUnknown_QueryInterface(unk, riid, ppv);
1639 IUnknown_Release(unk);
1641 return hr;
1643 else
1644 FIXME("not implemented for class %s\n", debugstr_guid(clsid));
1646 return CLASS_E_CLASSNOTAVAILABLE;
1649 static BOOL try_create_registration_free_com(REFIID clsid, WCHAR *classname, UINT classname_size, WCHAR *filename, UINT filename_size)
1651 ACTCTX_SECTION_KEYED_DATA guid_info = { sizeof(ACTCTX_SECTION_KEYED_DATA) };
1652 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *assembly_info = NULL;
1653 SIZE_T bytes_assembly_info;
1654 struct comclassredirect_data *redirect_data;
1655 struct clrclass_data *class_data;
1656 void *ptr_name;
1657 const WCHAR *ptr_path_start, *ptr_path_end;
1658 WCHAR path[MAX_PATH] = {0};
1659 WCHAR str_dll[] = {'.','d','l','l',0};
1660 BOOL ret = FALSE;
1662 if (!FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, 0, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, clsid, &guid_info))
1664 DWORD error = GetLastError();
1665 if (error != ERROR_SXS_KEY_NOT_FOUND)
1666 ERR("Failed to find guid: %d\n", error);
1667 goto end;
1670 QueryActCtxW(0, guid_info.hActCtx, &guid_info.ulAssemblyRosterIndex, AssemblyDetailedInformationInActivationContext, NULL, 0, &bytes_assembly_info);
1671 assembly_info = heap_alloc(bytes_assembly_info);
1672 if (!QueryActCtxW(0, guid_info.hActCtx, &guid_info.ulAssemblyRosterIndex,
1673 AssemblyDetailedInformationInActivationContext, assembly_info, bytes_assembly_info, &bytes_assembly_info))
1675 ERR("QueryActCtxW failed: %d!\n", GetLastError());
1676 goto end;
1679 redirect_data = guid_info.lpData;
1680 class_data = (void *)((char *)redirect_data + redirect_data->clrdata_offset);
1682 ptr_name = (char *)class_data + class_data->name_offset;
1683 if (lstrlenW(ptr_name) + 1 > classname_size) /* Include null-terminator */
1685 ERR("Buffer is too small\n");
1686 goto end;
1688 lstrcpyW(classname, ptr_name);
1690 ptr_path_start = assembly_info->lpAssemblyEncodedAssemblyIdentity;
1691 ptr_path_end = wcschr(ptr_path_start, ',');
1692 memcpy(path, ptr_path_start, (char*)ptr_path_end - (char*)ptr_path_start);
1694 GetModuleFileNameW(NULL, filename, filename_size);
1695 PathRemoveFileSpecW(filename);
1697 if (lstrlenW(filename) + lstrlenW(path) + ARRAY_SIZE(str_dll) + 1 > filename_size) /* Include blackslash */
1699 ERR("Buffer is too small\n");
1700 goto end;
1703 PathAppendW(filename, path);
1704 lstrcatW(filename, str_dll);
1706 ret = TRUE;
1708 end:
1709 heap_free(assembly_info);
1711 if (guid_info.hActCtx)
1712 ReleaseActCtx(guid_info.hActCtx);
1714 return ret;
1717 #define CHARS_IN_GUID 39
1719 HRESULT create_monodata(REFIID riid, LPVOID *ppObj )
1721 static const WCHAR wszAssembly[] = {'A','s','s','e','m','b','l','y',0};
1722 static const WCHAR wszCodebase[] = {'C','o','d','e','B','a','s','e',0};
1723 static const WCHAR wszClass[] = {'C','l','a','s','s',0};
1724 static const WCHAR wszFileSlash[] = {'f','i','l','e',':','/','/','/',0};
1725 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1726 static const WCHAR wszInprocServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1727 static const WCHAR wszDLL[] = {'.','d','l','l',0};
1728 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(wszCLSIDSlash) + ARRAY_SIZE(wszInprocServer32) - 1];
1729 MonoDomain *domain;
1730 MonoAssembly *assembly;
1731 ICLRRuntimeInfo *info = NULL;
1732 RuntimeHost *host;
1733 HRESULT hr;
1734 HKEY key, subkey;
1735 LONG res;
1736 int offset = 0;
1737 HANDLE file = INVALID_HANDLE_VALUE;
1738 DWORD numKeys, keyLength;
1739 WCHAR codebase[MAX_PATH + 8];
1740 WCHAR classname[350], subkeyName[256];
1741 WCHAR filename[MAX_PATH];
1743 DWORD dwBufLen = 350;
1745 lstrcpyW(path, wszCLSIDSlash);
1746 StringFromGUID2(riid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
1747 lstrcatW(path, wszInprocServer32);
1749 TRACE("Registry key: %s\n", debugstr_w(path));
1751 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key);
1752 if (res != ERROR_FILE_NOT_FOUND)
1754 res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen);
1755 if(res != ERROR_SUCCESS)
1757 WARN("Class value cannot be found.\n");
1758 hr = CLASS_E_CLASSNOTAVAILABLE;
1759 goto cleanup;
1762 TRACE("classname (%s)\n", debugstr_w(classname));
1764 dwBufLen = MAX_PATH + 8;
1765 res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen);
1766 if(res == ERROR_SUCCESS)
1768 /* Strip file:/// */
1769 if(wcsncmp(codebase, wszFileSlash, lstrlenW(wszFileSlash)) == 0)
1770 offset = lstrlenW(wszFileSlash);
1772 lstrcpyW(filename, codebase + offset);
1774 file = CreateFileW(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
1777 if (file != INVALID_HANDLE_VALUE)
1778 CloseHandle(file);
1779 else
1781 WCHAR assemblyname[MAX_PATH + 8];
1783 hr = CLASS_E_CLASSNOTAVAILABLE;
1784 WARN("CodeBase value cannot be found, trying Assembly.\n");
1785 /* get the last subkey of InprocServer32 */
1786 res = RegQueryInfoKeyW(key, 0, 0, 0, &numKeys, 0, 0, 0, 0, 0, 0, 0);
1787 if (res != ERROR_SUCCESS)
1788 goto cleanup;
1789 if (numKeys > 0)
1791 numKeys--;
1792 keyLength = ARRAY_SIZE(subkeyName);
1793 res = RegEnumKeyExW(key, numKeys, subkeyName, &keyLength, 0, 0, 0, 0);
1794 if (res != ERROR_SUCCESS)
1795 goto cleanup;
1796 res = RegOpenKeyExW(key, subkeyName, 0, KEY_READ, &subkey);
1797 if (res != ERROR_SUCCESS)
1798 goto cleanup;
1799 dwBufLen = MAX_PATH + 8;
1800 res = RegGetValueW(subkey, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen);
1801 RegCloseKey(subkey);
1802 if (res != ERROR_SUCCESS)
1803 goto cleanup;
1805 else
1807 dwBufLen = MAX_PATH + 8;
1808 res = RegGetValueW(key, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen);
1809 if (res != ERROR_SUCCESS)
1810 goto cleanup;
1813 hr = get_file_from_strongname(assemblyname, filename, MAX_PATH);
1814 if (FAILED(hr))
1817 * The registry doesn't have a CodeBase entry or the file isn't there, and it's not in the GAC.
1819 * Use the Assembly Key to retrieve the filename.
1820 * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null
1822 WCHAR *ns;
1824 WARN("Attempt to load from the application directory.\n");
1825 GetModuleFileNameW(NULL, filename, MAX_PATH);
1826 ns = wcsrchr(filename, '\\');
1827 *(ns+1) = '\0';
1829 ns = wcschr(assemblyname, ',');
1830 *(ns) = '\0';
1831 lstrcatW(filename, assemblyname);
1832 *(ns) = '.';
1833 lstrcatW(filename, wszDLL);
1837 else
1839 if (!try_create_registration_free_com(riid, classname, ARRAY_SIZE(classname), filename, ARRAY_SIZE(filename)))
1840 return CLASS_E_CLASSNOTAVAILABLE;
1842 TRACE("classname (%s)\n", debugstr_w(classname));
1845 TRACE("filename (%s)\n", debugstr_w(filename));
1847 *ppObj = NULL;
1850 hr = get_runtime_info(filename, NULL, NULL, NULL, 0, 0, FALSE, &info);
1851 if (SUCCEEDED(hr))
1853 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1855 if (SUCCEEDED(hr))
1856 hr = RuntimeHost_GetDefaultDomain(host, NULL, &domain);
1858 if (SUCCEEDED(hr))
1860 MonoImage *image;
1861 MonoClass *klass;
1862 MonoObject *result;
1863 MonoDomain *prev_domain;
1864 MonoImageOpenStatus status;
1865 IUnknown *unk = NULL;
1866 char *filenameA, *ns;
1867 char *classA;
1869 hr = CLASS_E_CLASSNOTAVAILABLE;
1871 prev_domain = domain_attach(domain);
1873 filenameA = WtoA(filename);
1874 assembly = mono_assembly_open(filenameA, &status);
1875 HeapFree(GetProcessHeap(), 0, filenameA);
1876 if (!assembly)
1878 ERR("Cannot open assembly %s, status=%i\n", filenameA, status);
1879 domain_restore(prev_domain);
1880 goto cleanup;
1883 image = mono_assembly_get_image(assembly);
1884 if (!image)
1886 ERR("Couldn't get assembly image\n");
1887 domain_restore(prev_domain);
1888 goto cleanup;
1891 classA = WtoA(classname);
1892 ns = strrchr(classA, '.');
1893 *ns = '\0';
1895 klass = mono_class_from_name(image, classA, ns+1);
1896 HeapFree(GetProcessHeap(), 0, classA);
1897 if (!klass)
1899 ERR("Couldn't get class from image\n");
1900 domain_restore(prev_domain);
1901 goto cleanup;
1905 * Use the default constructor for the .NET class.
1907 result = mono_object_new(domain, klass);
1908 mono_runtime_object_init(result);
1910 hr = RuntimeHost_GetIUnknownForObject(host, result, &unk);
1911 if (SUCCEEDED(hr))
1913 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj);
1915 IUnknown_Release(unk);
1917 else
1918 hr = CLASS_E_CLASSNOTAVAILABLE;
1920 domain_restore(prev_domain);
1922 else
1923 hr = CLASS_E_CLASSNOTAVAILABLE;
1925 else
1926 hr = CLASS_E_CLASSNOTAVAILABLE;
1928 cleanup:
1929 if(info)
1930 ICLRRuntimeInfo_Release(info);
1932 RegCloseKey(key);
1934 return hr;