1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS NT User Mode Library 4 * FILE: dll/ntdll/ldr/ldrapi.c 5 * PURPOSE: PE Loader Public APIs 6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 * Aleksey Bragin (aleksey@reactos.org) 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <ntdll.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS *******************************************************************/ 17 18 LIST_ENTRY LdrpUnloadHead; 19 LONG LdrpLoaderLockAcquisitonCount; 20 BOOLEAN LdrpShowRecursiveLoads, LdrpBreakOnRecursiveDllLoads; 21 UNICODE_STRING LdrApiDefaultExtension = RTL_CONSTANT_STRING(L".DLL"); 22 ULONG AlternateResourceModuleCount; 23 24 /* FUNCTIONS *****************************************************************/ 25 26 BOOLEAN 27 NTAPI 28 LdrAlternateResourcesEnabled(VOID) 29 { 30 /* ReactOS does not support this */ 31 return FALSE; 32 } 33 34 ULONG_PTR 35 FORCEINLINE 36 LdrpMakeCookie(VOID) 37 { 38 /* Generate a cookie */ 39 return (((ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) | 40 (_InterlockedIncrement(&LdrpLoaderLockAcquisitonCount) & 0xFFFF); 41 } 42 43 /* 44 * @implemented 45 */ 46 NTSTATUS 47 NTAPI 48 LdrUnlockLoaderLock(IN ULONG Flags, 49 IN ULONG Cookie OPTIONAL) 50 { 51 NTSTATUS Status = STATUS_SUCCESS; 52 53 DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags, Cookie); 54 55 /* Check for valid flags */ 56 if (Flags & ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 57 { 58 /* Flags are invalid, check how to fail */ 59 if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 60 { 61 /* The caller wants us to raise status */ 62 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1); 63 } 64 65 /* A normal failure */ 66 return STATUS_INVALID_PARAMETER_1; 67 } 68 69 /* If we don't have a cookie, just return */ 70 if (!Cookie) return STATUS_SUCCESS; 71 72 /* Validate the cookie */ 73 if ((Cookie & 0xF0000000) || 74 ((Cookie >> 16) ^ ((ULONG)(NtCurrentTeb()->RealClientId.UniqueThread) & 0xFFF))) 75 { 76 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n"); 77 78 /* Invalid cookie, check how to fail */ 79 if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 80 { 81 /* The caller wants us to raise status */ 82 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2); 83 } 84 85 /* A normal failure */ 86 return STATUS_INVALID_PARAMETER_2; 87 } 88 89 /* Ready to release the lock */ 90 if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 91 { 92 /* Do a direct leave */ 93 RtlLeaveCriticalSection(&LdrpLoaderLock); 94 } 95 else 96 { 97 /* Wrap this in SEH, since we're not supposed to raise */ 98 _SEH2_TRY 99 { 100 /* Leave the lock */ 101 RtlLeaveCriticalSection(&LdrpLoaderLock); 102 } 103 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 104 { 105 /* We should use the LDR Filter instead */ 106 Status = _SEH2_GetExceptionCode(); 107 } 108 _SEH2_END; 109 } 110 111 /* All done */ 112 return Status; 113 } 114 115 /* 116 * @implemented 117 */ 118 NTSTATUS 119 NTAPI 120 LdrLockLoaderLock(IN ULONG Flags, 121 OUT PULONG Disposition OPTIONAL, 122 OUT PULONG_PTR Cookie OPTIONAL) 123 { 124 NTSTATUS Status = STATUS_SUCCESS; 125 BOOLEAN InInit = LdrpInLdrInit; 126 127 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Disposition, Cookie); 128 129 /* Zero out the outputs */ 130 if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID; 131 if (Cookie) *Cookie = 0; 132 133 /* Validate the flags */ 134 if (Flags & ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS | 135 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)) 136 { 137 /* Flags are invalid, check how to fail */ 138 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 139 { 140 /* The caller wants us to raise status */ 141 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1); 142 } 143 144 /* A normal failure */ 145 return STATUS_INVALID_PARAMETER_1; 146 } 147 148 /* Make sure we got a cookie */ 149 if (!Cookie) 150 { 151 /* No cookie check how to fail */ 152 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 153 { 154 /* The caller wants us to raise status */ 155 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3); 156 } 157 158 /* A normal failure */ 159 return STATUS_INVALID_PARAMETER_3; 160 } 161 162 /* Do or Do Not. There is no Try */ 163 ASSERT((Disposition != NULL) || !(Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)); 164 165 /* If the flag is set, make sure we have a valid pointer to use */ 166 if ((Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) && !(Disposition)) 167 { 168 /* No pointer to return the data to */ 169 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 170 { 171 /* The caller wants us to raise status */ 172 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2); 173 } 174 175 /* Fail */ 176 return STATUS_INVALID_PARAMETER_2; 177 } 178 179 /* Return now if we are in the init phase */ 180 if (InInit) return STATUS_SUCCESS; 181 182 /* Check what locking semantic to use */ 183 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) 184 { 185 /* Check if we should enter or simply try */ 186 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) 187 { 188 /* Do a try */ 189 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock)) 190 { 191 /* It's locked */ 192 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED; 193 } 194 else 195 { 196 /* It worked */ 197 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; 198 *Cookie = LdrpMakeCookie(); 199 } 200 } 201 else 202 { 203 /* Do a enter */ 204 RtlEnterCriticalSection(&LdrpLoaderLock); 205 206 /* See if result was requested */ 207 if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; 208 *Cookie = LdrpMakeCookie(); 209 } 210 } 211 else 212 { 213 /* Wrap this in SEH, since we're not supposed to raise */ 214 _SEH2_TRY 215 { 216 /* Check if we should enter or simply try */ 217 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) 218 { 219 /* Do a try */ 220 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock)) 221 { 222 /* It's locked */ 223 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED; 224 } 225 else 226 { 227 /* It worked */ 228 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; 229 *Cookie = LdrpMakeCookie(); 230 } 231 } 232 else 233 { 234 /* Do an enter */ 235 RtlEnterCriticalSection(&LdrpLoaderLock); 236 237 /* See if result was requested */ 238 if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED; 239 *Cookie = LdrpMakeCookie(); 240 } 241 } 242 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 243 { 244 /* We should use the LDR Filter instead */ 245 Status = _SEH2_GetExceptionCode(); 246 } 247 _SEH2_END; 248 } 249 250 /* Return status */ 251 return Status; 252 } 253 254 /* 255 * @implemented 256 */ 257 NTSTATUS 258 NTAPI 259 LdrLoadDll(IN PWSTR SearchPath OPTIONAL, 260 IN PULONG DllCharacteristics OPTIONAL, 261 IN PUNICODE_STRING DllName, 262 OUT PVOID *BaseAddress) 263 { 264 WCHAR StringBuffer[MAX_PATH]; 265 UNICODE_STRING DllString1, DllString2; 266 BOOLEAN RedirectedDll = FALSE; 267 NTSTATUS Status; 268 ULONG Cookie; 269 PUNICODE_STRING OldTldDll; 270 PTEB Teb = NtCurrentTeb(); 271 272 /* Initialize the strings */ 273 RtlInitEmptyUnicodeString(&DllString2, NULL, 0); 274 DllString1.Buffer = StringBuffer; 275 DllString1.Length = 0; 276 DllString1.MaximumLength = sizeof(StringBuffer); 277 278 /* Check if the SxS Assemblies specify another file */ 279 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, 280 DllName, 281 &LdrApiDefaultExtension, 282 &DllString1, 283 &DllString2, 284 &DllName, 285 NULL, 286 NULL, 287 NULL); 288 289 /* Check success */ 290 if (NT_SUCCESS(Status)) 291 { 292 /* Let Ldrp know */ 293 RedirectedDll = TRUE; 294 } 295 else if (Status != STATUS_SXS_KEY_NOT_FOUND) 296 { 297 /* Unrecoverable SxS failure; did we get a string? */ 298 if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2); 299 return Status; 300 } 301 302 /* Lock the loader lock */ 303 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie); 304 305 /* Check if there's a TLD DLL being loaded */ 306 OldTldDll = LdrpTopLevelDllBeingLoaded; 307 if (OldTldDll) 308 { 309 /* This is a recursive load, do something about it? */ 310 if ((ShowSnaps) || (LdrpShowRecursiveLoads) || (LdrpBreakOnRecursiveDllLoads)) 311 { 312 /* Print out debug messages */ 313 DPRINT1("[%lx, %lx] LDR: Recursive DLL Load\n", 314 Teb->RealClientId.UniqueProcess, 315 Teb->RealClientId.UniqueThread); 316 DPRINT1("[%lx, %lx] Previous DLL being loaded \"%wZ\"\n", 317 Teb->RealClientId.UniqueProcess, 318 Teb->RealClientId.UniqueThread, 319 OldTldDll); 320 DPRINT1("[%lx, %lx] DLL being requested \"%wZ\"\n", 321 Teb->RealClientId.UniqueProcess, 322 Teb->RealClientId.UniqueThread, 323 DllName); 324 325 /* Was it initializing too? */ 326 if (!LdrpCurrentDllInitializer) 327 { 328 DPRINT1("[%lx, %lx] LDR: No DLL Initializer was running\n", 329 Teb->RealClientId.UniqueProcess, 330 Teb->RealClientId.UniqueThread); 331 } 332 else 333 { 334 DPRINT1("[%lx, %lx] DLL whose initializer was currently running \"%wZ\"\n", 335 Teb->ClientId.UniqueProcess, 336 Teb->ClientId.UniqueThread, 337 &LdrpCurrentDllInitializer->BaseDllName); 338 } 339 } 340 } 341 342 /* Set this one as the TLD DLL being loaded*/ 343 LdrpTopLevelDllBeingLoaded = DllName; 344 345 /* Load the DLL */ 346 Status = LdrpLoadDll(RedirectedDll, 347 SearchPath, 348 DllCharacteristics, 349 DllName, 350 BaseAddress, 351 TRUE); 352 if (NT_SUCCESS(Status)) 353 { 354 Status = STATUS_SUCCESS; 355 } 356 else if ((Status != STATUS_NO_SUCH_FILE) && 357 (Status != STATUS_DLL_NOT_FOUND) && 358 (Status != STATUS_OBJECT_NAME_NOT_FOUND) && 359 (Status != STATUS_DLL_INIT_FAILED)) 360 { 361 // 85 == DPFLTR_LDR_ID; 362 DbgPrintEx(85, 363 DPFLTR_WARNING_LEVEL, 364 "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n", 365 __FUNCTION__, 366 DllName, 367 Status); 368 } 369 370 /* Restore the old TLD DLL */ 371 LdrpTopLevelDllBeingLoaded = OldTldDll; 372 373 /* Release the lock */ 374 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie); 375 376 /* Do we have a redirect string? */ 377 if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2); 378 379 /* Return */ 380 return Status; 381 } 382 383 /* 384 * @implemented 385 */ 386 NTSTATUS 387 NTAPI 388 LdrFindEntryForAddress(PVOID Address, 389 PLDR_DATA_TABLE_ENTRY *Module) 390 { 391 PLIST_ENTRY ListHead, NextEntry; 392 PLDR_DATA_TABLE_ENTRY LdrEntry; 393 PIMAGE_NT_HEADERS NtHeader; 394 PPEB_LDR_DATA Ldr = NtCurrentPeb()->Ldr; 395 ULONG_PTR DllBase, DllEnd; 396 397 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address); 398 399 /* Nothing to do */ 400 if (!Ldr) return STATUS_NO_MORE_ENTRIES; 401 402 /* Get the current entry */ 403 LdrEntry = Ldr->EntryInProgress; 404 if (LdrEntry) 405 { 406 /* Get the NT Headers */ 407 NtHeader = RtlImageNtHeader(LdrEntry->DllBase); 408 if (NtHeader) 409 { 410 /* Get the Image Base */ 411 DllBase = (ULONG_PTR)LdrEntry->DllBase; 412 DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage; 413 414 /* Check if they match */ 415 if (((ULONG_PTR)Address >= DllBase) && 416 ((ULONG_PTR)Address < DllEnd)) 417 { 418 /* Return it */ 419 *Module = LdrEntry; 420 return STATUS_SUCCESS; 421 } 422 } 423 } 424 425 /* Loop the module list */ 426 ListHead = &Ldr->InMemoryOrderModuleList; 427 NextEntry = ListHead->Flink; 428 while (NextEntry != ListHead) 429 { 430 /* Get the entry and NT Headers */ 431 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList); 432 NtHeader = RtlImageNtHeader(LdrEntry->DllBase); 433 if (NtHeader) 434 { 435 /* Get the Image Base */ 436 DllBase = (ULONG_PTR)LdrEntry->DllBase; 437 DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage; 438 439 /* Check if they match */ 440 if (((ULONG_PTR)Address >= DllBase) && 441 ((ULONG_PTR)Address < DllEnd)) 442 { 443 /* Return it */ 444 *Module = LdrEntry; 445 return STATUS_SUCCESS; 446 } 447 448 /* Next Entry */ 449 NextEntry = NextEntry->Flink; 450 } 451 } 452 453 /* Nothing found */ 454 // 85 == DPFLTR_LDR_ID; 455 DbgPrintEx(85, DPFLTR_WARNING_LEVEL, "LDR: %s() exiting 0x%08lx\n", __FUNCTION__, STATUS_NO_MORE_ENTRIES); 456 return STATUS_NO_MORE_ENTRIES; 457 } 458 459 /* 460 * @implemented 461 */ 462 NTSTATUS 463 NTAPI 464 LdrGetDllHandleEx(IN ULONG Flags, 465 IN PWSTR DllPath OPTIONAL, 466 IN PULONG DllCharacteristics OPTIONAL, 467 IN PUNICODE_STRING DllName, 468 OUT PVOID *DllHandle OPTIONAL) 469 { 470 NTSTATUS Status; 471 PLDR_DATA_TABLE_ENTRY LdrEntry; 472 UNICODE_STRING RedirectName, DllString1, RawDllName; 473 PUNICODE_STRING pRedirectName, CompareName; 474 PWCHAR p1, p2, p3; 475 BOOLEAN Locked, RedirectedDll; 476 ULONG_PTR Cookie; 477 ULONG LoadFlag, Length; 478 479 /* Initialize the strings */ 480 RtlInitEmptyUnicodeString(&DllString1, NULL, 0); 481 RtlInitEmptyUnicodeString(&RawDllName, NULL, 0); 482 RedirectName = *DllName; 483 pRedirectName = &RedirectName; 484 485 /* Initialize state */ 486 RedirectedDll = Locked = FALSE; 487 LdrEntry = NULL; 488 Cookie = 0; 489 490 /* Clear the handle */ 491 if (DllHandle) *DllHandle = NULL; 492 493 /* Check for a valid flag combination */ 494 if ((Flags & ~(LDR_GET_DLL_HANDLE_EX_PIN | LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT)) || 495 (!DllHandle && !(Flags & LDR_GET_DLL_HANDLE_EX_PIN))) 496 { 497 DPRINT1("Flags are invalid or no DllHandle given\n"); 498 Status = STATUS_INVALID_PARAMETER; 499 goto Quickie; 500 } 501 502 /* If not initializing */ 503 if (!LdrpInLdrInit) 504 { 505 /* Acquire the lock */ 506 Status = LdrLockLoaderLock(0, NULL, &Cookie); 507 if (!NT_SUCCESS(Status)) goto Quickie; 508 509 /* Remember we own it */ 510 Locked = TRUE; 511 } 512 513 /* Check if the SxS Assemblies specify another file */ 514 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, 515 pRedirectName, 516 &LdrApiDefaultExtension, 517 NULL, 518 &DllString1, 519 &pRedirectName, 520 NULL, 521 NULL, 522 NULL); 523 524 /* Check success */ 525 if (NT_SUCCESS(Status)) 526 { 527 /* Let Ldrp know */ 528 RedirectedDll = TRUE; 529 } 530 else if (Status != STATUS_SXS_KEY_NOT_FOUND) 531 { 532 /* Unrecoverable SxS failure; */ 533 goto Quickie; 534 } 535 else 536 { 537 ASSERT(pRedirectName == &RedirectName); 538 } 539 540 /* Set default failure code */ 541 Status = STATUS_DLL_NOT_FOUND; 542 543 /* Use the cache if we can */ 544 if (LdrpGetModuleHandleCache) 545 { 546 /* Check if we were redirected */ 547 if (RedirectedDll) 548 { 549 /* Check the flag */ 550 if (!(LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED)) 551 { 552 goto DontCompare; 553 } 554 555 /* Use the right name */ 556 CompareName = &LdrpGetModuleHandleCache->FullDllName; 557 } 558 else 559 { 560 /* Check the flag */ 561 if (LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED) 562 { 563 goto DontCompare; 564 } 565 566 /* Use the right name */ 567 CompareName = &LdrpGetModuleHandleCache->BaseDllName; 568 } 569 570 /* Check if the name matches */ 571 if (RtlEqualUnicodeString(pRedirectName, 572 CompareName, 573 TRUE)) 574 { 575 /* Skip the rest */ 576 LdrEntry = LdrpGetModuleHandleCache; 577 578 /* Return success */ 579 Status = STATUS_SUCCESS; 580 goto Quickie; 581 } 582 } 583 584 DontCompare: 585 /* Find the name without the extension */ 586 p1 = pRedirectName->Buffer; 587 p2 = NULL; 588 p3 = &p1[pRedirectName->Length / sizeof(WCHAR)]; 589 while (p1 != p3) 590 { 591 if (*p1++ == L'.') 592 { 593 p2 = p1; 594 } 595 else if (*p1 == L'\\') 596 { 597 p2 = NULL; 598 } 599 } 600 601 /* Check if no extension was found or if we got a slash */ 602 if (!(p2) || (*p2 == L'\\') || (*p2 == L'/')) 603 { 604 /* Check that we have space to add one */ 605 Length = pRedirectName->Length + 606 LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL); 607 if (Length >= UNICODE_STRING_MAX_BYTES) 608 { 609 /* No space to add the extension */ 610 Status = STATUS_NAME_TOO_LONG; 611 goto Quickie; 612 } 613 614 /* Setup the string */ 615 RawDllName.MaximumLength = Length; 616 ASSERT(Length >= sizeof(UNICODE_NULL)); 617 RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 618 0, 619 RawDllName.MaximumLength); 620 if (!RawDllName.Buffer) 621 { 622 Status = STATUS_NO_MEMORY; 623 goto Quickie; 624 } 625 626 /* Copy the string and add extension */ 627 RtlCopyUnicodeString(&RawDllName, pRedirectName); 628 RtlAppendUnicodeStringToString(&RawDllName, &LdrApiDefaultExtension); 629 } 630 else 631 { 632 /* Check if there's something in the name */ 633 Length = pRedirectName->Length; 634 if (Length) 635 { 636 /* Check and remove trailing period */ 637 if (pRedirectName->Buffer[Length / sizeof(WCHAR) - sizeof(ANSI_NULL)] == '.') 638 { 639 /* Decrease the size */ 640 pRedirectName->Length -= sizeof(WCHAR); 641 } 642 } 643 644 /* Setup the string */ 645 RawDllName.MaximumLength = pRedirectName->Length + sizeof(WCHAR); 646 RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 647 0, 648 RawDllName.MaximumLength); 649 if (!RawDllName.Buffer) 650 { 651 Status = STATUS_NO_MEMORY; 652 goto Quickie; 653 } 654 655 /* Copy the string */ 656 RtlCopyUnicodeString(&RawDllName, pRedirectName); 657 } 658 659 /* Display debug string */ 660 if (ShowSnaps) 661 { 662 DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n", 663 &RawDllName, 664 DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L""); 665 } 666 667 /* Do the lookup */ 668 if (LdrpCheckForLoadedDll(DllPath, 669 &RawDllName, 670 ((ULONG_PTR)DllPath == 1) ? TRUE : FALSE, 671 RedirectedDll, 672 &LdrEntry)) 673 { 674 /* Update cached entry */ 675 LdrpGetModuleHandleCache = LdrEntry; 676 677 /* Return success */ 678 Status = STATUS_SUCCESS; 679 } 680 else 681 { 682 /* Make sure to NULL this */ 683 LdrEntry = NULL; 684 } 685 Quickie: 686 /* The success path must have a valid loader entry */ 687 ASSERT((LdrEntry != NULL) == NT_SUCCESS(Status)); 688 689 /* Check if we got an entry and success */ 690 DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry ? &LdrEntry->BaseDllName : NULL); 691 if ((LdrEntry) && (NT_SUCCESS(Status))) 692 { 693 /* Check if the DLL is locked */ 694 if ((LdrEntry->LoadCount != 0xFFFF) && 695 !(Flags & LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT)) 696 { 697 /* Check what to do with the load count */ 698 if (Flags & LDR_GET_DLL_HANDLE_EX_PIN) 699 { 700 /* Pin it */ 701 LdrEntry->LoadCount = 0xFFFF; 702 LoadFlag = LDRP_UPDATE_PIN; 703 } 704 else 705 { 706 /* Increase the load count */ 707 LdrEntry->LoadCount++; 708 LoadFlag = LDRP_UPDATE_REFCOUNT; 709 } 710 711 /* Update the load count now */ 712 LdrpUpdateLoadCount2(LdrEntry, LoadFlag); 713 LdrpClearLoadInProgress(); 714 } 715 716 /* Check if the caller is requesting the handle */ 717 if (DllHandle) *DllHandle = LdrEntry->DllBase; 718 } 719 720 /* Free string if needed */ 721 if (DllString1.Buffer) RtlFreeUnicodeString(&DllString1); 722 723 /* Free the raw DLL Name if needed */ 724 if (RawDllName.Buffer) 725 { 726 /* Free the heap-allocated buffer */ 727 RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName.Buffer); 728 RawDllName.Buffer = NULL; 729 } 730 731 /* Release lock */ 732 if (Locked) 733 { 734 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, 735 Cookie); 736 } 737 738 /* Return */ 739 return Status; 740 } 741 742 /* 743 * @implemented 744 */ 745 NTSTATUS 746 NTAPI 747 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL, 748 IN PULONG DllCharacteristics OPTIONAL, 749 IN PUNICODE_STRING DllName, 750 OUT PVOID *DllHandle) 751 { 752 /* Call the newer API */ 753 return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT, 754 DllPath, 755 DllCharacteristics, 756 DllName, 757 DllHandle); 758 } 759 760 /* 761 * @implemented 762 */ 763 NTSTATUS 764 NTAPI 765 LdrGetProcedureAddress(IN PVOID BaseAddress, 766 IN PANSI_STRING Name, 767 IN ULONG Ordinal, 768 OUT PVOID *ProcedureAddress) 769 { 770 /* Call the internal routine and tell it to execute DllInit */ 771 return LdrpGetProcedureAddress(BaseAddress, Name, Ordinal, ProcedureAddress, TRUE); 772 } 773 774 /* 775 * @implemented 776 */ 777 NTSTATUS 778 NTAPI 779 LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle, 780 IN PLDR_CALLBACK Callback, 781 IN PVOID CallbackContext, 782 OUT PUSHORT ImageCharacteristics) 783 { 784 FILE_STANDARD_INFORMATION FileStandardInfo; 785 PIMAGE_IMPORT_DESCRIPTOR ImportData; 786 PIMAGE_SECTION_HEADER LastSection = NULL; 787 IO_STATUS_BLOCK IoStatusBlock; 788 PIMAGE_NT_HEADERS NtHeader; 789 HANDLE SectionHandle; 790 SIZE_T ViewSize; 791 PVOID ViewBase; 792 BOOLEAN Result, NoActualCheck; 793 NTSTATUS Status; 794 PVOID ImportName; 795 ULONG Size; 796 DPRINT("LdrVerifyImageMatchesChecksum() called\n"); 797 798 /* If the handle has the magic KnownDll flag, skip actual checksums */ 799 NoActualCheck = ((ULONG_PTR)FileHandle & 1); 800 801 /* Create the section */ 802 Status = NtCreateSection(&SectionHandle, 803 SECTION_MAP_EXECUTE, 804 NULL, 805 NULL, 806 PAGE_EXECUTE, 807 SEC_COMMIT, 808 FileHandle); 809 if (!NT_SUCCESS(Status)) 810 { 811 DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status); 812 return Status; 813 } 814 815 /* Map the section */ 816 ViewSize = 0; 817 ViewBase = NULL; 818 Status = NtMapViewOfSection(SectionHandle, 819 NtCurrentProcess(), 820 &ViewBase, 821 0, 822 0, 823 NULL, 824 &ViewSize, 825 ViewShare, 826 0, 827 PAGE_EXECUTE); 828 if (!NT_SUCCESS(Status)) 829 { 830 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status); 831 NtClose(SectionHandle); 832 return Status; 833 } 834 835 /* Get the file information */ 836 Status = NtQueryInformationFile(FileHandle, 837 &IoStatusBlock, 838 &FileStandardInfo, 839 sizeof(FILE_STANDARD_INFORMATION), 840 FileStandardInformation); 841 if (!NT_SUCCESS(Status)) 842 { 843 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status); 844 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 845 NtClose(SectionHandle); 846 return Status; 847 } 848 849 /* Protect with SEH */ 850 _SEH2_TRY 851 { 852 /* Check if this is the KnownDll hack */ 853 if (NoActualCheck) 854 { 855 /* Don't actually do it */ 856 Result = TRUE; 857 } 858 else 859 { 860 /* Verify the checksum */ 861 Result = LdrVerifyMappedImageMatchesChecksum(ViewBase, 862 FileStandardInfo.EndOfFile.LowPart, 863 FileStandardInfo.EndOfFile.LowPart); 864 } 865 866 /* Check if a callback was supplied */ 867 if ((Result) && (Callback)) 868 { 869 /* Get the NT Header */ 870 NtHeader = RtlImageNtHeader(ViewBase); 871 872 /* Check if caller requested this back */ 873 if (ImageCharacteristics) 874 { 875 /* Return to caller */ 876 *ImageCharacteristics = NtHeader->FileHeader.Characteristics; 877 } 878 879 /* Get the Import Directory Data */ 880 ImportData = RtlImageDirectoryEntryToData(ViewBase, 881 FALSE, 882 IMAGE_DIRECTORY_ENTRY_IMPORT, 883 &Size); 884 885 /* Make sure there is one */ 886 if (ImportData) 887 { 888 /* Loop the imports */ 889 while (ImportData->Name) 890 { 891 /* Get the name */ 892 ImportName = RtlImageRvaToVa(NtHeader, 893 ViewBase, 894 ImportData->Name, 895 &LastSection); 896 897 /* Notify the callback */ 898 Callback(CallbackContext, ImportName); 899 ImportData++; 900 } 901 } 902 } 903 } 904 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 905 { 906 /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */ 907 Result = FALSE; 908 } 909 _SEH2_END; 910 911 /* Unmap file and close handle */ 912 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); 913 NtClose(SectionHandle); 914 915 /* Return status */ 916 return Result ? Status : STATUS_IMAGE_CHECKSUM_MISMATCH; 917 } 918 919 NTSTATUS 920 NTAPI 921 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId, 922 IN ULONG Reserved, 923 OUT PRTL_PROCESS_MODULES ModuleInformation, 924 IN ULONG Size, 925 OUT PULONG ReturnedSize OPTIONAL) 926 { 927 PLIST_ENTRY ModuleListHead, InitListHead; 928 PLIST_ENTRY Entry, InitEntry; 929 PLDR_DATA_TABLE_ENTRY Module, InitModule; 930 PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL; 931 NTSTATUS Status = STATUS_SUCCESS; 932 ULONG UsedSize = sizeof(ULONG); 933 ANSI_STRING AnsiString; 934 PCHAR p; 935 936 DPRINT("LdrQueryProcessModuleInformation() called\n"); 937 938 /* Acquire loader lock */ 939 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); 940 941 _SEH2_TRY 942 { 943 /* Check if we were given enough space */ 944 if (Size < UsedSize) 945 { 946 Status = STATUS_INFO_LENGTH_MISMATCH; 947 } 948 else 949 { 950 ModuleInformation->NumberOfModules = 0; 951 ModulePtr = &ModuleInformation->Modules[0]; 952 Status = STATUS_SUCCESS; 953 } 954 955 /* Traverse the list of modules */ 956 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 957 Entry = ModuleListHead->Flink; 958 959 while (Entry != ModuleListHead) 960 { 961 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 962 963 DPRINT(" Module %wZ\n", &Module->FullDllName); 964 965 /* Increase the used size */ 966 UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION); 967 968 if (UsedSize > Size) 969 { 970 Status = STATUS_INFO_LENGTH_MISMATCH; 971 } 972 else 973 { 974 ModulePtr->ImageBase = Module->DllBase; 975 ModulePtr->ImageSize = Module->SizeOfImage; 976 ModulePtr->Flags = Module->Flags; 977 ModulePtr->LoadCount = Module->LoadCount; 978 ModulePtr->MappedBase = NULL; 979 ModulePtr->InitOrderIndex = 0; 980 ModulePtr->LoadOrderIndex = ModuleInformation->NumberOfModules; 981 982 /* Now get init order index by traversing init list */ 983 InitListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList; 984 InitEntry = InitListHead->Flink; 985 986 while (InitEntry != InitListHead) 987 { 988 InitModule = CONTAINING_RECORD(InitEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList); 989 990 /* Increase the index */ 991 ModulePtr->InitOrderIndex++; 992 993 /* Quit the loop if our module is found */ 994 if (InitModule == Module) break; 995 996 /* Advance to the next entry */ 997 InitEntry = InitEntry->Flink; 998 } 999 1000 /* Prepare ANSI string with the module's name */ 1001 AnsiString.Length = 0; 1002 AnsiString.MaximumLength = sizeof(ModulePtr->FullPathName); 1003 AnsiString.Buffer = ModulePtr->FullPathName; 1004 RtlUnicodeStringToAnsiString(&AnsiString, 1005 &Module->FullDllName, 1006 FALSE); 1007 1008 /* Calculate OffsetToFileName field */ 1009 p = strrchr(ModulePtr->FullPathName, '\\'); 1010 if (p != NULL) 1011 ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1; 1012 else 1013 ModulePtr->OffsetToFileName = 0; 1014 1015 /* Advance to the next module in the output list */ 1016 ModulePtr++; 1017 1018 /* Increase number of modules */ 1019 if (ModuleInformation) 1020 ModuleInformation->NumberOfModules++; 1021 } 1022 1023 /* Go to the next entry in the modules list */ 1024 Entry = Entry->Flink; 1025 } 1026 1027 /* Set returned size if it was provided */ 1028 if (ReturnedSize) 1029 *ReturnedSize = UsedSize; 1030 } 1031 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1032 { 1033 /* Ignoring the exception */ 1034 } _SEH2_END; 1035 1036 /* Release the lock */ 1037 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); 1038 1039 DPRINT("LdrQueryProcessModuleInformation() done\n"); 1040 1041 return Status; 1042 } 1043 1044 /* 1045 * @implemented 1046 */ 1047 NTSTATUS 1048 NTAPI 1049 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation, 1050 IN ULONG Size, 1051 OUT PULONG ReturnedSize OPTIONAL) 1052 { 1053 /* Call Ex version of the API */ 1054 return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation, Size, ReturnedSize); 1055 } 1056 1057 /* 1058 * @implemented 1059 */ 1060 NTSTATUS 1061 NTAPI 1062 LdrEnumerateLoadedModules(IN BOOLEAN ReservedFlag, 1063 IN PLDR_ENUM_CALLBACK EnumProc, 1064 IN PVOID Context) 1065 { 1066 PLIST_ENTRY ListHead, ListEntry; 1067 PLDR_DATA_TABLE_ENTRY LdrEntry; 1068 NTSTATUS Status; 1069 ULONG Cookie; 1070 BOOLEAN Stop = FALSE; 1071 1072 /* Check parameters */ 1073 if ((ReservedFlag) || !(EnumProc)) return STATUS_INVALID_PARAMETER; 1074 1075 /* Acquire the loader lock */ 1076 Status = LdrLockLoaderLock(0, NULL, &Cookie); 1077 if (!NT_SUCCESS(Status)) return Status; 1078 1079 /* Loop all the modules and call enum proc */ 1080 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 1081 ListEntry = ListHead->Flink; 1082 while (ListHead != ListEntry) 1083 { 1084 /* Get the entry */ 1085 LdrEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 1086 1087 /* Call the enumeration proc inside SEH */ 1088 _SEH2_TRY 1089 { 1090 EnumProc(LdrEntry, Context, &Stop); 1091 } 1092 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1093 { 1094 /* Ignoring the exception */ 1095 } _SEH2_END; 1096 1097 /* Break if we were asked to stop enumeration */ 1098 if (Stop) 1099 { 1100 /* Release loader lock */ 1101 Status = LdrUnlockLoaderLock(0, Cookie); 1102 1103 /* Reset any successful status to STATUS_SUCCESS, but leave 1104 failure to the caller */ 1105 if (NT_SUCCESS(Status)) 1106 Status = STATUS_SUCCESS; 1107 1108 /* Return any possible failure status */ 1109 return Status; 1110 } 1111 1112 /* Advance to the next module */ 1113 ListEntry = ListEntry->Flink; 1114 } 1115 1116 /* Release loader lock, it must succeed this time */ 1117 Status = LdrUnlockLoaderLock(0, Cookie); 1118 ASSERT(NT_SUCCESS(Status)); 1119 1120 /* Return success */ 1121 return STATUS_SUCCESS; 1122 } 1123 1124 /* 1125 * @implemented 1126 */ 1127 NTSTATUS 1128 NTAPI 1129 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress) 1130 { 1131 PLDR_DATA_TABLE_ENTRY LdrEntry; 1132 NTSTATUS Status; 1133 BOOLEAN LockHeld; 1134 ULONG_PTR Cookie; 1135 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress); 1136 1137 /* Don't do it during shutdown */ 1138 if (LdrpShutdownInProgress) return STATUS_SUCCESS; 1139 1140 /* Check if we should grab the lock */ 1141 LockHeld = FALSE; 1142 if (!LdrpInLdrInit) 1143 { 1144 /* Grab the lock */ 1145 Status = LdrLockLoaderLock(0, NULL, &Cookie); 1146 if (!NT_SUCCESS(Status)) return Status; 1147 LockHeld = TRUE; 1148 } 1149 1150 /* Make sure the DLL is valid and get its entry */ 1151 Status = STATUS_DLL_NOT_FOUND; 1152 if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) 1153 { 1154 /* Get if it has a TLS slot */ 1155 if (!LdrEntry->TlsIndex) 1156 { 1157 /* It doesn't, so you're allowed to call this */ 1158 LdrEntry->Flags |= LDRP_DONT_CALL_FOR_THREADS; 1159 Status = STATUS_SUCCESS; 1160 } 1161 } 1162 1163 /* Check if the lock was held */ 1164 if (LockHeld) 1165 { 1166 /* Release it */ 1167 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie); 1168 } 1169 1170 /* Return the status */ 1171 return Status; 1172 } 1173 1174 /* 1175 * @implemented 1176 */ 1177 NTSTATUS 1178 NTAPI 1179 LdrAddRefDll(IN ULONG Flags, 1180 IN PVOID BaseAddress) 1181 { 1182 PLDR_DATA_TABLE_ENTRY LdrEntry; 1183 NTSTATUS Status = STATUS_SUCCESS; 1184 ULONG Cookie; 1185 BOOLEAN Locked = FALSE; 1186 1187 /* Check for invalid flags */ 1188 if (Flags & ~(LDR_ADDREF_DLL_PIN)) 1189 { 1190 /* Fail with invalid parameter status if so */ 1191 Status = STATUS_INVALID_PARAMETER; 1192 goto quickie; 1193 } 1194 1195 /* Acquire the loader lock if not in init phase */ 1196 if (!LdrpInLdrInit) 1197 { 1198 /* Acquire the lock */ 1199 Status = LdrLockLoaderLock(0, NULL, &Cookie); 1200 if (!NT_SUCCESS(Status)) goto quickie; 1201 Locked = TRUE; 1202 } 1203 1204 /* Get this module's data table entry */ 1205 if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) 1206 { 1207 if (!LdrEntry) 1208 { 1209 /* Shouldn't happen */ 1210 Status = STATUS_INTERNAL_ERROR; 1211 goto quickie; 1212 } 1213 1214 /* If this is not a pinned module */ 1215 if (LdrEntry->LoadCount != 0xFFFF) 1216 { 1217 /* Update its load count */ 1218 if (Flags & LDR_ADDREF_DLL_PIN) 1219 { 1220 /* Pin it by setting load count to -1 */ 1221 LdrEntry->LoadCount = 0xFFFF; 1222 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_PIN); 1223 } 1224 else 1225 { 1226 /* Increase its load count by one */ 1227 LdrEntry->LoadCount++; 1228 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT); 1229 } 1230 1231 /* Clear load in progress */ 1232 LdrpClearLoadInProgress(); 1233 } 1234 } 1235 else 1236 { 1237 /* There was an error getting this module's handle, return invalid param status */ 1238 Status = STATUS_INVALID_PARAMETER; 1239 } 1240 1241 quickie: 1242 /* Check for error case */ 1243 if (!NT_SUCCESS(Status)) 1244 { 1245 /* Print debug information */ 1246 if ((ShowSnaps) || ((Status != STATUS_NO_SUCH_FILE) && 1247 (Status != STATUS_DLL_NOT_FOUND) && 1248 (Status != STATUS_OBJECT_NAME_NOT_FOUND))) 1249 { 1250 DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress); 1251 } 1252 } 1253 1254 /* Release the lock if needed */ 1255 if (Locked) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie); 1256 return Status; 1257 } 1258 1259 /* 1260 * @implemented 1261 */ 1262 NTSTATUS 1263 NTAPI 1264 LdrUnloadDll(IN PVOID BaseAddress) 1265 { 1266 NTSTATUS Status = STATUS_SUCCESS; 1267 PPEB Peb = NtCurrentPeb(); 1268 PLDR_DATA_TABLE_ENTRY LdrEntry, CurrentEntry; 1269 PVOID EntryPoint; 1270 PLIST_ENTRY NextEntry; 1271 LIST_ENTRY UnloadList; 1272 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; 1273 PVOID CorImageData; 1274 ULONG ComSectionSize; 1275 1276 /* Get the LDR Lock */ 1277 if (!LdrpInLdrInit) RtlEnterCriticalSection(Peb->LoaderLock); 1278 1279 /* Increase the unload count */ 1280 LdrpActiveUnloadCount++; 1281 1282 /* Skip unload */ 1283 if (LdrpShutdownInProgress) goto Quickie; 1284 1285 /* Make sure the DLL is valid and get its entry */ 1286 if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) 1287 { 1288 Status = STATUS_DLL_NOT_FOUND; 1289 goto Quickie; 1290 } 1291 1292 /* Check the current Load Count */ 1293 if (LdrEntry->LoadCount != 0xFFFF) 1294 { 1295 /* Decrease it */ 1296 LdrEntry->LoadCount--; 1297 1298 /* If it's a dll */ 1299 if (LdrEntry->Flags & LDRP_IMAGE_DLL) 1300 { 1301 /* Set up the Act Ctx */ 1302 ActCtx.Size = sizeof(ActCtx); 1303 ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; 1304 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); 1305 1306 /* Activate the ActCtx */ 1307 RtlActivateActivationContextUnsafeFast(&ActCtx, 1308 LdrEntry->EntryPointActivationContext); 1309 1310 /* Update the load count */ 1311 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_DEREFCOUNT); 1312 1313 /* Release the context */ 1314 RtlDeactivateActivationContextUnsafeFast(&ActCtx); 1315 } 1316 } 1317 else 1318 { 1319 /* The DLL is locked */ 1320 goto Quickie; 1321 } 1322 1323 /* Show debug message */ 1324 if (ShowSnaps) DPRINT1("LDR: UNINIT LIST\n"); 1325 1326 /* Check if this is our only unload and initialize the list if so */ 1327 if (LdrpActiveUnloadCount == 1) InitializeListHead(&LdrpUnloadHead); 1328 1329 /* Loop the modules to build the list */ 1330 NextEntry = Peb->Ldr->InInitializationOrderModuleList.Blink; 1331 while (NextEntry != &Peb->Ldr->InInitializationOrderModuleList) 1332 { 1333 /* Get the entry */ 1334 LdrEntry = CONTAINING_RECORD(NextEntry, 1335 LDR_DATA_TABLE_ENTRY, 1336 InInitializationOrderModuleList); 1337 NextEntry = NextEntry->Blink; 1338 1339 /* Remove flag */ 1340 LdrEntry->Flags &= ~LDRP_UNLOAD_IN_PROGRESS; 1341 1342 /* If the load count is now 0 */ 1343 if (!LdrEntry->LoadCount) 1344 { 1345 /* Show message */ 1346 if (ShowSnaps) 1347 { 1348 DPRINT1("(%d) [%ws] %ws (%lx) deinit %lx\n", 1349 LdrpActiveUnloadCount, 1350 LdrEntry->BaseDllName.Buffer, 1351 LdrEntry->FullDllName.Buffer, 1352 (ULONG)LdrEntry->LoadCount, 1353 LdrEntry->EntryPoint); 1354 } 1355 1356 /* FIXME: Call Shim Engine and notify */ 1357 1358 /* Unlink it */ 1359 CurrentEntry = LdrEntry; 1360 RemoveEntryList(&CurrentEntry->InInitializationOrderModuleList); 1361 RemoveEntryList(&CurrentEntry->InMemoryOrderModuleList); 1362 RemoveEntryList(&CurrentEntry->HashLinks); 1363 1364 /* If there's more then one active unload */ 1365 if (LdrpActiveUnloadCount > 1) 1366 { 1367 /* Flush the cached DLL handle and clear the list */ 1368 LdrpLoadedDllHandleCache = NULL; 1369 CurrentEntry->InMemoryOrderModuleList.Flink = NULL; 1370 } 1371 1372 /* Add the entry on the unload list */ 1373 InsertTailList(&LdrpUnloadHead, &CurrentEntry->HashLinks); 1374 } 1375 } 1376 1377 /* Only call the entrypoints once */ 1378 if (LdrpActiveUnloadCount > 1) goto Quickie; 1379 1380 /* Now loop the unload list and create our own */ 1381 InitializeListHead(&UnloadList); 1382 CurrentEntry = NULL; 1383 NextEntry = LdrpUnloadHead.Flink; 1384 while (NextEntry != &LdrpUnloadHead) 1385 { 1386 /* Get the current entry */ 1387 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks); 1388 1389 /* FIXME: Log the Unload Event */ 1390 //LdrpRecordUnloadEvent(LdrEntry); 1391 1392 /* Set the entry and clear it from the list */ 1393 CurrentEntry = LdrEntry; 1394 LdrpLoadedDllHandleCache = NULL; 1395 CurrentEntry->InMemoryOrderModuleList.Flink = NULL; 1396 1397 /* Move it from the global to the local list */ 1398 RemoveEntryList(&CurrentEntry->HashLinks); 1399 InsertTailList(&UnloadList, &CurrentEntry->HashLinks); 1400 1401 /* Get the entrypoint */ 1402 EntryPoint = LdrEntry->EntryPoint; 1403 1404 /* Check if we should call it */ 1405 if ((EntryPoint) && (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED)) 1406 { 1407 /* Show message */ 1408 if (ShowSnaps) 1409 { 1410 DPRINT1("LDR: Calling deinit %lx\n", EntryPoint); 1411 } 1412 1413 /* Set up the Act Ctx */ 1414 ActCtx.Size = sizeof(ActCtx); 1415 ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; 1416 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); 1417 1418 /* Activate the ActCtx */ 1419 RtlActivateActivationContextUnsafeFast(&ActCtx, 1420 LdrEntry->EntryPointActivationContext); 1421 1422 /* Call the entrypoint */ 1423 LdrpCallInitRoutine(LdrEntry->EntryPoint, 1424 LdrEntry->DllBase, 1425 DLL_PROCESS_DETACH, 1426 NULL); 1427 1428 /* Release the context */ 1429 RtlDeactivateActivationContextUnsafeFast(&ActCtx); 1430 } 1431 1432 /* Remove it from the list */ 1433 RemoveEntryList(&CurrentEntry->InLoadOrderLinks); 1434 CurrentEntry = NULL; 1435 NextEntry = LdrpUnloadHead.Flink; 1436 } 1437 1438 /* Now loop our local list */ 1439 NextEntry = UnloadList.Flink; 1440 while (NextEntry != &UnloadList) 1441 { 1442 /* Get the entry */ 1443 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks); 1444 NextEntry = NextEntry->Flink; 1445 CurrentEntry = LdrEntry; 1446 1447 /* Notify Application Verifier */ 1448 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK) 1449 { 1450 DPRINT1("We don't support Application Verifier yet\n"); 1451 } 1452 1453 /* Show message */ 1454 if (ShowSnaps) 1455 { 1456 DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry->BaseDllName.Buffer); 1457 } 1458 1459 /* Check if this is a .NET executable */ 1460 CorImageData = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 1461 TRUE, 1462 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, 1463 &ComSectionSize); 1464 if (CorImageData) 1465 { 1466 /* FIXME */ 1467 DPRINT1(".NET Images are not supported yet\n"); 1468 } 1469 1470 /* Check if we should unmap*/ 1471 if (!(CurrentEntry->Flags & LDR_COR_OWNS_UNMAP)) 1472 { 1473 /* Unmap the DLL */ 1474 Status = NtUnmapViewOfSection(NtCurrentProcess(), 1475 CurrentEntry->DllBase); 1476 ASSERT(NT_SUCCESS(Status)); 1477 } 1478 1479 /* Unload the alternate resource module, if any */ 1480 LdrUnloadAlternateResourceModule(CurrentEntry->DllBase); 1481 1482 /* FIXME: Send shutdown notification */ 1483 //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress); 1484 1485 /* Check if a Hotpatch is active */ 1486 if (LdrEntry->PatchInformation) 1487 { 1488 /* FIXME */ 1489 DPRINT1("We don't support Hotpatching yet\n"); 1490 } 1491 1492 /* Deallocate the Entry */ 1493 LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry); 1494 1495 /* If this is the cached entry, invalidate it */ 1496 if (LdrpGetModuleHandleCache == CurrentEntry) 1497 { 1498 LdrpGetModuleHandleCache = NULL; 1499 } 1500 } 1501 1502 Quickie: 1503 /* Decrease unload count */ 1504 LdrpActiveUnloadCount--; 1505 if (!LdrpInLdrInit) RtlLeaveCriticalSection(Peb->LoaderLock); 1506 1507 /* Return to caller */ 1508 return Status; 1509 } 1510 1511 /* 1512 * @implemented 1513 */ 1514 BOOLEAN 1515 NTAPI 1516 RtlDllShutdownInProgress(VOID) 1517 { 1518 /* Return the internal global */ 1519 return LdrpShutdownInProgress; 1520 } 1521 1522 /* 1523 * @implemented 1524 */ 1525 PIMAGE_BASE_RELOCATION 1526 NTAPI 1527 LdrProcessRelocationBlock(IN ULONG_PTR Address, 1528 IN ULONG Count, 1529 IN PUSHORT TypeOffset, 1530 IN LONG_PTR Delta) 1531 { 1532 return LdrProcessRelocationBlockLongLong(Address, Count, TypeOffset, Delta); 1533 } 1534 1535 /* 1536 * @implemented 1537 */ 1538 BOOLEAN 1539 NTAPI 1540 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress) 1541 { 1542 ULONG_PTR Cookie; 1543 1544 /* Acquire the loader lock */ 1545 LdrLockLoaderLock(TRUE, NULL, &Cookie); 1546 1547 /* Check if there's any alternate resources loaded */ 1548 if (AlternateResourceModuleCount) 1549 { 1550 UNIMPLEMENTED; 1551 } 1552 1553 /* Release the loader lock */ 1554 LdrUnlockLoaderLock(1, Cookie); 1555 1556 /* All done */ 1557 return TRUE; 1558 } 1559 1560 /* FIXME: Add to ntstatus.mc */ 1561 #define STATUS_MUI_FILE_NOT_FOUND ((NTSTATUS)0xC00B0001L) 1562 1563 /* 1564 * @implemented 1565 */ 1566 NTSTATUS 1567 NTAPI 1568 LdrLoadAlternateResourceModule(IN PVOID Module, 1569 IN PWSTR Buffer) 1570 { 1571 /* Is MUI Support enabled? */ 1572 if (!LdrAlternateResourcesEnabled()) return STATUS_SUCCESS; 1573 1574 UNIMPLEMENTED; 1575 return STATUS_MUI_FILE_NOT_FOUND; 1576 } 1577 1578 /* EOF */ 1579