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