gdi32/tests: Add tests for GetGlyphOutlineA.
[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 "wine/list.h"
36 #include "mscoree_private.h"
37
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
41
42 struct RuntimeHost
43 {
44     const struct ICorRuntimeHostVtbl *lpVtbl;
45     const struct ICLRRuntimeHostVtbl *lpCLRHostVtbl;
46     const CLRRuntimeInfo *version;
47     const loaded_mono *mono;
48     struct list domains;
49     MonoDomain *default_domain;
50     CRITICAL_SECTION lock;
51     LONG ref;
52 };
53
54 struct DomainEntry
55 {
56     struct list entry;
57     MonoDomain *domain;
58 };
59
60 static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, MonoDomain **result)
61 {
62     struct DomainEntry *entry;
63     char *mscorlib_path;
64     HRESULT res=S_OK;
65
66     EnterCriticalSection(&This->lock);
67
68     entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
69     if (!entry)
70     {
71         res = E_OUTOFMEMORY;
72         goto end;
73     }
74
75     mscorlib_path = WtoA(This->version->mscorlib_path);
76     if (!mscorlib_path)
77     {
78         HeapFree(GetProcessHeap(), 0, entry);
79         res = E_OUTOFMEMORY;
80         goto end;
81     }
82
83     entry->domain = This->mono->mono_jit_init(mscorlib_path);
84
85     HeapFree(GetProcessHeap(), 0, mscorlib_path);
86
87     if (!entry->domain)
88     {
89         HeapFree(GetProcessHeap(), 0, entry);
90         res = E_FAIL;
91         goto end;
92     }
93
94     list_add_tail(&This->domains, &entry->entry);
95
96     MSCOREE_LockModule();
97
98     *result = entry->domain;
99
100 end:
101     LeaveCriticalSection(&This->lock);
102
103     return res;
104 }
105
106 static HRESULT RuntimeHost_GetDefaultDomain(RuntimeHost *This, MonoDomain **result)
107 {
108     HRESULT res=S_OK;
109
110     EnterCriticalSection(&This->lock);
111
112     if (This->default_domain) goto end;
113
114     res = RuntimeHost_AddDomain(This, &This->default_domain);
115
116 end:
117     *result = This->default_domain;
118
119     LeaveCriticalSection(&This->lock);
120
121     return res;
122 }
123
124 static void RuntimeHost_DeleteDomain(RuntimeHost *This, MonoDomain *domain)
125 {
126     struct DomainEntry *entry;
127
128     EnterCriticalSection(&This->lock);
129
130     LIST_FOR_EACH_ENTRY(entry, &This->domains, struct DomainEntry, entry)
131     {
132         if (entry->domain == domain)
133         {
134             This->mono->mono_jit_cleanup(domain);
135             list_remove(&entry->entry);
136             if (This->default_domain == domain)
137                 This->default_domain = NULL;
138             HeapFree(GetProcessHeap(), 0, entry);
139             MSCOREE_UnlockModule();
140             break;
141         }
142     }
143
144     LeaveCriticalSection(&This->lock);
145 }
146
147 static inline RuntimeHost *impl_from_ICLRRuntimeHost( ICLRRuntimeHost *iface )
148 {
149     return (RuntimeHost *)((char*)iface - FIELD_OFFSET(RuntimeHost, lpCLRHostVtbl));
150 }
151
152 static inline RuntimeHost *impl_from_ICorRuntimeHost( ICorRuntimeHost *iface )
153 {
154     return (RuntimeHost *)((char*)iface - FIELD_OFFSET(RuntimeHost, lpVtbl));
155 }
156
157 /*** IUnknown methods ***/
158 static HRESULT WINAPI corruntimehost_QueryInterface(ICorRuntimeHost* iface,
159         REFIID riid,
160         void **ppvObject)
161 {
162     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
163     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
164
165     if ( IsEqualGUID( riid, &IID_ICorRuntimeHost ) ||
166          IsEqualGUID( riid, &IID_IUnknown ) )
167     {
168         *ppvObject = iface;
169     }
170     else
171     {
172         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
173         return E_NOINTERFACE;
174     }
175
176     ICorRuntimeHost_AddRef( iface );
177
178     return S_OK;
179 }
180
181 static ULONG WINAPI corruntimehost_AddRef(ICorRuntimeHost* iface)
182 {
183     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
184
185     MSCOREE_LockModule();
186
187     return InterlockedIncrement( &This->ref );
188 }
189
190 static ULONG WINAPI corruntimehost_Release(ICorRuntimeHost* iface)
191 {
192     RuntimeHost *This = impl_from_ICorRuntimeHost( iface );
193     ULONG ref;
194
195     MSCOREE_UnlockModule();
196
197     ref = InterlockedDecrement( &This->ref );
198
199     return ref;
200 }
201
202 /*** ICorRuntimeHost methods ***/
203 static HRESULT WINAPI corruntimehost_CreateLogicalThreadState(
204                     ICorRuntimeHost* iface)
205 {
206     FIXME("stub %p\n", iface);
207     return E_NOTIMPL;
208 }
209
210 static HRESULT WINAPI corruntimehost_DeleteLogicalThreadState(
211                     ICorRuntimeHost* iface)
212 {
213     FIXME("stub %p\n", iface);
214     return E_NOTIMPL;
215 }
216
217 static HRESULT WINAPI corruntimehost_SwitchInLogicalThreadState(
218                     ICorRuntimeHost* iface,
219                     DWORD *fiberCookie)
220 {
221     FIXME("stub %p\n", iface);
222     return E_NOTIMPL;
223 }
224
225 static HRESULT WINAPI corruntimehost_SwitchOutLogicalThreadState(
226                     ICorRuntimeHost* iface,
227                     DWORD **fiberCookie)
228 {
229     FIXME("stub %p\n", iface);
230     return E_NOTIMPL;
231 }
232
233 static HRESULT WINAPI corruntimehost_LocksHeldByLogicalThread(
234                     ICorRuntimeHost* iface,
235                     DWORD *pCount)
236 {
237     FIXME("stub %p\n", iface);
238     return E_NOTIMPL;
239 }
240
241 static HRESULT WINAPI corruntimehost_MapFile(
242     ICorRuntimeHost* iface,
243     HANDLE hFile,
244     HMODULE *mapAddress)
245 {
246     FIXME("stub %p\n", iface);
247     return E_NOTIMPL;
248 }
249
250 static HRESULT WINAPI corruntimehost_GetConfiguration(
251     ICorRuntimeHost* iface,
252     ICorConfiguration **pConfiguration)
253 {
254     FIXME("stub %p\n", iface);
255     return E_NOTIMPL;
256 }
257
258 static HRESULT WINAPI corruntimehost_Start(
259     ICorRuntimeHost* iface)
260 {
261     FIXME("stub %p\n", iface);
262     return E_NOTIMPL;
263 }
264
265 static HRESULT WINAPI corruntimehost_Stop(
266     ICorRuntimeHost* iface)
267 {
268     FIXME("stub %p\n", iface);
269     return E_NOTIMPL;
270 }
271
272 static HRESULT WINAPI corruntimehost_CreateDomain(
273     ICorRuntimeHost* iface,
274     LPCWSTR friendlyName,
275     IUnknown *identityArray,
276     IUnknown **appDomain)
277 {
278     FIXME("stub %p\n", iface);
279     return E_NOTIMPL;
280 }
281
282 static HRESULT WINAPI corruntimehost_GetDefaultDomain(
283     ICorRuntimeHost* iface,
284     IUnknown **pAppDomain)
285 {
286     FIXME("stub %p\n", iface);
287     return E_NOTIMPL;
288 }
289
290 static HRESULT WINAPI corruntimehost_EnumDomains(
291     ICorRuntimeHost* iface,
292     HDOMAINENUM *hEnum)
293 {
294     FIXME("stub %p\n", iface);
295     return E_NOTIMPL;
296 }
297
298 static HRESULT WINAPI corruntimehost_NextDomain(
299     ICorRuntimeHost* iface,
300     HDOMAINENUM hEnum,
301     IUnknown **appDomain)
302 {
303     FIXME("stub %p\n", iface);
304     return E_NOTIMPL;
305 }
306
307 static HRESULT WINAPI corruntimehost_CloseEnum(
308     ICorRuntimeHost* iface,
309     HDOMAINENUM hEnum)
310 {
311     FIXME("stub %p\n", iface);
312     return E_NOTIMPL;
313 }
314
315 static HRESULT WINAPI corruntimehost_CreateDomainEx(
316     ICorRuntimeHost* iface,
317     LPCWSTR friendlyName,
318     IUnknown *setup,
319     IUnknown *evidence,
320     IUnknown **appDomain)
321 {
322     FIXME("stub %p\n", iface);
323     return E_NOTIMPL;
324 }
325
326 static HRESULT WINAPI corruntimehost_CreateDomainSetup(
327     ICorRuntimeHost* iface,
328     IUnknown **appDomainSetup)
329 {
330     FIXME("stub %p\n", iface);
331     return E_NOTIMPL;
332 }
333
334 static HRESULT WINAPI corruntimehost_CreateEvidence(
335     ICorRuntimeHost* iface,
336     IUnknown **evidence)
337 {
338     FIXME("stub %p\n", iface);
339     return E_NOTIMPL;
340 }
341
342 static HRESULT WINAPI corruntimehost_UnloadDomain(
343     ICorRuntimeHost* iface,
344     IUnknown *appDomain)
345 {
346     FIXME("stub %p\n", iface);
347     return E_NOTIMPL;
348 }
349
350 static HRESULT WINAPI corruntimehost_CurrentDomain(
351     ICorRuntimeHost* iface,
352     IUnknown **appDomain)
353 {
354     FIXME("stub %p\n", iface);
355     return E_NOTIMPL;
356 }
357
358 static const struct ICorRuntimeHostVtbl corruntimehost_vtbl =
359 {
360     corruntimehost_QueryInterface,
361     corruntimehost_AddRef,
362     corruntimehost_Release,
363     corruntimehost_CreateLogicalThreadState,
364     corruntimehost_DeleteLogicalThreadState,
365     corruntimehost_SwitchInLogicalThreadState,
366     corruntimehost_SwitchOutLogicalThreadState,
367     corruntimehost_LocksHeldByLogicalThread,
368     corruntimehost_MapFile,
369     corruntimehost_GetConfiguration,
370     corruntimehost_Start,
371     corruntimehost_Stop,
372     corruntimehost_CreateDomain,
373     corruntimehost_GetDefaultDomain,
374     corruntimehost_EnumDomains,
375     corruntimehost_NextDomain,
376     corruntimehost_CloseEnum,
377     corruntimehost_CreateDomainEx,
378     corruntimehost_CreateDomainSetup,
379     corruntimehost_CreateEvidence,
380     corruntimehost_UnloadDomain,
381     corruntimehost_CurrentDomain
382 };
383
384 static HRESULT WINAPI CLRRuntimeHost_QueryInterface(ICLRRuntimeHost* iface,
385         REFIID riid,
386         void **ppvObject)
387 {
388     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
389     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
390
391     if ( IsEqualGUID( riid, &IID_ICLRRuntimeHost ) ||
392          IsEqualGUID( riid, &IID_IUnknown ) )
393     {
394         *ppvObject = iface;
395     }
396     else
397     {
398         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
399         return E_NOINTERFACE;
400     }
401
402     ICLRRuntimeHost_AddRef( iface );
403
404     return S_OK;
405 }
406
407 static ULONG WINAPI CLRRuntimeHost_AddRef(ICLRRuntimeHost* iface)
408 {
409     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
410     return IUnknown_AddRef((IUnknown*)&This->lpVtbl);
411 }
412
413 static ULONG WINAPI CLRRuntimeHost_Release(ICLRRuntimeHost* iface)
414 {
415     RuntimeHost *This = impl_from_ICLRRuntimeHost( iface );
416     return IUnknown_Release((IUnknown*)&This->lpVtbl);
417 }
418
419 static HRESULT WINAPI CLRRuntimeHost_Start(ICLRRuntimeHost* iface)
420 {
421     FIXME("(%p)\n", iface);
422     return E_NOTIMPL;
423 }
424
425 static HRESULT WINAPI CLRRuntimeHost_Stop(ICLRRuntimeHost* iface)
426 {
427     FIXME("(%p)\n", iface);
428     return E_NOTIMPL;
429 }
430
431 static HRESULT WINAPI CLRRuntimeHost_SetHostControl(ICLRRuntimeHost* iface,
432     IHostControl *pHostControl)
433 {
434     FIXME("(%p,%p)\n", iface, pHostControl);
435     return E_NOTIMPL;
436 }
437
438 static HRESULT WINAPI CLRRuntimeHost_GetCLRControl(ICLRRuntimeHost* iface,
439     ICLRControl **pCLRControl)
440 {
441     FIXME("(%p,%p)\n", iface, pCLRControl);
442     return E_NOTIMPL;
443 }
444
445 static HRESULT WINAPI CLRRuntimeHost_UnloadAppDomain(ICLRRuntimeHost* iface,
446     DWORD dwAppDomainId, BOOL fWaitUntilDone)
447 {
448     FIXME("(%p,%u,%i)\n", iface, dwAppDomainId, fWaitUntilDone);
449     return E_NOTIMPL;
450 }
451
452 static HRESULT WINAPI CLRRuntimeHost_ExecuteInAppDomain(ICLRRuntimeHost* iface,
453     DWORD dwAppDomainId, FExecuteInAppDomainCallback pCallback, void *cookie)
454 {
455     FIXME("(%p,%u,%p,%p)\n", iface, dwAppDomainId, pCallback, cookie);
456     return E_NOTIMPL;
457 }
458
459 static HRESULT WINAPI CLRRuntimeHost_GetCurrentAppDomainId(ICLRRuntimeHost* iface,
460     DWORD *pdwAppDomainId)
461 {
462     FIXME("(%p,%p)\n", iface, pdwAppDomainId);
463     return E_NOTIMPL;
464 }
465
466 static HRESULT WINAPI CLRRuntimeHost_ExecuteApplication(ICLRRuntimeHost* iface,
467     LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR *ppwzManifestPaths,
468     DWORD dwActivationData, LPCWSTR *ppwzActivationData, int *pReturnValue)
469 {
470     FIXME("(%p,%s,%u,%u)\n", iface, debugstr_w(pwzAppFullName), dwManifestPaths, dwActivationData);
471     return E_NOTIMPL;
472 }
473
474 static HRESULT WINAPI CLRRuntimeHost_ExecuteInDefaultAppDomain(ICLRRuntimeHost* iface,
475     LPCWSTR pwzAssemblyPath, LPCWSTR pwzTypeName, LPCWSTR pwzMethodName,
476     LPCWSTR pwzArgument, DWORD *pReturnValue)
477 {
478     FIXME("(%p,%s,%s,%s,%s)\n", iface, debugstr_w(pwzAssemblyPath),
479         debugstr_w(pwzTypeName), debugstr_w(pwzMethodName), debugstr_w(pwzArgument));
480     return E_NOTIMPL;
481 }
482
483 static const struct ICLRRuntimeHostVtbl CLRHostVtbl =
484 {
485     CLRRuntimeHost_QueryInterface,
486     CLRRuntimeHost_AddRef,
487     CLRRuntimeHost_Release,
488     CLRRuntimeHost_Start,
489     CLRRuntimeHost_Stop,
490     CLRRuntimeHost_SetHostControl,
491     CLRRuntimeHost_GetCLRControl,
492     CLRRuntimeHost_UnloadAppDomain,
493     CLRRuntimeHost_ExecuteInAppDomain,
494     CLRRuntimeHost_GetCurrentAppDomainId,
495     CLRRuntimeHost_ExecuteApplication,
496     CLRRuntimeHost_ExecuteInDefaultAppDomain
497 };
498
499 /* Create an instance of a type given its name, by calling its constructor with
500  * no arguments. Note that result MUST be in the stack, or the garbage
501  * collector may free it prematurely. */
502 HRESULT RuntimeHost_CreateManagedInstance(RuntimeHost *This, LPCWSTR name,
503     MonoDomain *domain, MonoObject **result)
504 {
505     HRESULT hr=S_OK;
506     char *nameA=NULL;
507     MonoType *type;
508     MonoClass *klass;
509     MonoObject *obj;
510
511     if (!domain)
512         hr = RuntimeHost_GetDefaultDomain(This, &domain);
513
514     if (SUCCEEDED(hr))
515     {
516         nameA = WtoA(name);
517         if (!nameA)
518             hr = E_OUTOFMEMORY;
519     }
520
521     if (SUCCEEDED(hr))
522     {
523         type = This->mono->mono_reflection_type_from_name(nameA, NULL);
524         if (!type)
525         {
526             ERR("Cannot find type %s\n", debugstr_w(name));
527             hr = E_FAIL;
528         }
529     }
530
531     if (SUCCEEDED(hr))
532     {
533         klass = This->mono->mono_class_from_mono_type(type);
534         if (!klass)
535         {
536             ERR("Cannot convert type %s to a class\n", debugstr_w(name));
537             hr = E_FAIL;
538         }
539     }
540
541     if (SUCCEEDED(hr))
542     {
543         obj = This->mono->mono_object_new(domain, klass);
544         if (!obj)
545         {
546             ERR("Cannot allocate object of type %s\n", debugstr_w(name));
547             hr = E_FAIL;
548         }
549     }
550
551     if (SUCCEEDED(hr))
552     {
553         /* FIXME: Detect exceptions from the constructor? */
554         This->mono->mono_runtime_object_init(obj);
555         *result = obj;
556     }
557
558     HeapFree(GetProcessHeap(), 0, nameA);
559
560     return hr;
561 }
562
563 /* Get an IUnknown pointer for a Mono object.
564  *
565  * This is just a "light" wrapper around
566  * System.Runtime.InteropServices.Marshal:GetIUnknownForObject
567  *
568  * NOTE: The IUnknown* is created with a reference to the object.
569  * Until they have a reference, objects must be in the stack to prevent the
570  * garbage collector from freeing them. */
571 HRESULT RuntimeHost_GetIUnknownForObject(RuntimeHost *This, MonoObject *obj,
572     IUnknown **ppUnk)
573 {
574     MonoDomain *domain;
575     MonoAssembly *assembly;
576     MonoImage *image;
577     MonoClass *klass;
578     MonoMethod *method;
579     MonoObject *result;
580     void *args[2];
581
582     domain = This->mono->mono_object_get_domain(obj);
583
584     assembly = This->mono->mono_domain_assembly_open(domain, "mscorlib");
585     if (!assembly)
586     {
587         ERR("Cannot load mscorlib\n");
588         return E_FAIL;
589     }
590
591     image = This->mono->mono_assembly_get_image(assembly);
592     if (!image)
593     {
594         ERR("Couldn't get assembly image\n");
595         return E_FAIL;
596     }
597
598     klass = This->mono->mono_class_from_name(image, "System.Runtime.InteropServices", "Marshal");
599     if (!klass)
600     {
601         ERR("Couldn't get class from image\n");
602         return E_FAIL;
603     }
604
605     method = This->mono->mono_class_get_method_from_name(klass, "GetIUnknownForObject", 1);
606     if (!method)
607     {
608         ERR("Couldn't get method from class\n");
609         return E_FAIL;
610     }
611
612     args[0] = obj;
613     args[1] = NULL;
614     result = This->mono->mono_runtime_invoke(method, NULL, args, NULL);
615     if (!result)
616     {
617         ERR("Couldn't get result pointer\n");
618         return E_FAIL;
619     }
620
621     *ppUnk = *(IUnknown**)This->mono->mono_object_unbox(result);
622     if (!*ppUnk)
623     {
624         ERR("GetIUnknownForObject returned 0\n");
625         return E_FAIL;
626     }
627
628     return S_OK;
629 }
630
631 static void get_utf8_args(int *argc, char ***argv)
632 {
633     WCHAR **argvw;
634     int size=0, i;
635     char *current_arg;
636
637     argvw = CommandLineToArgvW(GetCommandLineW(), argc);
638
639     for (i=0; i<*argc; i++)
640     {
641         size += sizeof(char*);
642         size += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL);
643     }
644     size += sizeof(char*);
645
646     *argv = HeapAlloc(GetProcessHeap(), 0, size);
647     current_arg = (char*)(*argv + *argc + 1);
648
649     for (i=0; i<*argc; i++)
650     {
651         (*argv)[i] = current_arg;
652         current_arg += WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, current_arg, size, NULL, NULL);
653     }
654
655     (*argv)[*argc] = NULL;
656
657     HeapFree(GetProcessHeap(), 0, argvw);
658 }
659
660 __int32 WINAPI _CorExeMain(void)
661 {
662     int exit_code;
663     int argc;
664     char **argv;
665     MonoDomain *domain;
666     MonoAssembly *assembly;
667     WCHAR filename[MAX_PATH];
668     char *filenameA;
669     ICLRRuntimeInfo *info;
670     RuntimeHost *host;
671     HRESULT hr;
672     int i;
673
674     get_utf8_args(&argc, &argv);
675
676     GetModuleFileNameW(NULL, filename, MAX_PATH);
677
678     TRACE("%s", debugstr_w(filename));
679     for (i=0; i<argc; i++)
680         TRACE(" %s", debugstr_a(argv[i]));
681     TRACE("\n");
682
683     filenameA = WtoA(filename);
684     if (!filenameA)
685         return -1;
686
687     hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info);
688
689     if (SUCCEEDED(hr))
690     {
691         hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host);
692
693         if (SUCCEEDED(hr))
694             hr = RuntimeHost_GetDefaultDomain(host, &domain);
695
696         if (SUCCEEDED(hr))
697         {
698             assembly = host->mono->mono_domain_assembly_open(domain, filenameA);
699
700             exit_code = host->mono->mono_jit_exec(domain, assembly, argc, argv);
701
702             RuntimeHost_DeleteDomain(host, domain);
703         }
704         else
705             exit_code = -1;
706
707         ICLRRuntimeInfo_Release(info);
708     }
709     else
710         exit_code = -1;
711
712     HeapFree(GetProcessHeap(), 0, argv);
713
714     return exit_code;
715 }
716
717 HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version,
718     const loaded_mono *loaded_mono, RuntimeHost** result)
719 {
720     RuntimeHost *This;
721
722     This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
723     if ( !This )
724         return E_OUTOFMEMORY;
725
726     This->lpVtbl = &corruntimehost_vtbl;
727     This->lpCLRHostVtbl = &CLRHostVtbl;
728     This->ref = 1;
729     This->version = runtime_version;
730     This->mono = loaded_mono;
731     list_init(&This->domains);
732     This->default_domain = NULL;
733     InitializeCriticalSection(&This->lock);
734     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RuntimeHost.lock");
735
736     *result = This;
737
738     return S_OK;
739 }
740
741 HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv)
742 {
743     IUnknown *unk;
744     HRESULT hr;
745
746     if (IsEqualGUID(clsid, &CLSID_CorRuntimeHost))
747     {
748         unk = (IUnknown*)&This->lpVtbl;
749         IUnknown_AddRef(unk);
750     }
751     else if (IsEqualGUID(clsid, &CLSID_CLRRuntimeHost))
752     {
753         unk = (IUnknown*)&This->lpCLRHostVtbl;
754         IUnknown_AddRef(unk);
755     }
756     else if (IsEqualGUID(clsid, &CLSID_CorMetaDataDispenser) ||
757              IsEqualGUID(clsid, &CLSID_CorMetaDataDispenserRuntime))
758     {
759         hr = MetaDataDispenser_CreateInstance(&unk);
760         if (FAILED(hr))
761             return hr;
762     }
763     else
764         unk = NULL;
765
766     if (unk)
767     {
768         hr = IUnknown_QueryInterface(unk, riid, ppv);
769
770         IUnknown_Release(unk);
771
772         return hr;
773     }
774     else
775         FIXME("not implemented for class %s\n", debugstr_guid(clsid));
776
777     return CLASS_E_CLASSNOTAVAILABLE;
778 }
779
780 HRESULT RuntimeHost_Destroy(RuntimeHost *This)
781 {
782     struct DomainEntry *cursor, *cursor2;
783
784     This->lock.DebugInfo->Spare[0] = 0;
785     DeleteCriticalSection(&This->lock);
786
787     LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->domains, struct DomainEntry, entry)
788     {
789         This->mono->mono_jit_cleanup(cursor->domain);
790         list_remove(&cursor->entry);
791         HeapFree(GetProcessHeap(), 0, cursor);
792     }
793
794     HeapFree( GetProcessHeap(), 0, This );
795     return S_OK;
796 }