gdi32: Allow a driver to implement SelectBitmap but not CreateBitmap.
[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 static void FixupVTable(HMODULE hmodule)
807 {
808     ASSEMBLY *assembly;
809     HRESULT hr;
810     VTableFixup *vtable_fixups;
811     ULONG vtable_fixup_count;
812
813     hr = assembly_from_hmodule(&assembly, hmodule);
814     if (SUCCEEDED(hr))
815     {
816         hr = assembly_get_vtable_fixups(assembly, &vtable_fixups, &vtable_fixup_count);
817         if (vtable_fixup_count)
818             FIXME("vtable fixups are not implemented; expect a crash\n");
819
820         assembly_release(assembly);
821     }
822     else
823         ERR("failed to read CLR headers, hr=%x\n", hr);
824 }
825
826 __int32 WINAPI _CorExeMain(void)
827 {
828     int exit_code;
829     int argc;
830     char **argv;
831     MonoDomain *domain;
832     MonoImage *image;
833     MonoImageOpenStatus status;
834     MonoAssembly *assembly=NULL;
835     WCHAR filename[MAX_PATH];
836     char *filenameA;
837     ICLRRuntimeInfo *info;
838     RuntimeHost *host;
839     HRESULT hr;
840     int i;
841
842     get_utf8_args(&argc, &argv);
843
844     GetModuleFileNameW(NULL, filename, MAX_PATH);
845
846     TRACE("%s", debugstr_w(filename));
847     for (i=0; i<argc; i++)
848         TRACE(" %s", debugstr_a(argv[i]));
849     TRACE("\n");
850
851     filenameA = WtoA(filename);
852     if (!filenameA)
853         return -1;
854
855     FixupVTable(GetModuleHandleW(NULL));
856
857     hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
858
859     if (SUCCEEDED(hr))
860     {
861         hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
862
863         if (SUCCEEDED(hr))
864             hr = RuntimeHost_GetDefaultDomain(host, &domain);
865
866         if (SUCCEEDED(hr))
867         {
868             image = host->mono->mono_image_open_from_module_handle(GetModuleHandleW(NULL),
869                 filenameA, 1, &status);
870
871             if (image)
872                 assembly = host->mono->mono_assembly_load_from(image, filenameA, &status);
873
874             if (assembly)
875             {
876                 exit_code = host->mono->mono_jit_exec(domain, assembly, argc, argv);
877             }
878             else
879             {
880                 ERR("couldn't load %s, status=%d\n", debugstr_w(filename), status);
881                 exit_code = -1;
882             }
883
884             RuntimeHost_DeleteDomain(host, domain);
885         }
886         else
887             exit_code = -1;
888
889         ICLRRuntimeInfo_Release(info);
890     }
891     else
892         exit_code = -1;
893
894     HeapFree(GetProcessHeap(), 0, argv);
895
896     unload_all_runtimes();
897
898     return exit_code;
899 }
900
901 BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
902 {
903     TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
904
905     switch (fdwReason)
906     {
907     case DLL_PROCESS_ATTACH:
908         DisableThreadLibraryCalls(hinstDLL);
909         FixupVTable(hinstDLL);
910         break;
911     case DLL_PROCESS_DETACH:
912         break;
913     }
914     return TRUE;
915 }
916
917 HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version,
918     loaded_mono *loaded_mono, RuntimeHost** result)
919 {
920     RuntimeHost *This;
921
922     This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
923     if ( !This )
924         return E_OUTOFMEMORY;
925
926     This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
927     This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
928
929     This->ref = 1;
930     This->version = runtime_version;
931     This->mono = loaded_mono;
932     list_init(&This->domains);
933     This->default_domain = NULL;
934     InitializeCriticalSection(&This->lock);
935     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
936
937     *result = This;
938
939     return S_OK;
940 }
941
942 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
943 {
944     IUnknown *unk;
945     HRESULT hr;
946
947     if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
948     {
949         unk = (IUnknown*)&This->ICorRuntimeHost_iface;
950         IUnknown_AddRef(unk);
951     }
952     else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
953     {
954         unk = (IUnknown*)&This->ICLRRuntimeHost_iface;
955         IUnknown_AddRef(unk);
956     }
957     else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
958              IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
959     {
960         hr = MetaDataDispenser_CreateInstance(&unk);
961         if (FAILED(hr))
962             return hr;
963     }
964     else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
965     {
966         hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
967         if (FAILED(hr))
968             return hr;
969     }
970     else
971         unk = NULL;
972
973     if (unk)
974     {
975         hr = IUnknown_QueryInterface(unk, riid, ppv);
976
977         IUnknown_Release(unk);
978
979         return hr;
980     }
981     else
982         FIXME("not implemented for class %s\n", debugstr_guid(clsid));
983
984     return CLASS_E_CLASSNOTAVAILABLE;
985 }
986
987 HRESULT RuntimeHost_Destroy(RuntimeHost *This)
988 {
989     struct DomainEntry *cursor, *cursor2;
990
991     This->lock.DebugInfo->Spare[0] = 0;
992     DeleteCriticalSection(&This->lock);
993
994     LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->domains, struct DomainEntry, entry)
995     {
996         list_remove(&cursor->entry);
997         HeapFree(GetProcessHeap(), 0, cursor);
998     }
999
1000     HeapFree( GetProcessHeap(), 0, This );
1001     return S_OK;
1002 }
1003
1004 #define CHARS_IN_GUID 39
1005 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
1006
1007 HRESULT create_monodata(REFIID riid, LPVOID *ppObj )
1008 {
1009     static const WCHAR wszCodebase[] = {'C','o','d','e','B','a','s','e',0};
1010     static const WCHAR wszClass[] = {'C','l','a','s','s',0};
1011     static const WCHAR wszFileSlash[] = {'f','i','l','e',':','/','/','/',0};
1012     static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1013     static const WCHAR wszInprocServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1014     WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) + ARRAYSIZE(wszInprocServer32) - 1];
1015     MonoDomain *domain;
1016     MonoAssembly *assembly;
1017     ICLRRuntimeInfo *info;
1018     RuntimeHost *host;
1019     HRESULT hr;
1020     HKEY key;
1021     LONG res;
1022     int offset = 0;
1023     WCHAR codebase[MAX_PATH + 8];
1024     WCHAR classname[350];
1025     WCHAR filename[MAX_PATH];
1026
1027     DWORD dwBufLen = 350;
1028
1029     lstrcpyW(path, wszCLSIDSlash);
1030     StringFromGUID2(riid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
1031     lstrcatW(path, wszInprocServer32);
1032
1033     TRACE("Registry key: %s\n", debugstr_w(path));
1034
1035     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key);
1036     if (res == ERROR_FILE_NOT_FOUND)
1037         return CLASS_E_CLASSNOTAVAILABLE;
1038
1039     res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen);
1040     if(res != ERROR_SUCCESS)
1041     {
1042         WARN("Class value cannot be found.\n");
1043         hr = CLASS_E_CLASSNOTAVAILABLE;
1044         goto cleanup;
1045     }
1046
1047     TRACE("classname (%s)\n", debugstr_w(classname));
1048
1049     dwBufLen = MAX_PATH + 8;
1050     res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen);
1051     if(res != ERROR_SUCCESS)
1052     {
1053         WARN("CodeBase value cannot be found.\n");
1054         hr = CLASS_E_CLASSNOTAVAILABLE;
1055         goto cleanup;
1056     }
1057
1058     /* Strip file:/// */
1059     if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0)
1060         offset = strlenW(wszFileSlash);
1061
1062     strcpyW(filename, codebase + offset);
1063
1064     TRACE("codebase (%s)\n", debugstr_w(filename));
1065
1066     *ppObj = NULL;
1067
1068
1069     hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1070     if (SUCCEEDED(hr))
1071     {
1072         hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1073
1074         if (SUCCEEDED(hr))
1075             hr = RuntimeHost_GetDefaultDomain(host, &domain);
1076
1077         if (SUCCEEDED(hr))
1078         {
1079             MonoImage *image;
1080             MonoClass *klass;
1081             MonoObject *result;
1082             IUnknown *unk = NULL;
1083             char *filenameA, *ns;
1084             char *classA;
1085
1086             hr = CLASS_E_CLASSNOTAVAILABLE;
1087
1088             host->mono->mono_thread_attach(domain);
1089
1090             filenameA = WtoA(filename);
1091             assembly = host->mono->mono_domain_assembly_open(domain, filenameA);
1092             HeapFree(GetProcessHeap(), 0, filenameA);
1093             if (!assembly)
1094             {
1095                 ERR("Cannot open assembly %s\n", filenameA);
1096                 goto cleanup;
1097             }
1098
1099             image = host->mono->mono_assembly_get_image(assembly);
1100             if (!image)
1101             {
1102                 ERR("Couldn't get assembly image\n");
1103                 goto cleanup;
1104             }
1105
1106             classA = WtoA(classname);
1107             ns = strrchr(classA, '.');
1108             *ns = '\0';
1109
1110             klass = host->mono->mono_class_from_name(image, classA, ns+1);
1111             HeapFree(GetProcessHeap(), 0, classA);
1112             if (!klass)
1113             {
1114                 ERR("Couldn't get class from image\n");
1115                 goto cleanup;
1116             }
1117
1118             /*
1119              * Use the default constructor for the .NET class.
1120              */
1121             result = host->mono->mono_object_new(domain, klass);
1122             host->mono->mono_runtime_object_init(result);
1123
1124             hr = RuntimeHost_GetIUnknownForObject(host, result, &unk);
1125             if (SUCCEEDED(hr))
1126             {
1127                 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj);
1128
1129                 IUnknown_Release(unk);
1130             }
1131             else
1132                 hr = CLASS_E_CLASSNOTAVAILABLE;
1133         }
1134         else
1135             hr = CLASS_E_CLASSNOTAVAILABLE;
1136     }
1137     else
1138         hr = CLASS_E_CLASSNOTAVAILABLE;
1139
1140 cleanup:
1141     if(info)
1142         ICLRRuntimeInfo_Release(info);
1143
1144     RegCloseKey(key);
1145
1146     return hr;
1147 }