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