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 } 1378