mscoree: Implement ICorRuntimeHost_GetDefaultDomain.
[wine] / dlls / mscoree / corruntimehost.c
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 COBJMACROS
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "winreg.h"
29 #include "ole2.h"
30 #include "shellapi.h"
31
32 #include "cor.h"
33 #include "mscoree.h"
34 #include "metahost.h"
35 #include "wine/list.h"
36 #include "mscoree_private.h"
37
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
41
42 #include "initguid.h"
43
44 DEFINE_GUID(IID__AppDomain, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13);
45
46 struct RuntimeHost
47 {
48     const struct ICorRuntimeHostVtbl *lpVtbl;
49     const struct ICLRRuntimeHostVtbl *lpCLRHostVtbl;
50     const CLRRuntimeInfo *version;
51     loaded_mono *mono;
52     struct list domains;
53     MonoDomain *default_domain;
54     CRITICAL_SECTION lock;
55     LONG ref;
56 };
57
58 struct DomainEntry
59 {
60     struct list entry;
61     MonoDomain *domain;
62 };
63
64 static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, MonoDomain **result)
65 {
66     struct DomainEntry *entry;
67     char *mscorlib_path;
68     HRESULT res=S_OK;
69
70     EnterCriticalSection(&This->lock);
71
72     entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
73     if (!entry)
74     {
75         res = E_OUTOFMEMORY;
76         goto end;
77     }
78
79     mscorlib_path = WtoA(This->version->mscorlib_path);
80     if (!mscorlib_path)
81     {
82         HeapFree(GetProcessHeap(), 0, entry);
83         res = E_OUTOFMEMORY;
84         goto end;
85     }
86
87     entry->domain = This->mono->mono_jit_init(mscorlib_path);
88
89     HeapFree(GetProcessHeap(), 0, mscorlib_path);
90
91     if (!entry->domain)
92     {
93         HeapFree(GetProcessHeap(), 0, entry);
94         res = E_FAIL;
95         goto end;
96     }
97
98     This->mono->is_started = TRUE;
99
100     list_add_tail(&This->domains, &entry->entry);
101
102     *result = entry->domain;
103
104 end:
105     LeaveCriticalSection(&This->lock);
106
107     return res;
108 }
109
110 static HRESULT RuntimeHost_GetDefaultDomain(RuntimeHost *This, MonoDomain **result)
111 {
112     HRESULT res=S_OK;
113
114     EnterCriticalSection(&This->lock);
115
116     if (This->default_domain) goto end;
117
118     res = RuntimeHost_AddDomain(This, &This->default_domain);
119
120 end:
121     *result = This->default_domain;
122
123     LeaveCriticalSection(&This->lock);
124
125     return res;
126 }
127
128 static void RuntimeHost_DeleteDomain(RuntimeHost *This, MonoDomain *domain)
129 {
130     struct DomainEntry *entry;
131
132     EnterCriticalSection(&This->lock);
133
134     LIST_FOR_EACH_ENTRY(entry, &This->domains, struct DomainEntry, entry)
135     {
136         if (entry->domain == domain)
137         {
138             list_remove(&entry->entry);
139             if (This->default_domain == domain)
140                 This->default_domain = NULL;
141             HeapFree(GetProcessHeap(), 0, entry);
142             break;
143         }
144     }
145
146     LeaveCriticalSection(&This->lock);
147 }
148
149 static HRESULT RuntimeHost_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *domain, IUnknown **punk)
150 {
151     HRESULT hr;
152     void *args[0];
153     MonoAssembly *assembly;
154     MonoImage *image;
155     MonoClass *klass;
156     MonoMethod *method;
157     MonoObject *appdomain_object;
158     IUnknown *unk;
159
160     assembly = This->mono->mono_domain_assembly_open(domain, "mscorlib");
161     if (!assembly)
162     {
163         ERR("Cannot load mscorlib\n");
164         return E_FAIL;
165     }
166
167     image = This->mono->mono_assembly_get_image(assembly);
168     if (!image)
169     {
170         ERR("Couldn't get assembly image\n");
171         return E_FAIL;
172     }
173
174     klass = This->mono->mono_class_from_name(image, "System", "AppDomain");
175     if (!klass)
176     {
177         ERR("Couldn't get class from image\n");
178         return E_FAIL;
179     }
180
181     method = This->mono->mono_class_get_method_from_name(klass, "get_CurrentDomain", 0);
182     if (!method)
183     {
184         ERR("Couldn't get method from class\n");
185         return E_FAIL;
186     }
187
188     args[0] = NULL;
189     appdomain_object = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
190     if (!appdomain_object)
191     {
192         ERR("Couldn't get result pointer\n");
193         return E_FAIL;
194     }
195
196     hr = RuntimeHost_GetIUnknownForObject(This, appdomain_object, &unk);
197
198     if (SUCCEEDED(hr))
199     {
200         hr = IUnknown_QueryInterface(unk, &IID__AppDomain, (void**)punk);
201
202         IUnknown_Release(unk);
203     }
204
205     return hr;
206 }
207
208 static inline RuntimeHost *impl_from_ICLRRuntimeHost( ICLRRuntimeHost *iface )
209 {
210     return (RuntimeHost *)((char*)iface - FIELD_OFFSET(RuntimeHost, lpCLRHostVtbl));
211 }
212
213 static inline RuntimeHost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
214 {
215     return (RuntimeHost *)((char*)iface - FIELD_OFFSET(RuntimeHost, lpVtbl));
216 }
217
218 /*** IUnknown methods ***/
219 static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
220         REFIID riid,
221         void **ppvObject)
222 {
223     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
224     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
225
226     if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) ||
227          IsEqualGUID( riid, &IID_IUnknown ) )
228     {
229         *ppvObject = iface;
230     }
231     else
232     {
233         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
234         return E_NOINTERFACE;
235     }
236
237     ICorRuntimeHost_AddRef( iface );
238
239     return S_OK;
240 }
241
242 static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface)
243 {
244     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
245
246     return InterlockedIncrement( &This->ref );
247 }
248
249 static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface)
250 {
251     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
252     ULONG ref;
253
254     ref = InterlockedDecrement( &This->ref );
255
256     return ref;
257 }
258
259 /*** ICorRuntimeHost methods ***/
260 static HRESULT WINAPI corruntimehost_CreateLogicalThreadState(
261                     ICorRuntimeHost* iface)
262 {
263     FIXME("stub %p\n", iface);
264     return E_NOTIMPL;
265 }
266
267 static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState(
268                     ICorRuntimeHost* iface)
269 {
270     FIXME("stub %p\n", iface);
271     return E_NOTIMPL;
272 }
273
274 static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState(
275                     ICorRuntimeHost* iface,
276                     DWORD *fiberCookie)
277 {
278     FIXME("stub %p\n", iface);
279     return E_NOTIMPL;
280 }
281
282 static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState(
283                     ICorRuntimeHost* iface,
284                     DWORD **fiberCookie)
285 {
286     FIXME("stub %p\n", iface);
287     return E_NOTIMPL;
288 }
289
290 static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread(
291                     ICorRuntimeHost* iface,
292                     DWORD *pCount)
293 {
294     FIXME("stub %p\n", iface);
295     return E_NOTIMPL;
296 }
297
298 static HRESULT WINAPI corruntimehost_MapFile(
299     ICorRuntimeHost* iface,
300     HANDLE hFile,
301     HMODULE *mapAddress)
302 {
303     FIXME("stub %p\n", iface);
304     return E_NOTIMPL;
305 }
306
307 static HRESULT WINAPI corruntimehost_GetConfiguration(
308     ICorRuntimeHost* iface,
309     ICorConfiguration **pConfiguration)
310 {
311     FIXME("stub %p\n", iface);
312     return E_NOTIMPL;
313 }
314
315 static HRESULT WINAPI corruntimehost_Start(
316     ICorRuntimeHost* iface)
317 {
318     FIXME("stub %p\n", iface);
319     return S_OK;
320 }
321
322 static HRESULT WINAPI corruntimehost_Stop(
323     ICorRuntimeHost* iface)
324 {
325     FIXME("stub %p\n", iface);
326     return E_NOTIMPL;
327 }
328
329 static HRESULT WINAPI corruntimehost_CreateDomain(
330     ICorRuntimeHost* iface,
331     LPCWSTR friendlyName,
332     IUnknown *identityArray,
333     IUnknown **appDomain)
334 {
335     FIXME("stub %p\n", iface);
336     return E_NOTIMPL;
337 }
338
339 static HRESULT WINAPI corruntimehost_GetDefaultDomain(
340     ICorRuntimeHost* iface,
341     IUnknown **pAppDomain)
342 {
343     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
344     HRESULT hr;
345     MonoDomain *domain;
346
347     TRACE("(%p)\n", iface);
348
349     hr = RuntimeHost_GetDefaultDomain(This, &domain);
350
351     if (SUCCEEDED(hr))
352     {
353         hr = RuntimeHost_GetIUnknownForDomain(This, domain, pAppDomain);
354     }
355
356     return hr;
357 }
358
359 static HRESULT WINAPI corruntimehost_EnumDomains(
360     ICorRuntimeHost* iface,
361     HDOMAINENUM *hEnum)
362 {
363     FIXME("stub %p\n", iface);
364     return E_NOTIMPL;
365 }
366
367 static HRESULT WINAPI corruntimehost_NextDomain(
368     ICorRuntimeHost* iface,
369     HDOMAINENUM hEnum,
370     IUnknown **appDomain)
371 {
372     FIXME("stub %p\n", iface);
373     return E_NOTIMPL;
374 }
375
376 static HRESULT WINAPI corruntimehost_CloseEnum(
377     ICorRuntimeHost* iface,
378     HDOMAINENUM hEnum)
379 {
380     FIXME("stub %p\n", iface);
381     return E_NOTIMPL;
382 }
383
384 static HRESULT WINAPI corruntimehost_CreateDomainEx(
385     ICorRuntimeHost* iface,
386     LPCWSTR friendlyName,
387     IUnknown *setup,
388     IUnknown *evidence,
389     IUnknown **appDomain)
390 {
391     FIXME("stub %p\n", iface);
392     return E_NOTIMPL;
393 }
394
395 static HRESULT WINAPI corruntimehost_CreateDomainSetup(
396     ICorRuntimeHost* iface,
397     IUnknown **appDomainSetup)
398 {
399     FIXME("stub %p\n", iface);
400     return E_NOTIMPL;
401 }
402
403 static HRESULT WINAPI corruntimehost_CreateEvidence(
404     ICorRuntimeHost* iface,
405     IUnknown **evidence)
406 {
407     FIXME("stub %p\n", iface);
408     return E_NOTIMPL;
409 }
410
411 static HRESULT WINAPI corruntimehost_UnloadDomain(
412     ICorRuntimeHost* iface,
413     IUnknown *appDomain)
414 {
415     FIXME("stub %p\n", iface);
416     return E_NOTIMPL;
417 }
418
419 static HRESULT WINAPI corruntimehost_CurrentDomain(
420     ICorRuntimeHost* iface,
421     IUnknown **appDomain)
422 {
423     FIXME("stub %p\n", iface);
424     return E_NOTIMPL;
425 }
426
427 static const struct ICorRuntimeHostVtbl corruntimehost_vtbl =
428 {
429     corruntimehost_QueryInterface,
430     corruntimehost_AddRef,
431     corruntimehost_Release,
432     corruntimehost_CreateLogicalThreadState,
433     corruntimehost_DeleteLogicalThreadState,
434     corruntimehost_SwitchInLogicalThreadState,
435     corruntimehost_SwitchOutLogicalThreadState,
436     corruntimehost_LocksHeldByLogicalThread,
437     corruntimehost_MapFile,
438     corruntimehost_GetConfiguration,
439     corruntimehost_Start,
440     corruntimehost_Stop,
441     corruntimehost_CreateDomain,
442     corruntimehost_GetDefaultDomain,
443     corruntimehost_EnumDomains,
444     corruntimehost_NextDomain,
445     corruntimehost_CloseEnum,
446     corruntimehost_CreateDomainEx,
447     corruntimehost_CreateDomainSetup,
448     corruntimehost_CreateEvidence,
449     corruntimehost_UnloadDomain,
450     corruntimehost_CurrentDomain
451 };
452
453 static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface,
454         REFIID riid,
455         void **ppvObject)
456 {
457     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
458     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
459
460     if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) ||
461          IsEqualGUID( riid, &IID_IUnknown ) )
462     {
463         *ppvObject = iface;
464     }
465     else
466     {
467         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
468         return E_NOINTERFACE;
469     }
470
471     ICLRRuntimeHost_AddRef( iface );
472
473     return S_OK;
474 }
475
476 static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface)
477 {
478     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
479     return IUnknown_AddRef((IUnknown*)&This->lpVtbl);
480 }
481
482 static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface)
483 {
484     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
485     return IUnknown_Release((IUnknown*)&This->lpVtbl);
486 }
487
488 static HRESULT WINAPI CLRRuntimeHost_Start(ICLRRuntimeHost* iface)
489 {
490     FIXME("(%p)\n", iface);
491     return E_NOTIMPL;
492 }
493
494 static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
495 {
496     FIXME("(%p)\n", iface);
497     return E_NOTIMPL;
498 }
499
500 static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
501     IHostControl *pHostControl)
502 {
503     FIXME("(%p,%p)\n", iface, pHostControl);
504     return E_NOTIMPL;
505 }
506
507 static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
508     ICLRControl **pCLRControl)
509 {
510     FIXME("(%p,%p)\n", iface, pCLRControl);
511     return E_NOTIMPL;
512 }
513
514 static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
515     DWORD dwAppDomainId, BOOL fWaitUntilDone)
516 {
517     FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
518     return E_NOTIMPL;
519 }
520
521 static HRESULT WINAPI CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost* iface,
522     DWORD dwAppDomainId, FExecuteInAppDomainCallback pCallback, void *cookie)
523 {
524     FIXME("(%p,%u,%p,%p)\n", iface, dwAppDomainId, pCallback, cookie);
525     return E_NOTIMPL;
526 }
527
528 static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
529     DWORD *pdwAppDomainId)
530 {
531     FIXME("(%p,%p)\n", iface, pdwAppDomainId);
532     return E_NOTIMPL;
533 }
534
535 static HRESULT WINAPI CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost* iface,
536     LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR *ppwzManifestPaths,
537     DWORD dwActivationData, LPCWSTR *ppwzActivationData, int *pReturnValue)
538 {
539     FIXME("(%p,%s,%u,%u)\n", iface, debugstr_w(pwzAppFullName), dwManifestPaths, dwActivationData);
540     return E_NOTIMPL;
541 }
542
543 static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* iface,
544     LPCWSTR pwzAssemblyPath, LPCWSTR pwzTypeName, LPCWSTR pwzMethodName,
545     LPCWSTR pwzArgument, DWORD *pReturnValue)
546 {
547     FIXME("(%p,%s,%s,%s,%s)\n", iface, debugstr_w(pwzAssemblyPath),
548         debugstr_w(pwzTypeName), debugstr_w(pwzMethodName), debugstr_w(pwzArgument));
549     return E_NOTIMPL;
550 }
551
552 static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
553 {
554     CLRRuntimeHost_QueryInterface,
555     CLRRuntimeHost_AddRef,
556     CLRRuntimeHost_Release,
557     CLRRuntimeHost_Start,
558     CLRRuntimeHost_Stop,
559     CLRRuntimeHost_SetHostControl,
560     CLRRuntimeHost_GetCLRControl,
561     CLRRuntimeHost_UnloadAppDomain,
562     CLRRuntimeHost_ExecuteInAppDomain,
563     CLRRuntimeHost_GetCurrentAppDomainId,
564     CLRRuntimeHost_ExecuteApplication,
565     CLRRuntimeHost_ExecuteInDefaultAppDomain
566 };
567
568 /* Create an instance of a type given its name, by calling its constructor with
569  * no arguments. Note that result MUST be in the stack, or the garbage
570  * collector may free it prematurely. */
571 HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
572     MonoDomain *domain, MonoObject **result)
573 {
574     HRESULT hr=S_OK;
575     char *nameA=NULL;
576     MonoType *type;
577     MonoClass *klass;
578     MonoObject *obj;
579
580     if (!domain)
581         hr = RuntimeHost_GetDefaultDomain(This, &domain);
582
583     if (SUCCEEDED(hr))
584     {
585         nameA = WtoA(name);
586         if (!nameA)
587             hr = E_OUTOFMEMORY;
588     }
589
590     if (SUCCEEDED(hr))
591     {
592         type = This->mono->mono_reflection_type_from_name(nameA, NULL);
593         if (!type)
594         {
595             ERR("Cannot find type %s\n", debugstr_w(name));
596             hr = E_FAIL;
597         }
598     }
599
600     if (SUCCEEDED(hr))
601     {
602         klass = This->mono->mono_class_from_mono_type(type);
603         if (!klass)
604         {
605             ERR("Cannot convert type %s to a class\n", debugstr_w(name));
606             hr = E_FAIL;
607         }
608     }
609
610     if (SUCCEEDED(hr))
611     {
612         obj = This->mono->mono_object_new(domain, klass);
613         if (!obj)
614         {
615             ERR("Cannot allocate object of type %s\n", debugstr_w(name));
616             hr = E_FAIL;
617         }
618     }
619
620     if (SUCCEEDED(hr))
621     {
622         /* FIXME: Detect exceptions from the constructor? */
623         This->mono->mono_runtime_object_init(obj);
624         *result = obj;
625     }
626
627     HeapFree(GetProcessHeap(), 0, nameA);
628
629     return hr;
630 }
631
632 /* Get an IUnknown pointer for a Mono object.
633  *
634  * This is just a "light" wrapper around
635  * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
636  *
637  * NOTE: The IUnknown* is created with a reference to the object.
638  * Until they have a reference, objects must be in the stack to prevent the
639  * garbage collector from freeing them. */
640 HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj,
641     IUnknown **ppUnk)
642 {
643     MonoDomain *domain;
644     MonoAssembly *assembly;
645     MonoImage *image;
646     MonoClass *klass;
647     MonoMethod *method;
648     MonoObject *result;
649     void *args[2];
650
651     domain = This->mono->mono_object_get_domain(obj);
652
653     assembly = This->mono->mono_domain_assembly_open(domain, "mscorlib");
654     if (!assembly)
655     {
656         ERR("Cannot load mscorlib\n");
657         return E_FAIL;
658     }
659
660     image = This->mono->mono_assembly_get_image(assembly);
661     if (!image)
662     {
663         ERR("Couldn't get assembly image\n");
664         return E_FAIL;
665     }
666
667     klass = This->mono->mono_class_from_name(image, "System.Runtime.InteropServices", "Marshal");
668     if (!klass)
669     {
670         ERR("Couldn't get class from image\n");
671         return E_FAIL;
672     }
673
674     method = This->mono->mono_class_get_method_from_name(klass, "GetIUnknownForObject", 1);
675     if (!method)
676     {
677         ERR("Couldn't get method from class\n");
678         return E_FAIL;
679     }
680
681     args[0] = obj;
682     args[1] = NULL;
683     result = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
684     if (!result)
685     {
686         ERR("Couldn't get result pointer\n");
687         return E_FAIL;
688     }
689
690     *ppUnk = *(IUnknown**)This->mono->mono_object_unbox(result);
691     if (!*ppUnk)
692     {
693         ERR("GetIUnknownForObject returned 0\n");
694         return E_FAIL;
695     }
696
697     return S_OK;
698 }
699
700 static void get_utf8_args(int *argc, char ***argv)
701 {
702     WCHAR **argvw;
703     int size=0, i;
704     char *current_arg;
705
706     argvw = CommandLineToArgvW(GetCommandLineW(), argc);
707
708     for (i=0; i<*argc; i++)
709     {
710         size += sizeof(char*);
711         size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
712     }
713     size += sizeof(char*);
714
715     *argv = HeapAlloc(GetProcessHeap(), 0, size);
716     current_arg = (char*)(*argv + *argc + 1);
717
718     for (i=0; i<*argc; i++)
719     {
720         (*argv)[i] = current_arg;
721         current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
722     }
723
724     (*argv)[*argc] = NULL;
725
726     HeapFree(GetProcessHeap(), 0, argvw);
727 }
728
729 __int32 WINAPI _CorExeMain(void)
730 {
731     int exit_code;
732     int argc;
733     char **argv;
734     MonoDomain *domain;
735     MonoAssembly *assembly;
736     WCHAR filename[MAX_PATH];
737     char *filenameA;
738     ICLRRuntimeInfo *info;
739     RuntimeHost *host;
740     HRESULT hr;
741     int i;
742
743     get_utf8_args(&argc, &argv);
744
745     GetModuleFileNameW(NULL, filename, MAX_PATH);
746
747     TRACE("%s", debugstr_w(filename));
748     for (i=0; i<argc; i++)
749         TRACE(" %s", debugstr_a(argv[i]));
750     TRACE("\n");
751
752     filenameA = WtoA(filename);
753     if (!filenameA)
754         return -1;
755
756     hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
757
758     if (SUCCEEDED(hr))
759     {
760         hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
761
762         if (SUCCEEDED(hr))
763             hr = RuntimeHost_GetDefaultDomain(host, &domain);
764
765         if (SUCCEEDED(hr))
766         {
767             assembly = host->mono->mono_domain_assembly_open(domain, filenameA);
768
769             exit_code = host->mono->mono_jit_exec(domain, assembly, argc, argv);
770
771             RuntimeHost_DeleteDomain(host, domain);
772         }
773         else
774             exit_code = -1;
775
776         ICLRRuntimeInfo_Release(info);
777     }
778     else
779         exit_code = -1;
780
781     HeapFree(GetProcessHeap(), 0, argv);
782
783     unload_all_runtimes();
784
785     return exit_code;
786 }
787
788 HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version,
789     loaded_mono *loaded_mono, RuntimeHost** result)
790 {
791     RuntimeHost *This;
792
793     This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
794     if ( !This )
795         return E_OUTOFMEMORY;
796
797     This->lpVtbl = &corruntimehost_vtbl;
798     This->lpCLRHostVtbl = &CLRHostVtbl;
799     This->ref = 1;
800     This->version = runtime_version;
801     This->mono = loaded_mono;
802     list_init(&This->domains);
803     This->default_domain = NULL;
804     InitializeCriticalSection(&This->lock);
805     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
806
807     *result = This;
808
809     return S_OK;
810 }
811
812 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
813 {
814     IUnknown *unk;
815     HRESULT hr;
816
817     if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
818     {
819         unk = (IUnknown*)&This->lpVtbl;
820         IUnknown_AddRef(unk);
821     }
822     else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
823     {
824         unk = (IUnknown*)&This->lpCLRHostVtbl;
825         IUnknown_AddRef(unk);
826     }
827     else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
828              IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
829     {
830         hr = MetaDataDispenser_CreateInstance(&unk);
831         if (FAILED(hr))
832             return hr;
833     }
834     else
835         unk = NULL;
836
837     if (unk)
838     {
839         hr = IUnknown_QueryInterface(unk, riid, ppv);
840
841         IUnknown_Release(unk);
842
843         return hr;
844     }
845     else
846         FIXME("not implemented for class %s\n", debugstr_guid(clsid));
847
848     return CLASS_E_CLASSNOTAVAILABLE;
849 }
850
851 HRESULT RuntimeHost_Destroy(RuntimeHost *This)
852 {
853     struct DomainEntry *cursor, *cursor2;
854
855     This->lock.DebugInfo->Spare[0] = 0;
856     DeleteCriticalSection(&This->lock);
857
858     LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->domains, struct DomainEntry, entry)
859     {
860         list_remove(&cursor->entry);
861         HeapFree(GetProcessHeap(), 0, cursor);
862     }
863
864     HeapFree( GetProcessHeap(), 0, This );
865     return S_OK;
866 }