po: Update French translation.
[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 <assert.h>
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "ole2.h"
31 #include "shellapi.h"
32
33 #include "cor.h"
34 #include "mscoree.h"
35 #include "metahost.h"
36 #include "corhdr.h"
37 #include "cordebug.h"
38 #include "wine/list.h"
39 #include "mscoree_private.h"
40
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "wine/list.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
46
47 #include "initguid.h"
48
49 DEFINE_GUID(IID__AppDomain, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13);
50
51 struct DomainEntry
52 {
53     struct list entry;
54     MonoDomain *domain;
55 };
56
57 static HANDLE dll_fixup_heap; /* using a separate heap so we can have execute permission */
58
59 static struct list dll_fixups;
60
61 struct dll_fixup
62 {
63     struct list entry;
64     int done;
65     HMODULE dll;
66     void *thunk_code; /* pointer into dll_fixup_heap */
67     VTableFixup *fixup;
68     void *vtable;
69     void *tokens; /* pointer into process heap */
70 };
71
72 static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, MonoDomain **result)
73 {
74     struct DomainEntry *entry;
75     char *mscorlib_path;
76     HRESULT res=S_OK;
77
78     EnterCriticalSection(&This->lock);
79
80     entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
81     if (!entry)
82     {
83         res = E_OUTOFMEMORY;
84         goto end;
85     }
86
87     mscorlib_path = WtoA(This->version->mscorlib_path);
88     if (!mscorlib_path)
89     {
90         HeapFree(GetProcessHeap(), 0, entry);
91         res = E_OUTOFMEMORY;
92         goto end;
93     }
94
95     entry->domain = This->mono->mono_jit_init(mscorlib_path);
96
97     HeapFree(GetProcessHeap(), 0, mscorlib_path);
98
99     if (!entry->domain)
100     {
101         HeapFree(GetProcessHeap(), 0, entry);
102         res = E_FAIL;
103         goto end;
104     }
105
106     This->mono->is_started = TRUE;
107
108     list_add_tail(&This->domains, &entry->entry);
109
110     *result = entry->domain;
111
112 end:
113     LeaveCriticalSection(&This->lock);
114
115     return res;
116 }
117
118 static HRESULT RuntimeHost_GetDefaultDomain(RuntimeHost *This, MonoDomain **result)
119 {
120     HRESULT res=S_OK;
121
122     EnterCriticalSection(&This->lock);
123
124     if (This->default_domain) goto end;
125
126     res = RuntimeHost_AddDomain(This, &This->default_domain);
127
128 end:
129     *result = This->default_domain;
130
131     LeaveCriticalSection(&This->lock);
132
133     return res;
134 }
135
136 static void RuntimeHost_DeleteDomain(RuntimeHost *This, MonoDomain *domain)
137 {
138     struct DomainEntry *entry;
139
140     EnterCriticalSection(&This->lock);
141
142     LIST_FOR_EACH_ENTRY(entry, &This->domains, struct DomainEntry, entry)
143     {
144         if (entry->domain == domain)
145         {
146             list_remove(&entry->entry);
147             if (This->default_domain == domain)
148                 This->default_domain = NULL;
149             HeapFree(GetProcessHeap(), 0, entry);
150             break;
151         }
152     }
153
154     LeaveCriticalSection(&This->lock);
155 }
156
157 static HRESULT RuntimeHost_GetIUnknownForDomain(RuntimeHost *This, MonoDomain *domain, IUnknown **punk)
158 {
159     HRESULT hr;
160     void *args[1];
161     MonoAssembly *assembly;
162     MonoImage *image;
163     MonoClass *klass;
164     MonoMethod *method;
165     MonoObject *appdomain_object;
166     IUnknown *unk;
167
168     This->mono->mono_thread_attach(domain);
169
170     assembly = This->mono->mono_domain_assembly_open(domain, "mscorlib");
171     if (!assembly)
172     {
173         ERR("Cannot load mscorlib\n");
174         return E_FAIL;
175     }
176
177     image = This->mono->mono_assembly_get_image(assembly);
178     if (!image)
179     {
180         ERR("Couldn't get assembly image\n");
181         return E_FAIL;
182     }
183
184     klass = This->mono->mono_class_from_name(image, "System", "AppDomain");
185     if (!klass)
186     {
187         ERR("Couldn't get class from image\n");
188         return E_FAIL;
189     }
190
191     method = This->mono->mono_class_get_method_from_name(klass, "get_CurrentDomain", 0);
192     if (!method)
193     {
194         ERR("Couldn't get method from class\n");
195         return E_FAIL;
196     }
197
198     args[0] = NULL;
199     appdomain_object = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
200     if (!appdomain_object)
201     {
202         ERR("Couldn't get result pointer\n");
203         return E_FAIL;
204     }
205
206     hr = RuntimeHost_GetIUnknownForObject(This, appdomain_object, &unk);
207
208     if (SUCCEEDED(hr))
209     {
210         hr = IUnknown_QueryInterface(unk, &IID__AppDomain, (void**)punk);
211
212         IUnknown_Release(unk);
213     }
214
215     return hr;
216 }
217
218 static inline RuntimeHost *impl_from_ICLRRuntimeHost( ICLRRuntimeHost *iface )
219 {
220     return CONTAINING_RECORD(iface, RuntimeHost, ICLRRuntimeHost_iface);
221 }
222
223 static inline RuntimeHost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
224 {
225     return CONTAINING_RECORD(iface, RuntimeHost, ICorRuntimeHost_iface);
226 }
227
228 /*** IUnknown methods ***/
229 static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
230         REFIID riid,
231         void **ppvObject)
232 {
233     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
234     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
235
236     if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) ||
237          IsEqualGUID( riid, &IID_IUnknown ) )
238     {
239         *ppvObject = iface;
240     }
241     else
242     {
243         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
244         return E_NOINTERFACE;
245     }
246
247     ICorRuntimeHost_AddRef( iface );
248
249     return S_OK;
250 }
251
252 static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface)
253 {
254     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
255
256     return InterlockedIncrement( &This->ref );
257 }
258
259 static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface)
260 {
261     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
262     ULONG ref;
263
264     ref = InterlockedDecrement( &This->ref );
265
266     return ref;
267 }
268
269 /*** ICorRuntimeHost methods ***/
270 static HRESULT WINAPI corruntimehost_CreateLogicalThreadState(
271                     ICorRuntimeHost* iface)
272 {
273     FIXME("stub %p\n", iface);
274     return E_NOTIMPL;
275 }
276
277 static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState(
278                     ICorRuntimeHost* iface)
279 {
280     FIXME("stub %p\n", iface);
281     return E_NOTIMPL;
282 }
283
284 static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState(
285                     ICorRuntimeHost* iface,
286                     DWORD *fiberCookie)
287 {
288     FIXME("stub %p\n", iface);
289     return E_NOTIMPL;
290 }
291
292 static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState(
293                     ICorRuntimeHost* iface,
294                     DWORD **fiberCookie)
295 {
296     FIXME("stub %p\n", iface);
297     return E_NOTIMPL;
298 }
299
300 static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread(
301                     ICorRuntimeHost* iface,
302                     DWORD *pCount)
303 {
304     FIXME("stub %p\n", iface);
305     return E_NOTIMPL;
306 }
307
308 static HRESULT WINAPI corruntimehost_MapFile(
309     ICorRuntimeHost* iface,
310     HANDLE hFile,
311     HMODULE *mapAddress)
312 {
313     FIXME("stub %p\n", iface);
314     return E_NOTIMPL;
315 }
316
317 static HRESULT WINAPI corruntimehost_GetConfiguration(
318     ICorRuntimeHost* iface,
319     ICorConfiguration **pConfiguration)
320 {
321     FIXME("stub %p\n", iface);
322     return E_NOTIMPL;
323 }
324
325 static HRESULT WINAPI corruntimehost_Start(
326     ICorRuntimeHost* iface)
327 {
328     FIXME("stub %p\n", iface);
329     return S_OK;
330 }
331
332 static HRESULT WINAPI corruntimehost_Stop(
333     ICorRuntimeHost* iface)
334 {
335     FIXME("stub %p\n", iface);
336     return E_NOTIMPL;
337 }
338
339 static HRESULT WINAPI corruntimehost_CreateDomain(
340     ICorRuntimeHost* iface,
341     LPCWSTR friendlyName,
342     IUnknown *identityArray,
343     IUnknown **appDomain)
344 {
345     FIXME("stub %p\n", iface);
346     return E_NOTIMPL;
347 }
348
349 static HRESULT WINAPI corruntimehost_GetDefaultDomain(
350     ICorRuntimeHost* iface,
351     IUnknown **pAppDomain)
352 {
353     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
354     HRESULT hr;
355     MonoDomain *domain;
356
357     TRACE("(%p)\n", iface);
358
359     hr = RuntimeHost_GetDefaultDomain(This, &domain);
360
361     if (SUCCEEDED(hr))
362     {
363         hr = RuntimeHost_GetIUnknownForDomain(This, domain, pAppDomain);
364     }
365
366     return hr;
367 }
368
369 static HRESULT WINAPI corruntimehost_EnumDomains(
370     ICorRuntimeHost* iface,
371     HDOMAINENUM *hEnum)
372 {
373     FIXME("stub %p\n", iface);
374     return E_NOTIMPL;
375 }
376
377 static HRESULT WINAPI corruntimehost_NextDomain(
378     ICorRuntimeHost* iface,
379     HDOMAINENUM hEnum,
380     IUnknown **appDomain)
381 {
382     FIXME("stub %p\n", iface);
383     return E_NOTIMPL;
384 }
385
386 static HRESULT WINAPI corruntimehost_CloseEnum(
387     ICorRuntimeHost* iface,
388     HDOMAINENUM hEnum)
389 {
390     FIXME("stub %p\n", iface);
391     return E_NOTIMPL;
392 }
393
394 static HRESULT WINAPI corruntimehost_CreateDomainEx(
395     ICorRuntimeHost* iface,
396     LPCWSTR friendlyName,
397     IUnknown *setup,
398     IUnknown *evidence,
399     IUnknown **appDomain)
400 {
401     FIXME("stub %p\n", iface);
402     return E_NOTIMPL;
403 }
404
405 static HRESULT WINAPI corruntimehost_CreateDomainSetup(
406     ICorRuntimeHost* iface,
407     IUnknown **appDomainSetup)
408 {
409     FIXME("stub %p\n", iface);
410     return E_NOTIMPL;
411 }
412
413 static HRESULT WINAPI corruntimehost_CreateEvidence(
414     ICorRuntimeHost* iface,
415     IUnknown **evidence)
416 {
417     FIXME("stub %p\n", iface);
418     return E_NOTIMPL;
419 }
420
421 static HRESULT WINAPI corruntimehost_UnloadDomain(
422     ICorRuntimeHost* iface,
423     IUnknown *appDomain)
424 {
425     FIXME("stub %p\n", iface);
426     return E_NOTIMPL;
427 }
428
429 static HRESULT WINAPI corruntimehost_CurrentDomain(
430     ICorRuntimeHost* iface,
431     IUnknown **appDomain)
432 {
433     FIXME("stub %p\n", iface);
434     return E_NOTIMPL;
435 }
436
437 static const struct ICorRuntimeHostVtbl corruntimehost_vtbl =
438 {
439     corruntimehost_QueryInterface,
440     corruntimehost_AddRef,
441     corruntimehost_Release,
442     corruntimehost_CreateLogicalThreadState,
443     corruntimehost_DeleteLogicalThreadState,
444     corruntimehost_SwitchInLogicalThreadState,
445     corruntimehost_SwitchOutLogicalThreadState,
446     corruntimehost_LocksHeldByLogicalThread,
447     corruntimehost_MapFile,
448     corruntimehost_GetConfiguration,
449     corruntimehost_Start,
450     corruntimehost_Stop,
451     corruntimehost_CreateDomain,
452     corruntimehost_GetDefaultDomain,
453     corruntimehost_EnumDomains,
454     corruntimehost_NextDomain,
455     corruntimehost_CloseEnum,
456     corruntimehost_CreateDomainEx,
457     corruntimehost_CreateDomainSetup,
458     corruntimehost_CreateEvidence,
459     corruntimehost_UnloadDomain,
460     corruntimehost_CurrentDomain
461 };
462
463 static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface,
464         REFIID riid,
465         void **ppvObject)
466 {
467     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
468     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
469
470     if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) ||
471          IsEqualGUID( riid, &IID_IUnknown ) )
472     {
473         *ppvObject = iface;
474     }
475     else
476     {
477         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
478         return E_NOINTERFACE;
479     }
480
481     ICLRRuntimeHost_AddRef( iface );
482
483     return S_OK;
484 }
485
486 static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface)
487 {
488     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
489     return ICorRuntimeHost_AddRef(&This->ICorRuntimeHost_iface);
490 }
491
492 static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface)
493 {
494     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
495     return ICorRuntimeHost_Release(&This->ICorRuntimeHost_iface);
496 }
497
498 static HRESULT WINAPI CLRRuntimeHost_Start(ICLRRuntimeHost* iface)
499 {
500     FIXME("(%p)\n", iface);
501     return E_NOTIMPL;
502 }
503
504 static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
505 {
506     FIXME("(%p)\n", iface);
507     return E_NOTIMPL;
508 }
509
510 static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
511     IHostControl *pHostControl)
512 {
513     FIXME("(%p,%p)\n", iface, pHostControl);
514     return E_NOTIMPL;
515 }
516
517 static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
518     ICLRControl **pCLRControl)
519 {
520     FIXME("(%p,%p)\n", iface, pCLRControl);
521     return E_NOTIMPL;
522 }
523
524 static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
525     DWORD dwAppDomainId, BOOL fWaitUntilDone)
526 {
527     FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
528     return E_NOTIMPL;
529 }
530
531 static HRESULT WINAPI CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost* iface,
532     DWORD dwAppDomainId, FExecuteInAppDomainCallback pCallback, void *cookie)
533 {
534     FIXME("(%p,%u,%p,%p)\n", iface, dwAppDomainId, pCallback, cookie);
535     return E_NOTIMPL;
536 }
537
538 static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
539     DWORD *pdwAppDomainId)
540 {
541     FIXME("(%p,%p)\n", iface, pdwAppDomainId);
542     return E_NOTIMPL;
543 }
544
545 static HRESULT WINAPI CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost* iface,
546     LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR *ppwzManifestPaths,
547     DWORD dwActivationData, LPCWSTR *ppwzActivationData, int *pReturnValue)
548 {
549     FIXME("(%p,%s,%u,%u)\n", iface, debugstr_w(pwzAppFullName), dwManifestPaths, dwActivationData);
550     return E_NOTIMPL;
551 }
552
553 static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* iface,
554     LPCWSTR pwzAssemblyPath, LPCWSTR pwzTypeName, LPCWSTR pwzMethodName,
555     LPCWSTR pwzArgument, DWORD *pReturnValue)
556 {
557     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
558     HRESULT hr;
559     MonoDomain *domain;
560     MonoAssembly *assembly;
561     MonoImage *image;
562     MonoClass *klass;
563     MonoMethod *method;
564     MonoObject *result;
565     MonoString *str;
566     void *args[2];
567     char *filenameA = NULL, *classA = NULL, *methodA = NULL;
568     char *argsA = NULL, *ns;
569
570     TRACE("(%p,%s,%s,%s,%s)\n", iface, debugstr_w(pwzAssemblyPath),
571         debugstr_w(pwzTypeName), debugstr_w(pwzMethodName), debugstr_w(pwzArgument));
572
573     hr = RuntimeHost_GetDefaultDomain(This, &domain);
574     if(hr != S_OK)
575     {
576         ERR("Couldn't get Default Domain\n");
577         return hr;
578     }
579
580     hr = E_FAIL;
581
582     This->mono->mono_thread_attach(domain);
583
584     filenameA = WtoA(pwzAssemblyPath);
585     assembly = This->mono->mono_domain_assembly_open(domain, filenameA);
586     if (!assembly)
587     {
588         ERR("Cannot open assembly %s\n", filenameA);
589         goto cleanup;
590     }
591
592     image = This->mono->mono_assembly_get_image(assembly);
593     if (!image)
594     {
595         ERR("Couldn't get assembly image\n");
596         goto cleanup;
597     }
598
599     classA = WtoA(pwzTypeName);
600     ns = strrchr(classA, '.');
601     *ns = '\0';
602     klass = This->mono->mono_class_from_name(image, classA, ns+1);
603     if (!klass)
604     {
605         ERR("Couldn't get class from image\n");
606         goto cleanup;
607     }
608
609     methodA = WtoA(pwzMethodName);
610     method = This->mono->mono_class_get_method_from_name(klass, methodA, 1);
611     if (!method)
612     {
613         ERR("Couldn't get method from class\n");
614         goto cleanup;
615     }
616
617     /* The .NET function we are calling has the following declaration
618      *   public static int functionName(String param)
619      */
620     argsA = WtoA(pwzArgument);
621     str = This->mono->mono_string_new(domain, argsA);
622     args[0] = str;
623     args[1] = NULL;
624     result = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
625     if (!result)
626         ERR("Couldn't get result pointer\n");
627     else
628     {
629         *pReturnValue = *(DWORD*)This->mono->mono_object_unbox(result);
630         hr = S_OK;
631     }
632
633 cleanup:
634     HeapFree(GetProcessHeap(), 0, filenameA);
635     HeapFree(GetProcessHeap(), 0, classA);
636     HeapFree(GetProcessHeap(), 0, argsA);
637     HeapFree(GetProcessHeap(), 0, methodA);
638
639     return hr;
640 }
641
642 static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
643 {
644     CLRRuntimeHost_QueryInterface,
645     CLRRuntimeHost_AddRef,
646     CLRRuntimeHost_Release,
647     CLRRuntimeHost_Start,
648     CLRRuntimeHost_Stop,
649     CLRRuntimeHost_SetHostControl,
650     CLRRuntimeHost_GetCLRControl,
651     CLRRuntimeHost_UnloadAppDomain,
652     CLRRuntimeHost_ExecuteInAppDomain,
653     CLRRuntimeHost_GetCurrentAppDomainId,
654     CLRRuntimeHost_ExecuteApplication,
655     CLRRuntimeHost_ExecuteInDefaultAppDomain
656 };
657
658 /* Create an instance of a type given its name, by calling its constructor with
659  * no arguments. Note that result MUST be in the stack, or the garbage
660  * collector may free it prematurely. */
661 HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
662     MonoDomain *domain, MonoObject **result)
663 {
664     HRESULT hr=S_OK;
665     char *nameA=NULL;
666     MonoType *type;
667     MonoClass *klass;
668     MonoObject *obj;
669
670     if (!domain)
671         hr = RuntimeHost_GetDefaultDomain(This, &domain);
672
673     if (SUCCEEDED(hr))
674     {
675         nameA = WtoA(name);
676         if (!nameA)
677             hr = E_OUTOFMEMORY;
678     }
679
680     if (SUCCEEDED(hr))
681     {
682         This->mono->mono_thread_attach(domain);
683
684         type = This->mono->mono_reflection_type_from_name(nameA, NULL);
685         if (!type)
686         {
687             ERR("Cannot find type %s\n", debugstr_w(name));
688             hr = E_FAIL;
689         }
690     }
691
692     if (SUCCEEDED(hr))
693     {
694         klass = This->mono->mono_class_from_mono_type(type);
695         if (!klass)
696         {
697             ERR("Cannot convert type %s to a class\n", debugstr_w(name));
698             hr = E_FAIL;
699         }
700     }
701
702     if (SUCCEEDED(hr))
703     {
704         obj = This->mono->mono_object_new(domain, klass);
705         if (!obj)
706         {
707             ERR("Cannot allocate object of type %s\n", debugstr_w(name));
708             hr = E_FAIL;
709         }
710     }
711
712     if (SUCCEEDED(hr))
713     {
714         /* FIXME: Detect exceptions from the constructor? */
715         This->mono->mono_runtime_object_init(obj);
716         *result = obj;
717     }
718
719     HeapFree(GetProcessHeap(), 0, nameA);
720
721     return hr;
722 }
723
724 /* Get an IUnknown pointer for a Mono object.
725  *
726  * This is just a "light" wrapper around
727  * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
728  *
729  * NOTE: The IUnknown* is created with a reference to the object.
730  * Until they have a reference, objects must be in the stack to prevent the
731  * garbage collector from freeing them.
732  *
733  * mono_thread_attach must have already been called for this thread. */
734 HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj,
735     IUnknown **ppUnk)
736 {
737     MonoDomain *domain;
738     MonoAssembly *assembly;
739     MonoImage *image;
740     MonoClass *klass;
741     MonoMethod *method;
742     MonoObject *result;
743     void *args[2];
744
745     domain = This->mono->mono_object_get_domain(obj);
746
747     assembly = This->mono->mono_domain_assembly_open(domain, "mscorlib");
748     if (!assembly)
749     {
750         ERR("Cannot load mscorlib\n");
751         return E_FAIL;
752     }
753
754     image = This->mono->mono_assembly_get_image(assembly);
755     if (!image)
756     {
757         ERR("Couldn't get assembly image\n");
758         return E_FAIL;
759     }
760
761     klass = This->mono->mono_class_from_name(image, "System.Runtime.InteropServices", "Marshal");
762     if (!klass)
763     {
764         ERR("Couldn't get class from image\n");
765         return E_FAIL;
766     }
767
768     method = This->mono->mono_class_get_method_from_name(klass, "GetIUnknownForObject", 1);
769     if (!method)
770     {
771         ERR("Couldn't get method from class\n");
772         return E_FAIL;
773     }
774
775     args[0] = obj;
776     args[1] = NULL;
777     result = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
778     if (!result)
779     {
780         ERR("Couldn't get result pointer\n");
781         return E_FAIL;
782     }
783
784     *ppUnk = *(IUnknown**)This->mono->mono_object_unbox(result);
785     if (!*ppUnk)
786     {
787         ERR("GetIUnknownForObject returned 0\n");
788         return E_FAIL;
789     }
790
791     return S_OK;
792 }
793
794 static void get_utf8_args(int *argc, char ***argv)
795 {
796     WCHAR **argvw;
797     int size=0, i;
798     char *current_arg;
799
800     argvw = CommandLineToArgvW(GetCommandLineW(), argc);
801
802     for (i=0; i<*argc; i++)
803     {
804         size += sizeof(char*);
805         size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
806     }
807     size += sizeof(char*);
808
809     *argv = HeapAlloc(GetProcessHeap(), 0, size);
810     current_arg = (char*)(*argv + *argc + 1);
811
812     for (i=0; i<*argc; i++)
813     {
814         (*argv)[i] = current_arg;
815         current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
816     }
817
818     (*argv)[*argc] = NULL;
819
820     HeapFree(GetProcessHeap(), 0, argvw);
821 }
822
823 #if __i386__
824
825 # define CAN_FIXUP_VTABLE 1
826
827 #include "pshpack1.h"
828
829 struct vtable_fixup_thunk
830 {
831     /* sub $0x4,%esp */
832     BYTE i1[3];
833     /* mov fixup,(%esp) */
834     BYTE i2[3];
835     struct dll_fixup *fixup;
836     /* mov function,%eax */
837     BYTE i3;
838     void (CDECL *function)(struct dll_fixup *);
839     /* call *%eax */
840     BYTE i4[2];
841     /* pop %eax */
842     BYTE i5;
843     /* jmp *vtable_entry */
844     BYTE i6[2];
845     void *vtable_entry;
846 };
847
848 static const struct vtable_fixup_thunk thunk_template = {
849     {0x83,0xec,0x04},
850     {0xc7,0x04,0x24},
851     NULL,
852     0xb8,
853     NULL,
854     {0xff,0xd0},
855     0x58,
856     {0xff,0x25},
857     NULL
858 };
859
860 #include "poppack.h"
861
862 #else /* !defined(__i386__) */
863
864 # define CAN_FIXUP_VTABLE 0
865
866 struct vtable_fixup_thunk
867 {
868     struct dll_fixup *fixup;
869     void (CDECL *function)(struct dll_fixup *fixup);
870     void *vtable_entry;
871 };
872
873 static const struct vtable_fixup_thunk thunk_template = {0};
874
875 #endif
876
877 static void CDECL ReallyFixupVTable(struct dll_fixup *fixup)
878 {
879     HRESULT hr=S_OK;
880     WCHAR filename[MAX_PATH];
881     ICLRRuntimeInfo *info=NULL;
882     RuntimeHost *host;
883     char *filenameA;
884     MonoImage *image=NULL;
885     MonoAssembly *assembly=NULL;
886     MonoImageOpenStatus status=0;
887     MonoDomain *domain;
888
889     if (fixup->done) return;
890
891     /* It's possible we'll have two threads doing this at once. This is
892      * considered preferable to the potential deadlock if we use a mutex. */
893
894     GetModuleFileNameW(fixup->dll, filename, MAX_PATH);
895
896     TRACE("%p,%p,%s\n", fixup, fixup->dll, debugstr_w(filename));
897
898     filenameA = WtoA(filename);
899     if (!filenameA)
900         hr = E_OUTOFMEMORY;
901
902     if (SUCCEEDED(hr))
903         hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
904
905     if (SUCCEEDED(hr))
906         hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
907
908     if (SUCCEEDED(hr))
909         hr = RuntimeHost_GetDefaultDomain(host, &domain);
910
911     if (SUCCEEDED(hr))
912     {
913         host->mono->mono_thread_attach(domain);
914
915         image = host->mono->mono_image_open_from_module_handle(fixup->dll,
916             filenameA, 1, &status);
917     }
918
919     if (image)
920         assembly = host->mono->mono_assembly_load_from(image, filenameA, &status);
921
922     if (assembly)
923     {
924         int i;
925
926         /* Mono needs an image that belongs to an assembly. */
927         image = host->mono->mono_assembly_get_image(assembly);
928
929         if (fixup->fixup->type & COR_VTABLE_32BIT)
930         {
931             DWORD *vtable = fixup->vtable;
932             DWORD *tokens = fixup->tokens;
933             for (i=0; i<fixup->fixup->count; i++)
934             {
935                 TRACE("%x\n", tokens[i]);
936                 vtable[i] = PtrToUint(host->mono->mono_marshal_get_vtfixup_ftnptr(
937                     image, tokens[i], fixup->fixup->type));
938             }
939         }
940
941         fixup->done = 1;
942     }
943
944     if (info != NULL)
945         ICLRRuntimeHost_Release(info);
946
947     HeapFree(GetProcessHeap(), 0, filenameA);
948
949     if (!fixup->done)
950     {
951         ERR("unable to fixup vtable, hr=%x, status=%d\n", hr, status);
952         /* If we returned now, we'd get an infinite loop. */
953         assert(0);
954     }
955 }
956
957 static void FixupVTableEntry(HMODULE hmodule, VTableFixup *vtable_fixup)
958 {
959     /* We can't actually generate code for the functions without loading mono,
960      * and loading mono inside DllMain is a terrible idea. So we make thunks
961      * that call ReallyFixupVTable, which will load the runtime and fill in the
962      * vtable, then do an indirect jump using the (now filled in) vtable. Note
963      * that we have to keep the thunks around forever, as one of them may get
964      * called while we're filling in the table, and we can never be sure all
965      * threads are clear. */
966     struct dll_fixup *fixup;
967
968     fixup = HeapAlloc(GetProcessHeap(), 0, sizeof(*fixup));
969
970     fixup->dll = hmodule;
971     fixup->thunk_code = HeapAlloc(dll_fixup_heap, 0, sizeof(struct vtable_fixup_thunk) * vtable_fixup->count);
972     fixup->fixup = vtable_fixup;
973     fixup->vtable = (BYTE*)hmodule + vtable_fixup->rva;
974     fixup->done = 0;
975
976     if (vtable_fixup->type & COR_VTABLE_32BIT)
977     {
978         DWORD *vtable = fixup->vtable;
979         DWORD *tokens;
980         int i;
981         struct vtable_fixup_thunk *thunks = fixup->thunk_code;
982
983         if (sizeof(void*) > 4)
984             ERR("32-bit fixup in 64-bit mode; broken image?\n");
985
986         tokens = fixup->tokens = HeapAlloc(GetProcessHeap(), 0, sizeof(*tokens) * vtable_fixup->count);
987         memcpy(tokens, vtable, sizeof(*tokens) * vtable_fixup->count);
988         for (i=0; i<vtable_fixup->count; i++)
989         {
990             memcpy(&thunks[i], &thunk_template, sizeof(thunk_template));
991             thunks[i].fixup = fixup;
992             thunks[i].function = ReallyFixupVTable;
993             thunks[i].vtable_entry = &vtable[i];
994             vtable[i] = PtrToUint(&thunks[i]);
995         }
996     }
997     else
998     {
999         ERR("unsupported vtable fixup flags %x\n", vtable_fixup->type);
1000         HeapFree(dll_fixup_heap, 0, fixup->thunk_code);
1001         HeapFree(GetProcessHeap(), 0, fixup);
1002         return;
1003     }
1004
1005     list_add_tail(&dll_fixups, &fixup->entry);
1006 }
1007
1008 static void FixupVTable(HMODULE hmodule)
1009 {
1010     ASSEMBLY *assembly;
1011     HRESULT hr;
1012     VTableFixup *vtable_fixups;
1013     ULONG vtable_fixup_count, i;
1014
1015     hr = assembly_from_hmodule(&assembly, hmodule);
1016     if (SUCCEEDED(hr))
1017     {
1018         hr = assembly_get_vtable_fixups(assembly, &vtable_fixups, &vtable_fixup_count);
1019         if (CAN_FIXUP_VTABLE)
1020             for (i=0; i<vtable_fixup_count; i++)
1021                 FixupVTableEntry(hmodule, &vtable_fixups[i]);
1022         else if (vtable_fixup_count)
1023             FIXME("cannot fixup vtable; expect a crash\n");
1024
1025         assembly_release(assembly);
1026     }
1027     else
1028         ERR("failed to read CLR headers, hr=%x\n", hr);
1029 }
1030
1031 __int32 WINAPI _CorExeMain(void)
1032 {
1033     int exit_code;
1034     int argc;
1035     char **argv;
1036     MonoDomain *domain;
1037     MonoImage *image;
1038     MonoImageOpenStatus status;
1039     MonoAssembly *assembly=NULL;
1040     WCHAR filename[MAX_PATH];
1041     char *filenameA;
1042     ICLRRuntimeInfo *info;
1043     RuntimeHost *host;
1044     HRESULT hr;
1045     int i;
1046
1047     get_utf8_args(&argc, &argv);
1048
1049     GetModuleFileNameW(NULL, filename, MAX_PATH);
1050
1051     TRACE("%s", debugstr_w(filename));
1052     for (i=0; i<argc; i++)
1053         TRACE(" %s", debugstr_a(argv[i]));
1054     TRACE("\n");
1055
1056     filenameA = WtoA(filename);
1057     if (!filenameA)
1058         return -1;
1059
1060     FixupVTable(GetModuleHandleW(NULL));
1061
1062     hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1063
1064     if (SUCCEEDED(hr))
1065     {
1066         hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1067
1068         if (SUCCEEDED(hr))
1069             hr = RuntimeHost_GetDefaultDomain(host, &domain);
1070
1071         if (SUCCEEDED(hr))
1072         {
1073             image = host->mono->mono_image_open_from_module_handle(GetModuleHandleW(NULL),
1074                 filenameA, 1, &status);
1075
1076             if (image)
1077                 assembly = host->mono->mono_assembly_load_from(image, filenameA, &status);
1078
1079             if (assembly)
1080             {
1081                 exit_code = host->mono->mono_jit_exec(domain, assembly, argc, argv);
1082             }
1083             else
1084             {
1085                 ERR("couldn't load %s, status=%d\n", debugstr_w(filename), status);
1086                 exit_code = -1;
1087             }
1088
1089             RuntimeHost_DeleteDomain(host, domain);
1090         }
1091         else
1092             exit_code = -1;
1093
1094         ICLRRuntimeInfo_Release(info);
1095     }
1096     else
1097         exit_code = -1;
1098
1099     HeapFree(GetProcessHeap(), 0, argv);
1100
1101     unload_all_runtimes();
1102
1103     return exit_code;
1104 }
1105
1106 BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1107 {
1108     TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1109
1110     switch (fdwReason)
1111     {
1112     case DLL_PROCESS_ATTACH:
1113         DisableThreadLibraryCalls(hinstDLL);
1114         FixupVTable(hinstDLL);
1115         break;
1116     case DLL_PROCESS_DETACH:
1117         /* FIXME: clean up the vtables */
1118         break;
1119     }
1120     return TRUE;
1121 }
1122
1123 /* called from DLL_PROCESS_ATTACH */
1124 void runtimehost_init(void)
1125 {
1126     dll_fixup_heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
1127     list_init(&dll_fixups);
1128 }
1129
1130 /* called from DLL_PROCESS_DETACH */
1131 void runtimehost_uninit(void)
1132 {
1133     struct dll_fixup *fixup, *fixup2;
1134
1135     HeapDestroy(dll_fixup_heap);
1136     LIST_FOR_EACH_ENTRY_SAFE(fixup, fixup2, &dll_fixups, struct dll_fixup, entry)
1137     {
1138         HeapFree(GetProcessHeap(), 0, fixup->tokens);
1139         HeapFree(GetProcessHeap(), 0, fixup);
1140     }
1141 }
1142
1143 HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version,
1144     loaded_mono *loaded_mono, RuntimeHost** result)
1145 {
1146     RuntimeHost *This;
1147
1148     This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1149     if ( !This )
1150         return E_OUTOFMEMORY;
1151
1152     This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
1153     This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
1154
1155     This->ref = 1;
1156     This->version = runtime_version;
1157     This->mono = loaded_mono;
1158     list_init(&This->domains);
1159     This->default_domain = NULL;
1160     InitializeCriticalSection(&This->lock);
1161     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
1162
1163     *result = This;
1164
1165     return S_OK;
1166 }
1167
1168 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
1169 {
1170     IUnknown *unk;
1171     HRESULT hr;
1172
1173     if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
1174     {
1175         unk = (IUnknown*)&This->ICorRuntimeHost_iface;
1176         IUnknown_AddRef(unk);
1177     }
1178     else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
1179     {
1180         unk = (IUnknown*)&This->ICLRRuntimeHost_iface;
1181         IUnknown_AddRef(unk);
1182     }
1183     else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
1184              IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
1185     {
1186         hr = MetaDataDispenser_CreateInstance(&unk);
1187         if (FAILED(hr))
1188             return hr;
1189     }
1190     else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
1191     {
1192         hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
1193         if (FAILED(hr))
1194             return hr;
1195     }
1196     else
1197         unk = NULL;
1198
1199     if (unk)
1200     {
1201         hr = IUnknown_QueryInterface(unk, riid, ppv);
1202
1203         IUnknown_Release(unk);
1204
1205         return hr;
1206     }
1207     else
1208         FIXME("not implemented for class %s\n", debugstr_guid(clsid));
1209
1210     return CLASS_E_CLASSNOTAVAILABLE;
1211 }
1212
1213 HRESULT RuntimeHost_Destroy(RuntimeHost *This)
1214 {
1215     struct DomainEntry *cursor, *cursor2;
1216
1217     This->lock.DebugInfo->Spare[0] = 0;
1218     DeleteCriticalSection(&This->lock);
1219
1220     LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->domains, struct DomainEntry, entry)
1221     {
1222         list_remove(&cursor->entry);
1223         HeapFree(GetProcessHeap(), 0, cursor);
1224     }
1225
1226     HeapFree( GetProcessHeap(), 0, This );
1227     return S_OK;
1228 }
1229
1230 #define CHARS_IN_GUID 39
1231 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
1232
1233 HRESULT create_monodata(REFIID riid, LPVOID *ppObj )
1234 {
1235     static const WCHAR wszCodebase[] = {'C','o','d','e','B','a','s','e',0};
1236     static const WCHAR wszClass[] = {'C','l','a','s','s',0};
1237     static const WCHAR wszFileSlash[] = {'f','i','l','e',':','/','/','/',0};
1238     static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1239     static const WCHAR wszInprocServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1240     WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) + ARRAYSIZE(wszInprocServer32) - 1];
1241     MonoDomain *domain;
1242     MonoAssembly *assembly;
1243     ICLRRuntimeInfo *info;
1244     RuntimeHost *host;
1245     HRESULT hr;
1246     HKEY key;
1247     LONG res;
1248     int offset = 0;
1249     WCHAR codebase[MAX_PATH + 8];
1250     WCHAR classname[350];
1251     WCHAR filename[MAX_PATH];
1252
1253     DWORD dwBufLen = 350;
1254
1255     lstrcpyW(path, wszCLSIDSlash);
1256     StringFromGUID2(riid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
1257     lstrcatW(path, wszInprocServer32);
1258
1259     TRACE("Registry key: %s\n", debugstr_w(path));
1260
1261     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key);
1262     if (res == ERROR_FILE_NOT_FOUND)
1263         return CLASS_E_CLASSNOTAVAILABLE;
1264
1265     res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen);
1266     if(res != ERROR_SUCCESS)
1267     {
1268         WARN("Class value cannot be found.\n");
1269         hr = CLASS_E_CLASSNOTAVAILABLE;
1270         goto cleanup;
1271     }
1272
1273     TRACE("classname (%s)\n", debugstr_w(classname));
1274
1275     dwBufLen = MAX_PATH + 8;
1276     res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen);
1277     if(res != ERROR_SUCCESS)
1278     {
1279         WARN("CodeBase value cannot be found.\n");
1280         hr = CLASS_E_CLASSNOTAVAILABLE;
1281         goto cleanup;
1282     }
1283
1284     /* Strip file:/// */
1285     if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0)
1286         offset = strlenW(wszFileSlash);
1287
1288     strcpyW(filename, codebase + offset);
1289
1290     TRACE("codebase (%s)\n", debugstr_w(filename));
1291
1292     *ppObj = NULL;
1293
1294
1295     hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
1296     if (SUCCEEDED(hr))
1297     {
1298         hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
1299
1300         if (SUCCEEDED(hr))
1301             hr = RuntimeHost_GetDefaultDomain(host, &domain);
1302
1303         if (SUCCEEDED(hr))
1304         {
1305             MonoImage *image;
1306             MonoClass *klass;
1307             MonoObject *result;
1308             IUnknown *unk = NULL;
1309             char *filenameA, *ns;
1310             char *classA;
1311
1312             hr = CLASS_E_CLASSNOTAVAILABLE;
1313
1314             host->mono->mono_thread_attach(domain);
1315
1316             filenameA = WtoA(filename);
1317             assembly = host->mono->mono_domain_assembly_open(domain, filenameA);
1318             HeapFree(GetProcessHeap(), 0, filenameA);
1319             if (!assembly)
1320             {
1321                 ERR("Cannot open assembly %s\n", filenameA);
1322                 goto cleanup;
1323             }
1324
1325             image = host->mono->mono_assembly_get_image(assembly);
1326             if (!image)
1327             {
1328                 ERR("Couldn't get assembly image\n");
1329                 goto cleanup;
1330             }
1331
1332             classA = WtoA(classname);
1333             ns = strrchr(classA, '.');
1334             *ns = '\0';
1335
1336             klass = host->mono->mono_class_from_name(image, classA, ns+1);
1337             HeapFree(GetProcessHeap(), 0, classA);
1338             if (!klass)
1339             {
1340                 ERR("Couldn't get class from image\n");
1341                 goto cleanup;
1342             }
1343
1344             /*
1345              * Use the default constructor for the .NET class.
1346              */
1347             result = host->mono->mono_object_new(domain, klass);
1348             host->mono->mono_runtime_object_init(result);
1349
1350             hr = RuntimeHost_GetIUnknownForObject(host, result, &unk);
1351             if (SUCCEEDED(hr))
1352             {
1353                 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj);
1354
1355                 IUnknown_Release(unk);
1356             }
1357             else
1358                 hr = CLASS_E_CLASSNOTAVAILABLE;
1359         }
1360         else
1361             hr = CLASS_E_CLASSNOTAVAILABLE;
1362     }
1363     else
1364         hr = CLASS_E_CLASSNOTAVAILABLE;
1365
1366 cleanup:
1367     if(info)
1368         ICLRRuntimeInfo_Release(info);
1369
1370     RegCloseKey(key);
1371
1372     return hr;
1373 }