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