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