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