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