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