xref: /reactos/dll/win32/mscoree/corruntimehost.c (revision cdf90707)
1 /*
2  *
3  * Copyright 2008 Alistair Leslie-Hughes
4  *
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.
9  *
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.
14  *
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
18  */
19 
20 #include "mscoree_private.h"
21 
22 #include <assert.h>
23 #include <shellapi.h>
24 #include <initguid.h>
25 
26 DEFINE_GUID(IID__AppDomain, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13);
27 
28 struct DomainEntry
29 {
30     struct list entry;
31     MonoDomain *domain;
32 };
33 
34 static HANDLE dll_fixup_heap; /* using a separate heap so we can have execute permission */
35 
36 static struct list dll_fixups;
37 
38 struct dll_fixup
39 {
40     struct list entry;
41     int done;
42     HMODULE dll;
43     void *thunk_code; /* pointer into dll_fixup_heap */
44     VTableFixup *fixup;
45     void *vtable;
46     void *tokens; /* pointer into process heap */
47 };
48 
49 static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, MonoDomain **result)
50 {
51     struct DomainEntry *entry;
52     char *mscorlib_path;
53     HRESULT res=S_OK;
54 
55     EnterCriticalSection(&This->lock);
56 
57     entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
58     if (!entry)
59     {
60         res = E_OUTOFMEMORY;
61         goto end;
62     }
63 
64     mscorlib_path = WtoA(This->version->mscorlib_path);
65     if (!mscorlib_path)
66     {
67         HeapFree(GetProcessHeap(), 0, entry);
68         res = E_OUTOFMEMORY;
69         goto end;
70     }
71 
72     entry->domain = This->mono->mono_jit_init(mscorlib_path);
73 
74     HeapFree(GetProcessHeap(), 0, mscorlib_path);
75 
76     if (!entry->domain)
77     {
78         HeapFree(GetProcessHeap(), 0, entry);
79         res = E_FAIL;
80         goto end;
81     }
82 
83     This->mono->is_started = TRUE;
84 
85     list_add_tail(&This->domains, &entry->entry);
86 
87     *result = entry->domain;
88 
89 end:
90     LeaveCriticalSection(&This->lock);
91 
92     return res;
93 }
94 
95 static HRESULT RuntimeHost_GetDefaultDomain(RuntimeHost *This, MonoDomain **result)
96 {
97     HRESULT res=S_OK;
98 
99     EnterCriticalSection(&This->lock);
100 
101     if (This->default_domain) goto end;
102 
103     res = RuntimeHost_AddDomain(This, &This->default_domain);
104 
105 end:
106     *result = This->default_domain;
107 
108     LeaveCriticalSection(&This->lock);
109 
110     return res;
111 }
112 
113 static void RuntimeHost_DeleteDomain(RuntimeHost *This, MonoDomain *domain)
114 {
115     struct DomainEntry *entry;
116 
117     EnterCriticalSection(&This->lock);
118 
119     LIST_FOR_EACH_ENTRY(entry, &This->domains, struct DomainEntry, entry)
120     {
121         if (entry->domain == domain)
122         {
123             list_remove(&entry->entry);
124             if (This->default_domain == domain)
125                 This->default_domain = NULL;
126             HeapFree(GetProcessHeap(), 0, entry);
127             break;
128         }
129     }
130 
131     LeaveCriticalSection(&This->lock);
132 }
133 
134 static HRESULT RuntimeHost_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *domain, IUnknown **punk)
135 {
136     HRESULT hr;
137     void *args[1];
138     MonoAssembly *assembly;
139     MonoImage *image;
140     MonoClass *klass;
141     MonoMethod *method;
142     MonoObject *appdomain_object;
143     IUnknown *unk;
144 
145     This->mono->mono_thread_attach(domain);
146 
147     assembly = This->mono->mono_domain_assembly_open(domain, "mscorlib");
148     if (!assembly)
149     {
150         ERR("Cannot load mscorlib\n");
151         return E_FAIL;
152     }
153 
154     image = This->mono->mono_assembly_get_image(assembly);
155     if (!image)
156     {
157         ERR("Couldn't get assembly image\n");
158         return E_FAIL;
159     }
160 
161     klass = This->mono->mono_class_from_name(image, "System", "AppDomain");
162     if (!klass)
163     {
164         ERR("Couldn't get class from image\n");
165         return E_FAIL;
166     }
167 
168     method = This->mono->mono_class_get_method_from_name(klass, "get_CurrentDomain", 0);
169     if (!method)
170     {
171         ERR("Couldn't get method from class\n");
172         return E_FAIL;
173     }
174 
175     args[0] = NULL;
176     appdomain_object = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
177     if (!appdomain_object)
178     {
179         ERR("Couldn't get result pointer\n");
180         return E_FAIL;
181     }
182 
183     hr = RuntimeHost_GetIUnknownForObject(This, appdomain_object, &unk);
184 
185     if (SUCCEEDED(hr))
186     {
187         hr = IUnknown_QueryInterface(unk, &IID__AppDomain, (void**)punk);
188 
189         IUnknown_Release(unk);
190     }
191 
192     return hr;
193 }
194 
195 static inline RuntimeHost *impl_from_ICLRRuntimeHost( ICLRRuntimeHost *iface )
196 {
197     return CONTAINING_RECORD(iface, RuntimeHost, ICLRRuntimeHost_iface);
198 }
199 
200 static inline RuntimeHost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
201 {
202     return CONTAINING_RECORD(iface, RuntimeHost, ICorRuntimeHost_iface);
203 }
204 
205 /*** IUnknown methods ***/
206 static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
207         REFIID riid,
208         void **ppvObject)
209 {
210     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
211     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
212 
213     if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) ||
214          IsEqualGUID( riid, &IID_IUnknown ) )
215     {
216         *ppvObject = iface;
217     }
218     else
219     {
220         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
221         return E_NOINTERFACE;
222     }
223 
224     ICorRuntimeHost_AddRef( iface );
225 
226     return S_OK;
227 }
228 
229 static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface)
230 {
231     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
232 
233     return InterlockedIncrement( &This->ref );
234 }
235 
236 static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface)
237 {
238     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
239     ULONG ref;
240 
241     ref = InterlockedDecrement( &This->ref );
242 
243     return ref;
244 }
245 
246 /*** ICorRuntimeHost methods ***/
247 static HRESULT WINAPI corruntimehost_CreateLogicalThreadState(
248                     ICorRuntimeHost* iface)
249 {
250     FIXME("stub %p\n", iface);
251     return E_NOTIMPL;
252 }
253 
254 static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState(
255                     ICorRuntimeHost* iface)
256 {
257     FIXME("stub %p\n", iface);
258     return E_NOTIMPL;
259 }
260 
261 static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState(
262                     ICorRuntimeHost* iface,
263                     DWORD *fiberCookie)
264 {
265     FIXME("stub %p\n", iface);
266     return E_NOTIMPL;
267 }
268 
269 static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState(
270                     ICorRuntimeHost* iface,
271                     DWORD **fiberCookie)
272 {
273     FIXME("stub %p\n", iface);
274     return E_NOTIMPL;
275 }
276 
277 static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread(
278                     ICorRuntimeHost* iface,
279                     DWORD *pCount)
280 {
281     FIXME("stub %p\n", iface);
282     return E_NOTIMPL;
283 }
284 
285 static HRESULT WINAPI corruntimehost_MapFile(
286     ICorRuntimeHost* iface,
287     HANDLE hFile,
288     HMODULE *mapAddress)
289 {
290     FIXME("stub %p\n", iface);
291     return E_NOTIMPL;
292 }
293 
294 static HRESULT WINAPI corruntimehost_GetConfiguration(
295     ICorRuntimeHost* iface,
296     ICorConfiguration **pConfiguration)
297 {
298     FIXME("stub %p\n", iface);
299     return E_NOTIMPL;
300 }
301 
302 static HRESULT WINAPI corruntimehost_Start(
303     ICorRuntimeHost* iface)
304 {
305     FIXME("stub %p\n", iface);
306     return S_OK;
307 }
308 
309 static HRESULT WINAPI corruntimehost_Stop(
310     ICorRuntimeHost* iface)
311 {
312     FIXME("stub %p\n", iface);
313     return E_NOTIMPL;
314 }
315 
316 static HRESULT WINAPI corruntimehost_CreateDomain(
317     ICorRuntimeHost* iface,
318     LPCWSTR friendlyName,
319     IUnknown *identityArray,
320     IUnknown **appDomain)
321 {
322     FIXME("stub %p\n", iface);
323     return E_NOTIMPL;
324 }
325 
326 static HRESULT WINAPI corruntimehost_GetDefaultDomain(
327     ICorRuntimeHost* iface,
328     IUnknown **pAppDomain)
329 {
330     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
331     HRESULT hr;
332     MonoDomain *domain;
333 
334     TRACE("(%p)\n", iface);
335 
336     hr = RuntimeHost_GetDefaultDomain(This, &domain);
337 
338     if (SUCCEEDED(hr))
339     {
340         hr = RuntimeHost_GetIUnknownForDomain(This, domain, pAppDomain);
341     }
342 
343     return hr;
344 }
345 
346 static HRESULT WINAPI corruntimehost_EnumDomains(
347     ICorRuntimeHost* iface,
348     HDOMAINENUM *hEnum)
349 {
350     FIXME("stub %p\n", iface);
351     return E_NOTIMPL;
352 }
353 
354 static HRESULT WINAPI corruntimehost_NextDomain(
355     ICorRuntimeHost* iface,
356     HDOMAINENUM hEnum,
357     IUnknown **appDomain)
358 {
359     FIXME("stub %p\n", iface);
360     return E_NOTIMPL;
361 }
362 
363 static HRESULT WINAPI corruntimehost_CloseEnum(
364     ICorRuntimeHost* iface,
365     HDOMAINENUM hEnum)
366 {
367     FIXME("stub %p\n", iface);
368     return E_NOTIMPL;
369 }
370 
371 static HRESULT WINAPI corruntimehost_CreateDomainEx(
372     ICorRuntimeHost* iface,
373     LPCWSTR friendlyName,
374     IUnknown *setup,
375     IUnknown *evidence,
376     IUnknown **appDomain)
377 {
378     FIXME("stub %p\n", iface);
379     return E_NOTIMPL;
380 }
381 
382 static HRESULT WINAPI corruntimehost_CreateDomainSetup(
383     ICorRuntimeHost* iface,
384     IUnknown **appDomainSetup)
385 {
386     FIXME("stub %p\n", iface);
387     return E_NOTIMPL;
388 }
389 
390 static HRESULT WINAPI corruntimehost_CreateEvidence(
391     ICorRuntimeHost* iface,
392     IUnknown **evidence)
393 {
394     FIXME("stub %p\n", iface);
395     return E_NOTIMPL;
396 }
397 
398 static HRESULT WINAPI corruntimehost_UnloadDomain(
399     ICorRuntimeHost* iface,
400     IUnknown *appDomain)
401 {
402     FIXME("stub %p\n", iface);
403     return E_NOTIMPL;
404 }
405 
406 static HRESULT WINAPI corruntimehost_CurrentDomain(
407     ICorRuntimeHost* iface,
408     IUnknown **appDomain)
409 {
410     FIXME("stub %p\n", iface);
411     return E_NOTIMPL;
412 }
413 
414 static const struct ICorRuntimeHostVtbl corruntimehost_vtbl =
415 {
416     corruntimehost_QueryInterface,
417     corruntimehost_AddRef,
418     corruntimehost_Release,
419     corruntimehost_CreateLogicalThreadState,
420     corruntimehost_DeleteLogicalThreadState,
421     corruntimehost_SwitchInLogicalThreadState,
422     corruntimehost_SwitchOutLogicalThreadState,
423     corruntimehost_LocksHeldByLogicalThread,
424     corruntimehost_MapFile,
425     corruntimehost_GetConfiguration,
426     corruntimehost_Start,
427     corruntimehost_Stop,
428     corruntimehost_CreateDomain,
429     corruntimehost_GetDefaultDomain,
430     corruntimehost_EnumDomains,
431     corruntimehost_NextDomain,
432     corruntimehost_CloseEnum,
433     corruntimehost_CreateDomainEx,
434     corruntimehost_CreateDomainSetup,
435     corruntimehost_CreateEvidence,
436     corruntimehost_UnloadDomain,
437     corruntimehost_CurrentDomain
438 };
439 
440 static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface,
441         REFIID riid,
442         void **ppvObject)
443 {
444     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
445     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
446 
447     if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) ||
448          IsEqualGUID( riid, &IID_IUnknown ) )
449     {
450         *ppvObject = iface;
451     }
452     else
453     {
454         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
455         return E_NOINTERFACE;
456     }
457 
458     ICLRRuntimeHost_AddRef( iface );
459 
460     return S_OK;
461 }
462 
463 static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface)
464 {
465     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
466     return ICorRuntimeHost_AddRef(&This->ICorRuntimeHost_iface);
467 }
468 
469 static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface)
470 {
471     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
472     return ICorRuntimeHost_Release(&This->ICorRuntimeHost_iface);
473 }
474 
475 static HRESULT WINAPI CLRRuntimeHost_Start(ICLRRuntimeHost* iface)
476 {
477     FIXME("(%p)\n", iface);
478     return E_NOTIMPL;
479 }
480 
481 static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
482 {
483     FIXME("(%p)\n", iface);
484     return E_NOTIMPL;
485 }
486 
487 static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
488     IHostControl *pHostControl)
489 {
490     FIXME("(%p,%p)\n", iface, pHostControl);
491     return E_NOTIMPL;
492 }
493 
494 static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
495     ICLRControl **pCLRControl)
496 {
497     FIXME("(%p,%p)\n", iface, pCLRControl);
498     return E_NOTIMPL;
499 }
500 
501 static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
502     DWORD dwAppDomainId, BOOL fWaitUntilDone)
503 {
504     FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
505     return E_NOTIMPL;
506 }
507 
508 static HRESULT WINAPI CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost* iface,
509     DWORD dwAppDomainId, FExecuteInAppDomainCallback pCallback, void *cookie)
510 {
511     FIXME("(%p,%u,%p,%p)\n", iface, dwAppDomainId, pCallback, cookie);
512     return E_NOTIMPL;
513 }
514 
515 static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
516     DWORD *pdwAppDomainId)
517 {
518     FIXME("(%p,%p)\n", iface, pdwAppDomainId);
519     return E_NOTIMPL;
520 }
521 
522 static HRESULT WINAPI CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost* iface,
523     LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR *ppwzManifestPaths,
524     DWORD dwActivationData, LPCWSTR *ppwzActivationData, int *pReturnValue)
525 {
526     FIXME("(%p,%s,%u,%u)\n", iface, debugstr_w(pwzAppFullName), dwManifestPaths, dwActivationData);
527     return E_NOTIMPL;
528 }
529 
530 static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* iface,
531     LPCWSTR pwzAssemblyPath, LPCWSTR pwzTypeName, LPCWSTR pwzMethodName,
532     LPCWSTR pwzArgument, DWORD *pReturnValue)
533 {
534     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
535     HRESULT hr;
536     MonoDomain *domain;
537     MonoAssembly *assembly;
538     MonoImage *image;
539     MonoClass *klass;
540     MonoMethod *method;
541     MonoObject *result;
542     MonoString *str;
543     void *args[2];
544     char *filenameA = NULL, *classA = NULL, *methodA = NULL;
545     char *argsA = NULL, *ns;
546 
547     TRACE("(%p,%s,%s,%s,%s)\n", iface, debugstr_w(pwzAssemblyPath),
548         debugstr_w(pwzTypeName), debugstr_w(pwzMethodName), debugstr_w(pwzArgument));
549 
550     hr = RuntimeHost_GetDefaultDomain(This, &domain);
551     if(hr != S_OK)
552     {
553         ERR("Couldn't get Default Domain\n");
554         return hr;
555     }
556 
557     hr = E_FAIL;
558 
559     This->mono->mono_thread_attach(domain);
560 
561     filenameA = WtoA(pwzAssemblyPath);
562     assembly = This->mono->mono_domain_assembly_open(domain, filenameA);
563     if (!assembly)
564     {
565         ERR("Cannot open assembly %s\n", filenameA);
566         goto cleanup;
567     }
568 
569     image = This->mono->mono_assembly_get_image(assembly);
570     if (!image)
571     {
572         ERR("Couldn't get assembly image\n");
573         goto cleanup;
574     }
575 
576     classA = WtoA(pwzTypeName);
577     ns = strrchr(classA, '.');
578     *ns = '\0';
579     klass = This->mono->mono_class_from_name(image, classA, ns+1);
580     if (!klass)
581     {
582         ERR("Couldn't get class from image\n");
583         goto cleanup;
584     }
585 
586     methodA = WtoA(pwzMethodName);
587     method = This->mono->mono_class_get_method_from_name(klass, methodA, 1);
588     if (!method)
589     {
590         ERR("Couldn't get method from class\n");
591         goto cleanup;
592     }
593 
594     /* The .NET function we are calling has the following declaration
595      *   public static int functionName(String param)
596      */
597     argsA = WtoA(pwzArgument);
598     str = This->mono->mono_string_new(domain, argsA);
599     args[0] = str;
600     args[1] = NULL;
601     result = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
602     if (!result)
603         ERR("Couldn't get result pointer\n");
604     else
605     {
606         *pReturnValue = *(DWORD*)This->mono->mono_object_unbox(result);
607         hr = S_OK;
608     }
609 
610 cleanup:
611     HeapFree(GetProcessHeap(), 0, filenameA);
612     HeapFree(GetProcessHeap(), 0, classA);
613     HeapFree(GetProcessHeap(), 0, argsA);
614     HeapFree(GetProcessHeap(), 0, methodA);
615 
616     return hr;
617 }
618 
619 static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
620 {
621     CLRRuntimeHost_QueryInterface,
622     CLRRuntimeHost_AddRef,
623     CLRRuntimeHost_Release,
624     CLRRuntimeHost_Start,
625     CLRRuntimeHost_Stop,
626     CLRRuntimeHost_SetHostControl,
627     CLRRuntimeHost_GetCLRControl,
628     CLRRuntimeHost_UnloadAppDomain,
629     CLRRuntimeHost_ExecuteInAppDomain,
630     CLRRuntimeHost_GetCurrentAppDomainId,
631     CLRRuntimeHost_ExecuteApplication,
632     CLRRuntimeHost_ExecuteInDefaultAppDomain
633 };
634 
635 /* Create an instance of a type given its name, by calling its constructor with
636  * no arguments. Note that result MUST be in the stack, or the garbage
637  * collector may free it prematurely. */
638 HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
639     MonoDomain *domain, MonoObject **result)
640 {
641     HRESULT hr=S_OK;
642     char *nameA=NULL;
643     MonoType *type;
644     MonoClass *klass;
645     MonoObject *obj;
646 
647     if (!domain)
648         hr = RuntimeHost_GetDefaultDomain(This, &domain);
649 
650     if (SUCCEEDED(hr))
651     {
652         nameA = WtoA(name);
653         if (!nameA)
654             hr = E_OUTOFMEMORY;
655     }
656 
657     if (SUCCEEDED(hr))
658     {
659         This->mono->mono_thread_attach(domain);
660 
661         type = This->mono->mono_reflection_type_from_name(nameA, NULL);
662         if (!type)
663         {
664             ERR("Cannot find type %s\n", debugstr_w(name));
665             hr = E_FAIL;
666         }
667     }
668 
669     if (SUCCEEDED(hr))
670     {
671         klass = This->mono->mono_class_from_mono_type(type);
672         if (!klass)
673         {
674             ERR("Cannot convert type %s to a class\n", debugstr_w(name));
675             hr = E_FAIL;
676         }
677     }
678 
679     if (SUCCEEDED(hr))
680     {
681         obj = This->mono->mono_object_new(domain, klass);
682         if (!obj)
683         {
684             ERR("Cannot allocate object of type %s\n", debugstr_w(name));
685             hr = E_FAIL;
686         }
687     }
688 
689     if (SUCCEEDED(hr))
690     {
691         /* FIXME: Detect exceptions from the constructor? */
692         This->mono->mono_runtime_object_init(obj);
693         *result = obj;
694     }
695 
696     HeapFree(GetProcessHeap(), 0, nameA);
697 
698     return hr;
699 }
700 
701 /* Get an IUnknown pointer for a Mono object.
702  *
703  * This is just a "light" wrapper around
704  * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
705  *
706  * NOTE: The IUnknown* is created with a reference to the object.
707  * Until they have a reference, objects must be in the stack to prevent the
708  * garbage collector from freeing them.
709  *
710  * mono_thread_attach must have already been called for this thread. */
711 HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj,
712     IUnknown **ppUnk)
713 {
714     MonoDomain *domain;
715     MonoAssembly *assembly;
716     MonoImage *image;
717     MonoClass *klass;
718     MonoMethod *method;
719     MonoObject *result;
720     void *args[2];
721 
722     domain = This->mono->mono_object_get_domain(obj);
723 
724     assembly = This->mono->mono_domain_assembly_open(domain, "mscorlib");
725     if (!assembly)
726     {
727         ERR("Cannot load mscorlib\n");
728         return E_FAIL;
729     }
730 
731     image = This->mono->mono_assembly_get_image(assembly);
732     if (!image)
733     {
734         ERR("Couldn't get assembly image\n");
735         return E_FAIL;
736     }
737 
738     klass = This->mono->mono_class_from_name(image, "System.Runtime.InteropServices", "Marshal");
739     if (!klass)
740     {
741         ERR("Couldn't get class from image\n");
742         return E_FAIL;
743     }
744 
745     method = This->mono->mono_class_get_method_from_name(klass, "GetIUnknownForObject", 1);
746     if (!method)
747     {
748         ERR("Couldn't get method from class\n");
749         return E_FAIL;
750     }
751 
752     args[0] = obj;
753     args[1] = NULL;
754     result = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
755     if (!result)
756     {
757         ERR("Couldn't get result pointer\n");
758         return E_FAIL;
759     }
760 
761     *ppUnk = *(IUnknown**)This->mono->mono_object_unbox(result);
762     if (!*ppUnk)
763     {
764         ERR("GetIUnknownForObject returned 0\n");
765         return E_FAIL;
766     }
767 
768     return S_OK;
769 }
770 
771 static void get_utf8_args(int *argc, char ***argv)
772 {
773     WCHAR **argvw;
774     int size=0, i;
775     char *current_arg;
776 
777     argvw = CommandLineToArgvW(GetCommandLineW(), argc);
778 
779     for (i=0; i<*argc; i++)
780     {
781         size += sizeof(char*);
782         size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
783     }
784     size += sizeof(char*);
785 
786     *argv = HeapAlloc(GetProcessHeap(), 0, size);
787     current_arg = (char*)(*argv + *argc + 1);
788 
789     for (i=0; i<*argc; i++)
790     {
791         (*argv)[i] = current_arg;
792         current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
793     }
794 
795     (*argv)[*argc] = NULL;
796 
797     HeapFree(GetProcessHeap(), 0, argvw);
798 }
799 
800 #if __i386__
801 
802 # define CAN_FIXUP_VTABLE 1
803 
804 #include "pshpack1.h"
805 
806 struct vtable_fixup_thunk
807 {
808     /* sub $0x4,%esp */
809     BYTE i1[3];
810     /* mov fixup,(%esp) */
811     BYTE i2[3];
812     struct dll_fixup *fixup;
813     /* mov function,%eax */
814     BYTE i3;
815     void (CDECL *function)(struct dll_fixup *);
816     /* call *%eax */
817     BYTE i4[2];
818     /* pop %eax */
819     BYTE i5;
820     /* jmp *vtable_entry */
821     BYTE i6[2];
822     void *vtable_entry;
823 };
824 
825 static const struct vtable_fixup_thunk thunk_template = {
826     {0x83,0xec,0x04},
827     {0xc7,0x04,0x24},
828     NULL,
829     0xb8,
830     NULL,
831     {0xff,0xd0},
832     0x58,
833     {0xff,0x25},
834     NULL
835 };
836 
837 #include "poppack.h"
838 
839 #else /* !defined(__i386__) */
840 
841 # define CAN_FIXUP_VTABLE 0
842 
843 struct vtable_fixup_thunk
844 {
845     struct dll_fixup *fixup;
846     void (CDECL *function)(struct dll_fixup *fixup);
847     void *vtable_entry;
848 };
849 
850 static const struct vtable_fixup_thunk thunk_template = {0};
851 
852 #endif
853 
854 static void CDECL ReallyFixupVTable(struct dll_fixup *fixup)
855 {
856     HRESULT hr=S_OK;
857     WCHAR filename[MAX_PATH];
858     ICLRRuntimeInfo *info=NULL;
859     RuntimeHost *host;
860     char *filenameA;
861     MonoImage *image=NULL;
862     MonoAssembly *assembly=NULL;
863     MonoImageOpenStatus status=0;
864     MonoDomain *domain;
865 
866     if (fixup->done) return;
867 
868     /* It's possible we'll have two threads doing this at once. This is
869      * considered preferable to the potential deadlock if we use a mutex. */
870 
871     GetModuleFileNameW(fixup->dll, filename, MAX_PATH);
872 
873     TRACE("%p,%p,%s\n", fixup, fixup->dll, debugstr_w(filename));
874 
875     filenameA = WtoA(filename);
876     if (!filenameA)
877         hr = E_OUTOFMEMORY;
878 
879     if (SUCCEEDED(hr))
880         hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
881 
882     if (SUCCEEDED(hr))
883         hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
884 
885     if (SUCCEEDED(hr))
886         hr = RuntimeHost_GetDefaultDomain(host, &domain);
887 
888     if (SUCCEEDED(hr))
889     {
890         host->mono->mono_thread_attach(domain);
891 
892         image = host->mono->mono_image_open_from_module_handle(fixup->dll,
893             filenameA, 1, &status);
894     }
895 
896     if (image)
897         assembly = host->mono->mono_assembly_load_from(image, filenameA, &status);
898 
899     if (assembly)
900     {
901         int i;
902 
903         /* Mono needs an image that belongs to an assembly. */
904         image = host->mono->mono_assembly_get_image(assembly);
905 
906         if (fixup->fixup->type & COR_VTABLE_32BIT)
907         {
908             DWORD *vtable = fixup->vtable;
909             DWORD *tokens = fixup->tokens;
910             for (i=0; i<fixup->fixup->count; i++)
911             {
912                 TRACE("%x\n", tokens[i]);
913                 vtable[i] = PtrToUint(host->mono->mono_marshal_get_vtfixup_ftnptr(
914                     image, tokens[i], fixup->fixup->type));
915             }
916         }
917 
918         fixup->done = 1;
919     }
920 
921     if (info != NULL)
922         ICLRRuntimeInfo_Release(info);
923 
924     HeapFree(GetProcessHeap(), 0, filenameA);
925 
926     if (!fixup->done)
927     {
928         ERR("unable to fixup vtable, hr=%x, status=%d\n", hr, status);
929         /* If we returned now, we'd get an infinite loop. */
930         assert(0);
931     }
932 }
933 
934 static void FixupVTableEntry(HMODULE hmodule, VTableFixup *vtable_fixup)
935 {
936     /* We can't actually generate code for the functions without loading mono,
937      * and loading mono inside DllMain is a terrible idea. So we make thunks
938      * that call ReallyFixupVTable, which will load the runtime and fill in the
939      * vtable, then do an indirect jump using the (now filled in) vtable. Note
940      * that we have to keep the thunks around forever, as one of them may get
941      * called while we're filling in the table, and we can never be sure all
942      * threads are clear. */
943     struct dll_fixup *fixup;
944 
945     fixup = HeapAlloc(GetProcessHeap(), 0, sizeof(*fixup));
946 
947     fixup->dll = hmodule;
948     fixup->thunk_code = HeapAlloc(dll_fixup_heap, 0, sizeof(struct vtable_fixup_thunk) * vtable_fixup->count);
949     fixup->fixup = vtable_fixup;
950     fixup->vtable = (BYTE*)hmodule + vtable_fixup->rva;
951     fixup->done = 0;
952 
953     if (vtable_fixup->type & COR_VTABLE_32BIT)
954     {
955         DWORD *vtable = fixup->vtable;
956         DWORD *tokens;
957         int i;
958         struct vtable_fixup_thunk *thunks = fixup->thunk_code;
959 
960         if (sizeof(void*) > 4)
961             ERR("32-bit fixup in 64-bit mode; broken image?\n");
962 
963         tokens = fixup->tokens = HeapAlloc(GetProcessHeap(), 0, sizeof(*tokens) * vtable_fixup->count);
964         memcpy(tokens, vtable, sizeof(*tokens) * vtable_fixup->count);
965         for (i=0; i<vtable_fixup->count; i++)
966         {
967             memcpy(&thunks[i], &thunk_template, sizeof(thunk_template));
968             thunks[i].fixup = fixup;
969             thunks[i].function = ReallyFixupVTable;
970             thunks[i].vtable_entry = &vtable[i];
971             vtable[i] = PtrToUint(&thunks[i]);
972         }
973     }
974     else
975     {
976         ERR("unsupported vtable fixup flags %x\n", vtable_fixup->type);
977         HeapFree(dll_fixup_heap, 0, fixup->thunk_code);
978         HeapFree(GetProcessHeap(), 0, fixup);
979         return;
980     }
981 
982     list_add_tail(&dll_fixups, &fixup->entry);
983 }
984 
985 static void FixupVTable(HMODULE hmodule)
986 {
987     ASSEMBLY *assembly;
988     HRESULT hr;
989     VTableFixup *vtable_fixups;
990     ULONG vtable_fixup_count, i;
991 
992     hr = assembly_from_hmodule(&assembly, hmodule);
993     if (SUCCEEDED(hr))
994     {
995         hr = assembly_get_vtable_fixups(assembly, &vtable_fixups, &vtable_fixup_count);
996         if (CAN_FIXUP_VTABLE)
997             for (i=0; i<vtable_fixup_count; i++)
998                 FixupVTableEntry(hmodule, &vtable_fixups[i]);
999         else if (vtable_fixup_count)
1000             FIXME("cannot fixup vtable; expect a crash\n");
1001 
1002         assembly_release(assembly);
1003     }
1004     else
1005         ERR("failed to read CLR headers, hr=%x\n", hr);
1006 }
1007 
1008 __int32 WINAPI _CorExeMain(void)
1009 {
1010     int exit_code;
1011     int argc;
1012     char **argv;
1013     MonoDomain *domain;
1014     MonoImage *image;
1015     MonoImageOpenStatus status;
1016     MonoAssembly *assembly=NULL;
1017     WCHAR filename[MAX_PATH];
1018     char *filenameA;
1019     ICLRRuntimeInfo *info;
1020     RuntimeHost *host;
1021     HRESULT hr;
1022     int i;
1023 
1024     get_utf8_args(&argc, &argv);
1025 
1026     GetModuleFileNameW(NULL, filename, MAX_PATH);
1027 
1028     TRACE("%s", debugstr_w(filename));
1029     for (i=0; i<argc; i++)
1030         TRACE(" %s", debugstr_a(argv[i]));
1031     TRACE("\n");
1032 
1033     filenameA = WtoA(filename);
1034     if (!filenameA)
1035         return -1;
1036 
1037     FixupVTable(GetModuleHandleW(NULL));
1038 
1039     hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1040 
1041     if (SUCCEEDED(hr))
1042     {
1043         hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1044 
1045         if (SUCCEEDED(hr))
1046             hr = RuntimeHost_GetDefaultDomain(host, &domain);
1047 
1048         if (SUCCEEDED(hr))
1049         {
1050             image = host->mono->mono_image_open_from_module_handle(GetModuleHandleW(NULL),
1051                 filenameA, 1, &status);
1052 
1053             if (image)
1054                 assembly = host->mono->mono_assembly_load_from(image, filenameA, &status);
1055 
1056             if (assembly)
1057             {
1058                 exit_code = host->mono->mono_jit_exec(domain, assembly, argc, argv);
1059             }
1060             else
1061             {
1062                 ERR("couldn't load %s, status=%d\n", debugstr_w(filename), status);
1063                 exit_code = -1;
1064             }
1065 
1066             RuntimeHost_DeleteDomain(host, domain);
1067         }
1068         else
1069             exit_code = -1;
1070 
1071         ICLRRuntimeInfo_Release(info);
1072     }
1073     else
1074         exit_code = -1;
1075 
1076     HeapFree(GetProcessHeap(), 0, argv);
1077 
1078     unload_all_runtimes();
1079 
1080     return exit_code;
1081 }
1082 
1083 BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1084 {
1085     TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1086 
1087     switch (fdwReason)
1088     {
1089     case DLL_PROCESS_ATTACH:
1090         DisableThreadLibraryCalls(hinstDLL);
1091         FixupVTable(hinstDLL);
1092         break;
1093     case DLL_PROCESS_DETACH:
1094         /* FIXME: clean up the vtables */
1095         break;
1096     }
1097     return TRUE;
1098 }
1099 
1100 /* called from DLL_PROCESS_ATTACH */
1101 void runtimehost_init(void)
1102 {
1103     dll_fixup_heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
1104     list_init(&dll_fixups);
1105 }
1106 
1107 /* called from DLL_PROCESS_DETACH */
1108 void runtimehost_uninit(void)
1109 {
1110     struct dll_fixup *fixup, *fixup2;
1111 
1112     HeapDestroy(dll_fixup_heap);
1113     LIST_FOR_EACH_ENTRY_SAFE(fixup, fixup2, &dll_fixups, struct dll_fixup, entry)
1114     {
1115         HeapFree(GetProcessHeap(), 0, fixup->tokens);
1116         HeapFree(GetProcessHeap(), 0, fixup);
1117     }
1118 }
1119 
1120 HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version,
1121     loaded_mono *loaded_mono, RuntimeHost** result)
1122 {
1123     RuntimeHost *This;
1124 
1125     This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1126     if ( !This )
1127         return E_OUTOFMEMORY;
1128 
1129     This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
1130     This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
1131 
1132     This->ref = 1;
1133     This->version = runtime_version;
1134     This->mono = loaded_mono;
1135     list_init(&This->domains);
1136     This->default_domain = NULL;
1137     InitializeCriticalSection(&This->lock);
1138     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
1139 
1140     *result = This;
1141 
1142     return S_OK;
1143 }
1144 
1145 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
1146 {
1147     IUnknown *unk;
1148     HRESULT hr;
1149 
1150     if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
1151     {
1152         unk = (IUnknown*)&This->ICorRuntimeHost_iface;
1153         IUnknown_AddRef(unk);
1154     }
1155     else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
1156     {
1157         unk = (IUnknown*)&This->ICLRRuntimeHost_iface;
1158         IUnknown_AddRef(unk);
1159     }
1160     else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
1161              IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
1162     {
1163         hr = MetaDataDispenser_CreateInstance(&unk);
1164         if (FAILED(hr))
1165             return hr;
1166     }
1167     else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
1168     {
1169         hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
1170         if (FAILED(hr))
1171             return hr;
1172     }
1173     else
1174         unk = NULL;
1175 
1176     if (unk)
1177     {
1178         hr = IUnknown_QueryInterface(unk, riid, ppv);
1179 
1180         IUnknown_Release(unk);
1181 
1182         return hr;
1183     }
1184     else
1185         FIXME("not implemented for class %s\n", debugstr_guid(clsid));
1186 
1187     return CLASS_E_CLASSNOTAVAILABLE;
1188 }
1189 
1190 HRESULT RuntimeHost_Destroy(RuntimeHost *This)
1191 {
1192     struct DomainEntry *cursor, *cursor2;
1193 
1194     This->lock.DebugInfo->Spare[0] = 0;
1195     DeleteCriticalSection(&This->lock);
1196 
1197     LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->domains, struct DomainEntry, entry)
1198     {
1199         list_remove(&cursor->entry);
1200         HeapFree(GetProcessHeap(), 0, cursor);
1201     }
1202 
1203     HeapFree( GetProcessHeap(), 0, This );
1204     return S_OK;
1205 }
1206 
1207 #define CHARS_IN_GUID 39
1208 #undef ARRAYSIZE
1209 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
1210 
1211 HRESULT create_monodata(REFIID riid, LPVOID *ppObj )
1212 {
1213     static const WCHAR wszCodebase[] = {'C','o','d','e','B','a','s','e',0};
1214     static const WCHAR wszClass[] = {'C','l','a','s','s',0};
1215     static const WCHAR wszFileSlash[] = {'f','i','l','e',':','/','/','/',0};
1216     static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1217     static const WCHAR wszInprocServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1218     WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) + ARRAYSIZE(wszInprocServer32) - 1];
1219     MonoDomain *domain;
1220     MonoAssembly *assembly;
1221     ICLRRuntimeInfo *info = NULL;
1222     RuntimeHost *host;
1223     HRESULT hr;
1224     HKEY key;
1225     LONG res;
1226     int offset = 0;
1227     WCHAR codebase[MAX_PATH + 8];
1228     WCHAR classname[350];
1229     WCHAR filename[MAX_PATH];
1230 
1231     DWORD dwBufLen = 350;
1232 
1233     lstrcpyW(path, wszCLSIDSlash);
1234     StringFromGUID2(riid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
1235     lstrcatW(path, wszInprocServer32);
1236 
1237     TRACE("Registry key: %s\n", debugstr_w(path));
1238 
1239     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key);
1240     if (res == ERROR_FILE_NOT_FOUND)
1241         return CLASS_E_CLASSNOTAVAILABLE;
1242 
1243     res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen);
1244     if(res != ERROR_SUCCESS)
1245     {
1246         WARN("Class value cannot be found.\n");
1247         hr = CLASS_E_CLASSNOTAVAILABLE;
1248         goto cleanup;
1249     }
1250 
1251     TRACE("classname (%s)\n", debugstr_w(classname));
1252 
1253     dwBufLen = MAX_PATH + 8;
1254     res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen);
1255     if(res != ERROR_SUCCESS)
1256     {
1257         WARN("CodeBase value cannot be found.\n");
1258         hr = CLASS_E_CLASSNOTAVAILABLE;
1259         goto cleanup;
1260     }
1261 
1262     /* Strip file:/// */
1263     if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0)
1264         offset = strlenW(wszFileSlash);
1265 
1266     strcpyW(filename, codebase + offset);
1267 
1268     TRACE("codebase (%s)\n", debugstr_w(filename));
1269 
1270     *ppObj = NULL;
1271 
1272 
1273     hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1274     if (SUCCEEDED(hr))
1275     {
1276         hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1277 
1278         if (SUCCEEDED(hr))
1279             hr = RuntimeHost_GetDefaultDomain(host, &domain);
1280 
1281         if (SUCCEEDED(hr))
1282         {
1283             MonoImage *image;
1284             MonoClass *klass;
1285             MonoObject *result;
1286             IUnknown *unk = NULL;
1287             char *filenameA, *ns;
1288             char *classA;
1289 
1290             hr = CLASS_E_CLASSNOTAVAILABLE;
1291 
1292             host->mono->mono_thread_attach(domain);
1293 
1294             filenameA = WtoA(filename);
1295             assembly = host->mono->mono_domain_assembly_open(domain, filenameA);
1296             HeapFree(GetProcessHeap(), 0, filenameA);
1297             if (!assembly)
1298             {
1299                 ERR("Cannot open assembly %s\n", filenameA);
1300                 goto cleanup;
1301             }
1302 
1303             image = host->mono->mono_assembly_get_image(assembly);
1304             if (!image)
1305             {
1306                 ERR("Couldn't get assembly image\n");
1307                 goto cleanup;
1308             }
1309 
1310             classA = WtoA(classname);
1311             ns = strrchr(classA, '.');
1312             *ns = '\0';
1313 
1314             klass = host->mono->mono_class_from_name(image, classA, ns+1);
1315             HeapFree(GetProcessHeap(), 0, classA);
1316             if (!klass)
1317             {
1318                 ERR("Couldn't get class from image\n");
1319                 goto cleanup;
1320             }
1321 
1322             /*
1323              * Use the default constructor for the .NET class.
1324              */
1325             result = host->mono->mono_object_new(domain, klass);
1326             host->mono->mono_runtime_object_init(result);
1327 
1328             hr = RuntimeHost_GetIUnknownForObject(host, result, &unk);
1329             if (SUCCEEDED(hr))
1330             {
1331                 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj);
1332 
1333                 IUnknown_Release(unk);
1334             }
1335             else
1336                 hr = CLASS_E_CLASSNOTAVAILABLE;
1337         }
1338         else
1339             hr = CLASS_E_CLASSNOTAVAILABLE;
1340     }
1341     else
1342         hr = CLASS_E_CLASSNOTAVAILABLE;
1343 
1344 cleanup:
1345     if(info)
1346         ICLRRuntimeInfo_Release(info);
1347 
1348     RegCloseKey(key);
1349 
1350     return hr;
1351 }
1352