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 ICLRRuntimeInfo_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 #undef ARRAYSIZE 1209 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0])) 1210 1211 HRESULT create_monodata(REFIID riid, LPVOID *ppObj ) 1212 { 1213 static const WCHAR wszCodebase[] = {'C','o','d','e','B','a','s','e',0}; 1214 static const WCHAR wszClass[] = {'C','l','a','s','s',0}; 1215 static const WCHAR wszFileSlash[] = {'f','i','l','e',':','/','/','/',0}; 1216 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0}; 1217 static const WCHAR wszInprocServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0}; 1218 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) + ARRAYSIZE(wszInprocServer32) - 1]; 1219 MonoDomain *domain; 1220 MonoAssembly *assembly; 1221 ICLRRuntimeInfo *info = NULL; 1222 RuntimeHost *host; 1223 HRESULT hr; 1224 HKEY key; 1225 LONG res; 1226 int offset = 0; 1227 WCHAR codebase[MAX_PATH + 8]; 1228 WCHAR classname[350]; 1229 WCHAR filename[MAX_PATH]; 1230 1231 DWORD dwBufLen = 350; 1232 1233 lstrcpyW(path, wszCLSIDSlash); 1234 StringFromGUID2(riid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID); 1235 lstrcatW(path, wszInprocServer32); 1236 1237 TRACE("Registry key: %s\n", debugstr_w(path)); 1238 1239 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key); 1240 if (res == ERROR_FILE_NOT_FOUND) 1241 return CLASS_E_CLASSNOTAVAILABLE; 1242 1243 res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen); 1244 if(res != ERROR_SUCCESS) 1245 { 1246 WARN("Class value cannot be found.\n"); 1247 hr = CLASS_E_CLASSNOTAVAILABLE; 1248 goto cleanup; 1249 } 1250 1251 TRACE("classname (%s)\n", debugstr_w(classname)); 1252 1253 dwBufLen = MAX_PATH + 8; 1254 res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen); 1255 if(res != ERROR_SUCCESS) 1256 { 1257 WARN("CodeBase value cannot be found.\n"); 1258 hr = CLASS_E_CLASSNOTAVAILABLE; 1259 goto cleanup; 1260 } 1261 1262 /* Strip file:/// */ 1263 if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0) 1264 offset = strlenW(wszFileSlash); 1265 1266 strcpyW(filename, codebase + offset); 1267 1268 TRACE("codebase (%s)\n", debugstr_w(filename)); 1269 1270 *ppObj = NULL; 1271 1272 1273 hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info); 1274 if (SUCCEEDED(hr)) 1275 { 1276 hr = ICLRRuntimeInfo_GetRuntimeHost(info, &host); 1277 1278 if (SUCCEEDED(hr)) 1279 hr = RuntimeHost_GetDefaultDomain(host, &domain); 1280 1281 if (SUCCEEDED(hr)) 1282 { 1283 MonoImage *image; 1284 MonoClass *klass; 1285 MonoObject *result; 1286 IUnknown *unk = NULL; 1287 char *filenameA, *ns; 1288 char *classA; 1289 1290 hr = CLASS_E_CLASSNOTAVAILABLE; 1291 1292 host->mono->mono_thread_attach(domain); 1293 1294 filenameA = WtoA(filename); 1295 assembly = host->mono->mono_domain_assembly_open(domain, filenameA); 1296 HeapFree(GetProcessHeap(), 0, filenameA); 1297 if (!assembly) 1298 { 1299 ERR("Cannot open assembly %s\n", filenameA); 1300 goto cleanup; 1301 } 1302 1303 image = host->mono->mono_assembly_get_image(assembly); 1304 if (!image) 1305 { 1306 ERR("Couldn't get assembly image\n"); 1307 goto cleanup; 1308 } 1309 1310 classA = WtoA(classname); 1311 ns = strrchr(classA, '.'); 1312 *ns = '\0'; 1313 1314 klass = host->mono->mono_class_from_name(image, classA, ns+1); 1315 HeapFree(GetProcessHeap(), 0, classA); 1316 if (!klass) 1317 { 1318 ERR("Couldn't get class from image\n"); 1319 goto cleanup; 1320 } 1321 1322 /* 1323 * Use the default constructor for the .NET class. 1324 */ 1325 result = host->mono->mono_object_new(domain, klass); 1326 host->mono->mono_runtime_object_init(result); 1327 1328 hr = RuntimeHost_GetIUnknownForObject(host, result, &unk); 1329 if (SUCCEEDED(hr)) 1330 { 1331 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, ppObj); 1332 1333 IUnknown_Release(unk); 1334 } 1335 else 1336 hr = CLASS_E_CLASSNOTAVAILABLE; 1337 } 1338 else 1339 hr = CLASS_E_CLASSNOTAVAILABLE; 1340 } 1341 else 1342 hr = CLASS_E_CLASSNOTAVAILABLE; 1343 1344 cleanup: 1345 if(info) 1346 ICLRRuntimeInfo_Release(info); 1347 1348 RegCloseKey(key); 1349 1350 return hr; 1351 } 1352