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