2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode Library
4 * FILE: dll/ntdll/ldr/ldrutils.c
5 * PURPOSE: Internal Loader Utility Functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
10 /* INCLUDES *****************************************************************/
16 /* GLOBALS *******************************************************************/
17 #define IMAGE_DLLCHARACTERISTICS_WX86_DLL 0x1000
19 LIST_ENTRY LdrpUnloadHead
;
20 PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache
;
21 PLDR_DATA_TABLE_ENTRY LdrpGetModuleHandleCache
;
23 #define LDR_GET_HASH_ENTRY(x) (RtlUpcaseUnicodeChar((x)) & (LDR_HASH_TABLE_ENTRIES - 1))
25 /* FUNCTIONS *****************************************************************/
29 LdrpCallDllEntry(PDLLMAIN_FUNC EntryPoint
,
35 return EntryPoint(BaseAddress
, Reason
, Context
);
40 LdrpUpdateLoadCount3(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
42 OUT PUNICODE_STRING UpdateString
)
44 PIMAGE_BOUND_FORWARDER_REF NewImportForwarder
;
47 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry
;
48 PIMAGE_IMPORT_DESCRIPTOR ImportEntry
;
49 PIMAGE_THUNK_DATA FirstThunk
;
50 PLDR_DATA_TABLE_ENTRY Entry
;
51 PUNICODE_STRING ImportNameUnic
;
52 ANSI_STRING ImportNameAnsi
;
58 /* Check the action we need to perform */
59 if (Flags
== LDRP_UPDATE_REFCOUNT
)
61 /* Make sure entry is not being loaded already */
62 if (LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
)
65 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
67 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
69 /* Make sure the entry is not being unloaded already */
70 if (LdrEntry
->Flags
& LDRP_UNLOAD_IN_PROGRESS
)
73 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
76 /* Go through all bound DLLs and dereference them */
77 ImportNameUnic
= &NtCurrentTeb()->StaticUnicodeString
;
79 /* Try to get the new import entry */
80 BoundEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
82 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
87 /* Set entry flags if refing/derefing */
88 if (Flags
== LDRP_UPDATE_REFCOUNT
)
89 LdrEntry
->Flags
|= LDRP_LOAD_IN_PROGRESS
;
90 else if (Flags
== LDRP_UPDATE_DEREFCOUNT
)
91 LdrEntry
->Flags
|= LDRP_UNLOAD_IN_PROGRESS
;
93 while (BoundEntry
->OffsetModuleName
)
95 /* Get pointer to the current import name */
96 ImportName
= (PCHAR
)BoundEntry
+ BoundEntry
->OffsetModuleName
;
98 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
99 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
101 if (NT_SUCCESS(Status
))
103 if (LdrpCheckForLoadedDll(NULL
,
109 if (Entry
->LoadCount
!= -1)
111 /* Perform the required action */
114 case LDRP_UPDATE_REFCOUNT
:
117 case LDRP_UPDATE_DEREFCOUNT
:
120 case LDRP_UPDATE_PIN
:
121 Entry
->LoadCount
= -1;
128 DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
132 /* Recurse into this entry */
133 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
137 /* Go through forwarders */
138 NewImportForwarder
= (PIMAGE_BOUND_FORWARDER_REF
)(BoundEntry
+ 1);
139 for (i
=0; i
<BoundEntry
->NumberOfModuleForwarderRefs
; i
++)
141 ImportName
= (PCHAR
)BoundEntry
+ NewImportForwarder
->OffsetModuleName
;
143 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
144 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
145 if (NT_SUCCESS(Status
))
147 if (LdrpCheckForLoadedDll(NULL
,
153 if (Entry
->LoadCount
!= -1)
155 /* Perform the required action */
158 case LDRP_UPDATE_REFCOUNT
:
161 case LDRP_UPDATE_DEREFCOUNT
:
164 case LDRP_UPDATE_PIN
:
165 Entry
->LoadCount
= -1;
172 DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
176 /* Recurse into this entry */
177 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
181 NewImportForwarder
++;
184 BoundEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)NewImportForwarder
;
191 /* Check oldstyle import descriptor */
192 ImportEntry
= (PIMAGE_IMPORT_DESCRIPTOR
)RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
194 IMAGE_DIRECTORY_ENTRY_IMPORT
,
198 /* There is old one, so go through its entries */
199 while (ImportEntry
->Name
&& ImportEntry
->FirstThunk
)
201 FirstThunk
= (PIMAGE_THUNK_DATA
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->FirstThunk
);
203 /* Skip this entry if needed */
204 if (!FirstThunk
->u1
.Function
)
210 ImportName
= (PSZ
)((ULONG_PTR
)LdrEntry
->DllBase
+ ImportEntry
->Name
);
212 RtlInitAnsiString(&ImportNameAnsi
, ImportName
);
213 Status
= RtlAnsiStringToUnicodeString(ImportNameUnic
, &ImportNameAnsi
, FALSE
);
214 if (NT_SUCCESS(Status
))
216 if (LdrpCheckForLoadedDll(NULL
,
222 if (Entry
->LoadCount
!= -1)
224 /* Perform the required action */
227 case LDRP_UPDATE_REFCOUNT
:
230 case LDRP_UPDATE_DEREFCOUNT
:
233 case LDRP_UPDATE_PIN
:
234 Entry
->LoadCount
= -1;
241 DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags
, ImportNameUnic
, Entry
->LoadCount
);
246 LdrpUpdateLoadCount3(Entry
, Flags
, UpdateString
);
250 /* Go to the next entry */
258 LdrpUpdateLoadCount2(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
261 WCHAR Buffer
[MAX_PATH
];
262 UNICODE_STRING UpdateString
;
264 /* Setup the string */
265 UpdateString
.Buffer
= Buffer
;
266 UpdateString
.Length
= 0;
267 UpdateString
.MaximumLength
= sizeof(Buffer
);
269 /* Call the extended API */
270 LdrpUpdateLoadCount3(LdrEntry
, Flags
, &UpdateString
);
275 LdrpTlsCallback(PVOID BaseAddress
, ULONG Reason
)
277 PIMAGE_TLS_DIRECTORY TlsDirectory
;
278 PIMAGE_TLS_CALLBACK
*Array
, Callback
;
281 /* Get the TLS Directory */
282 TlsDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
284 IMAGE_DIRECTORY_ENTRY_TLS
,
287 /* Protect against invalid pointers */
290 /* Make sure it's valid and we have an array */
291 if (TlsDirectory
&& (Array
= (PIMAGE_TLS_CALLBACK
*)TlsDirectory
->AddressOfCallBacks
))
296 DPRINT1("LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n",
297 BaseAddress
, TlsDirectory
, Array
);
303 /* Get the TLS Entrypoint */
309 DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n",
310 BaseAddress
, Callback
);
314 LdrpCallDllEntry((PDLLMAIN_FUNC
)Callback
, BaseAddress
, Reason
, NULL
);
318 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
327 LdrpCodeAuthzCheckDllAllowed(PUNICODE_STRING FullName
,
330 return STATUS_SUCCESS
;
335 LdrpCreateDllSection(IN PUNICODE_STRING FullName
,
337 IN PULONG DllCharacteristics OPTIONAL
,
338 OUT PHANDLE SectionHandle
)
342 OBJECT_ATTRIBUTES ObjectAttributes
;
343 IO_STATUS_BLOCK IoStatusBlock
;
344 ULONG_PTR HardErrorParameters
[1];
346 SECTION_IMAGE_INFORMATION SectionImageInfo
;
348 /* Check if we don't already have a handle */
351 /* Create the object attributes */
352 InitializeObjectAttributes(&ObjectAttributes
,
354 OBJ_CASE_INSENSITIVE
,
359 Status
= NtOpenFile(&FileHandle
,
360 SYNCHRONIZE
| FILE_EXECUTE
| FILE_READ_DATA
,
363 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
364 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
366 /* Check if we failed */
367 if (!NT_SUCCESS(Status
))
369 /* Attempt to open for execute only */
370 Status
= NtOpenFile(&FileHandle
,
371 SYNCHRONIZE
| FILE_EXECUTE
,
374 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
375 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
377 /* Check if this failed too */
378 if (!NT_SUCCESS(Status
))
380 /* Show debug message */
383 DPRINT1("LDR: LdrpCreateDllSection - NtOpenFile failed; status = %x\n",
387 /* Make sure to return an expected status code */
388 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
390 /* Callers expect this instead */
391 Status
= STATUS_DLL_NOT_FOUND
;
394 /* Return an empty section handle */
395 *SectionHandle
= NULL
;
402 /* Use the handle we already have */
403 FileHandle
= DllHandle
;
406 /* Create a section for the DLL */
407 Status
= NtCreateSection(SectionHandle
,
408 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
|
409 SECTION_MAP_WRITE
| SECTION_QUERY
,
416 /* If mapping failed, raise a hard error */
417 if (!NT_SUCCESS(Status
))
419 /* Forget the handle */
420 *SectionHandle
= NULL
;
422 /* Give the DLL name */
423 HardErrorParameters
[0] = (ULONG_PTR
)FullName
;
425 /* Raise the error */
426 ZwRaiseHardError(STATUS_INVALID_IMAGE_FORMAT
,
433 /* Increment the error count */
434 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
437 /* Check for Safer restrictions */
438 if (DllCharacteristics
&&
439 !(*DllCharacteristics
& IMAGE_DLLCHARACTERISTICS_WX86_DLL
))
441 /* Make sure it's executable */
442 Status
= ZwQuerySection(*SectionHandle
,
443 SectionImageInformation
,
445 sizeof(SECTION_IMAGE_INFORMATION
),
447 if (NT_SUCCESS(Status
))
449 /* Check if it's executable */
450 if (SectionImageInfo
.ImageContainsCode
)
452 /* It is, check safer */
453 Status
= LdrpCodeAuthzCheckDllAllowed(FullName
, DllHandle
);
454 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_NOT_FOUND
))
456 /* Show debug message */
459 DPRINT1("LDR: Loading of (%wZ) blocked by Winsafer\n",
465 /* We're fine, return normally */
471 /* Failure case, close section handle */
472 NtClose(*SectionHandle
);
473 *SectionHandle
= NULL
;
477 /* Close the file handle, we don't need it */
486 LdrpResolveDllName(PWSTR DllPath
,
488 PUNICODE_STRING FullDllName
,
489 PUNICODE_STRING BaseDllName
)
491 PWCHAR NameBuffer
, p1
, p2
= 0;
495 /* Allocate space for full DLL name */
496 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufSize
+ sizeof(UNICODE_NULL
));
497 if (!FullDllName
->Buffer
) return FALSE
;
499 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
504 &BaseDllName
->Buffer
);
506 if (!Length
|| Length
> BufSize
)
510 DPRINT1("LDR: LdrResolveDllName - Unable to find ");
511 DPRINT1("%ws from %ws\n", DllName
, DllPath
? DllPath
: LdrpDefaultPath
.Buffer
);
514 RtlFreeUnicodeString(FullDllName
);
518 /* Construct full DLL name */
519 FullDllName
->Length
= Length
;
520 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
522 /* Allocate a new buffer */
523 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
526 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
530 /* Copy over the contents from the previous one and free it */
531 RtlCopyMemory(NameBuffer
, FullDllName
->Buffer
, FullDllName
->MaximumLength
);
532 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
533 FullDllName
->Buffer
= NameBuffer
;
535 /* Find last backslash */
536 p1
= FullDllName
->Buffer
;
545 /* If found, set p1 to it, otherwise p1 points to the beginning of DllName */
553 /* Calculate remaining length */
556 /* Construct base DLL name */
557 BaseDllName
->Length
= (ULONG_PTR
)p1
- (ULONG_PTR
)p2
;
558 BaseDllName
->MaximumLength
= BaseDllName
->Length
+ sizeof(UNICODE_NULL
);
559 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BaseDllName
->MaximumLength
);
561 if (!BaseDllName
->Buffer
)
563 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
567 /* Copy base dll name to the new buffer */
568 RtlMoveMemory(BaseDllName
->Buffer
,
570 BaseDllName
->Length
);
572 /* Null-terminate the string */
573 BaseDllName
->Buffer
[BaseDllName
->Length
/ sizeof(WCHAR
)] = 0;
580 LdrpFetchAddressOfEntryPoint(PVOID ImageBase
)
582 PIMAGE_NT_HEADERS NtHeaders
;
583 ULONG_PTR EntryPoint
;
585 /* Get entry point offset from NT headers */
586 NtHeaders
= RtlImageNtHeader(ImageBase
);
587 EntryPoint
= NtHeaders
->OptionalHeader
.AddressOfEntryPoint
;
589 /* If it's 0 - return so */
590 if (!EntryPoint
) return NULL
;
593 EntryPoint
+= (ULONG_PTR
)ImageBase
;
595 /* Return calculated pointer */
596 return (PVOID
)EntryPoint
;
601 LdrpCheckForKnownDll(PWSTR DllName
,
602 PUNICODE_STRING FullDllName
,
603 PUNICODE_STRING BaseDllName
)
605 OBJECT_ATTRIBUTES ObjectAttributes
;
606 HANDLE Section
= NULL
;
607 UNICODE_STRING DllNameUnic
;
612 /* Upgrade DllName to a unicode string */
613 RtlInitUnicodeString(&DllNameUnic
, DllName
);
615 /* Get the activation context */
616 Status
= RtlFindActivationContextSectionString(0,
618 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
622 /* Check if it's a SxS or not */
623 if (Status
== STATUS_SXS_SECTION_NOT_FOUND
||
624 Status
== STATUS_SXS_KEY_NOT_FOUND
)
626 /* Set up BaseDllName */
627 BaseDllName
->Length
= DllNameUnic
.Length
;
628 BaseDllName
->MaximumLength
= DllNameUnic
.MaximumLength
;
629 BaseDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
631 DllNameUnic
.MaximumLength
);
632 if (!BaseDllName
->Buffer
) return NULL
;
634 /* Copy the contents there */
635 RtlMoveMemory(BaseDllName
->Buffer
, DllNameUnic
.Buffer
, DllNameUnic
.MaximumLength
);
637 /* Set up FullDllName */
638 FullDllName
->Length
= LdrpKnownDllPath
.Length
+ BaseDllName
->Length
+ sizeof(WCHAR
);
639 FullDllName
->MaximumLength
= FullDllName
->Length
+ sizeof(UNICODE_NULL
);
640 FullDllName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName
->MaximumLength
);
641 if (!FullDllName
->Buffer
)
643 /* Free base name and fail */
644 RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName
->Buffer
);
648 RtlMoveMemory(FullDllName
->Buffer
, LdrpKnownDllPath
.Buffer
, LdrpKnownDllPath
.Length
);
650 /* Put a slash there */
651 p1
= (PCHAR
)FullDllName
->Buffer
+ LdrpKnownDllPath
.Length
;
656 /* Set up DllNameUnic for a relative path */
657 DllNameUnic
.Buffer
= (PWSTR
)p1
;
658 DllNameUnic
.Length
= BaseDllName
->Length
;
659 DllNameUnic
.MaximumLength
= DllNameUnic
.Length
+ sizeof(UNICODE_NULL
);
661 /* Copy the contents */
662 RtlMoveMemory(p1
, BaseDllName
->Buffer
, BaseDllName
->MaximumLength
);
664 /* There are all names, init attributes and open the section */
665 InitializeObjectAttributes(&ObjectAttributes
,
667 OBJ_CASE_INSENSITIVE
,
668 LdrpKnownDllObjectDirectory
,
671 Status
= NtOpenSection(&Section
,
672 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
| SECTION_MAP_WRITE
,
674 if (!NT_SUCCESS(Status
))
676 /* Opening failed, free resources */
678 RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName
->Buffer
);
679 RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName
->Buffer
);
684 if (!NT_SUCCESS(Status
)) Section
= NULL
;
687 /* Return section handle */
693 LdrpSetProtection(PVOID ViewBase
,
696 PIMAGE_NT_HEADERS NtHeaders
;
697 PIMAGE_SECTION_HEADER Section
;
701 ULONG NewProtection
, OldProtection
, i
;
703 /* Get the NT headers */
704 NtHeaders
= RtlImageNtHeader(ViewBase
);
706 /* Compute address of the first section header */
707 Section
= (PIMAGE_SECTION_HEADER
)(
708 (ULONG_PTR
)NtHeaders
+ sizeof(ULONG
) + sizeof(IMAGE_FILE_HEADER
) +
709 NtHeaders
->FileHeader
.SizeOfOptionalHeader
);
711 /* Go through all sections */
712 for (i
= 0; i
< NtHeaders
->FileHeader
.NumberOfSections
; i
++)
714 if (Section
->SizeOfRawData
&&
715 !(Section
->Characteristics
& IMAGE_SCN_MEM_WRITE
))
717 /* This section is not writable and has some size, so we need to change
721 /* Set it to either EXECUTE or READONLY */
722 if (Section
->Characteristics
& IMAGE_SCN_MEM_EXECUTE
)
723 NewProtection
= PAGE_EXECUTE
;
725 NewProtection
= PAGE_READONLY
;
727 /* Add PAGE_NOCACHE if needed */
728 if (Section
->Characteristics
& IMAGE_SCN_MEM_NOT_CACHED
)
729 NewProtection
|= PAGE_NOCACHE
;
733 /* Enable write access */
734 NewProtection
= PAGE_READWRITE
;
737 SectionBase
= (PVOID
)((ULONG_PTR
)ViewBase
+ Section
->VirtualAddress
);
738 SectionSize
= Section
->SizeOfRawData
;
743 Status
= ZwProtectVirtualMemory(NtCurrentProcess(),
749 if (!NT_SUCCESS(Status
)) return Status
;
753 /* Move to the next section */
757 /* Flush instruction cache if necessary */
758 if (Restore
) ZwFlushInstructionCache(NtCurrentProcess(), NULL
, 0);
760 return STATUS_SUCCESS
;
765 LdrpMapDll(IN PWSTR SearchPath OPTIONAL
,
767 IN PWSTR DllName OPTIONAL
,
768 IN PULONG DllCharacteristics
,
771 OUT PLDR_DATA_TABLE_ENTRY
*DataTableEntry
)
773 PTEB Teb
= NtCurrentTeb();
774 PPEB Peb
= NtCurrentPeb();
777 BOOLEAN KnownDll
= FALSE
;
778 UNICODE_STRING FullDllName
, BaseDllName
;
779 HANDLE SectionHandle
= NULL
, DllHandle
= 0;
780 UNICODE_STRING NtPathDllName
;
781 ULONG_PTR HardErrorParameters
[2];
782 UNICODE_STRING HardErrorDllName
, HardErrorDllPath
;
785 PVOID ViewBase
= NULL
;
786 PVOID ArbitraryUserPointer
;
787 PIMAGE_NT_HEADERS NtHeaders
;
788 NTSTATUS HardErrorStatus
, Status
;
789 BOOLEAN OverlapDllFound
= FALSE
;
790 ULONG_PTR ImageBase
, ImageEnd
;
791 PLIST_ENTRY ListHead
, NextEntry
;
792 PLDR_DATA_TABLE_ENTRY CandidateEntry
, LdrEntry
;
793 ULONG_PTR CandidateBase
, CandidateEnd
;
794 UNICODE_STRING OverlapDll
;
795 BOOLEAN RelocatableDll
= TRUE
;
796 UNICODE_STRING IllegalDll
;
798 ULONG RelocDataSize
= 0;
800 // FIXME: AppCompat stuff is missing
804 DPRINT1("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n",
806 SearchPath
? SearchPath
: L
"");
809 /* Check if we have a known dll directory */
810 if (LdrpKnownDllObjectDirectory
)
812 /* Check if the path is full */
816 if (TempChar
== '\\' || TempChar
== '/' )
818 /* Complete path, don't do Known Dll lookup */
823 /* Try to find a Known DLL */
824 SectionHandle
= LdrpCheckForKnownDll(DllName
,
831 /* Check if the Known DLL Check returned something */
834 /* It didn't, so try to resolve the name now */
835 if (LdrpResolveDllName(SearchPath
,
840 /* Got a name, display a message */
843 DPRINT1("LDR: Loading (%s) %wZ\n",
844 Static
? "STATIC" : "DYNAMIC",
848 /* Convert to NT Name */
849 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
854 /* Path was invalid */
855 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
858 /* Create a section for this dLL */
859 Status
= LdrpCreateDllSection(&NtPathDllName
,
864 /* Free the NT Name */
865 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathDllName
.Buffer
);
868 if (!NT_SUCCESS(Status
))
870 /* Free the name strings and return */
871 RtlFreeUnicodeString(&FullDllName
);
872 RtlFreeUnicodeString(&BaseDllName
);
878 /* We couldn't resolve the name, is this a static load? */
882 * This is BAD! Static loads are CRITICAL. Bugcheck!
883 * Initialize the strings for the error
885 RtlInitUnicodeString(&HardErrorDllName
, DllName
);
886 RtlInitUnicodeString(&HardErrorDllPath
,
887 DllPath2
? DllPath2
: LdrpDefaultPath
.Buffer
);
889 /* Set them as error parameters */
890 HardErrorParameters
[0] = (ULONG_PTR
)&HardErrorDllName
;
891 HardErrorParameters
[1] = (ULONG_PTR
)&HardErrorDllPath
;
893 /* Raise the hard error */
894 NtRaiseHardError(STATUS_DLL_NOT_FOUND
,
901 /* We're back, where we initializing? */
902 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
906 return STATUS_DLL_NOT_FOUND
;
911 /* We have a section handle, so this is a known dll */
915 /* Stuff the image name in the TIB, for the debugger */
916 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
917 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
922 Status
= NtMapViewOfSection(SectionHandle
,
934 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
936 /* Fail if we couldn't map it */
937 if (!NT_SUCCESS(Status
))
939 /* Close and return */
940 NtClose(SectionHandle
);
944 /* Get the NT Header */
945 if (!(NtHeaders
= RtlImageNtHeader(ViewBase
)))
947 /* Invalid image, unmap, close handle and fail */
948 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
949 NtClose(SectionHandle
);
950 return STATUS_INVALID_IMAGE_FORMAT
;
953 // FIXME: .NET support is missing
955 /* Allocate an entry */
956 if (!(LdrEntry
= LdrpAllocateDataTableEntry(ViewBase
)))
958 /* Invalid image, unmap, close handle and fail */
959 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
960 NtClose(SectionHandle
);
961 return STATUS_NO_MEMORY
;
964 /* Setup the entry */
965 LdrEntry
->Flags
= Static
? LDRP_STATIC_LINK
: 0;
966 if (Redirect
) LdrEntry
->Flags
|= LDRP_REDIRECTED
;
967 LdrEntry
->LoadCount
= 0;
968 LdrEntry
->FullDllName
= FullDllName
;
969 LdrEntry
->BaseDllName
= BaseDllName
;
970 LdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(LdrEntry
->DllBase
);
972 /* Show debug message */
975 DPRINT1("LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n",
980 /* Insert this entry */
981 LdrpInsertMemoryTableEntry(LdrEntry
);
983 // LdrpSendDllNotifications(LdrEntry, TRUE, Status == STATUS_IMAGE_NOT_AT_BASE)
985 /* Check for invalid CPU Image */
986 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
988 /* Load our header */
989 PIMAGE_NT_HEADERS ImageNtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
991 /* Assume defaults if we don't have to run the Hard Error path */
992 HardErrorStatus
= STATUS_SUCCESS
;
993 Response
= ResponseCancel
;
995 /* Are we an NT 3.0 image? [Do these still exist? LOL -- IAI] */
996 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
998 /* Reset the entrypoint, save our Dll Name */
999 LdrEntry
->EntryPoint
= 0;
1000 HardErrorParameters
[0] = (ULONG_PTR
)&FullDllName
;
1002 /* Raise the error */
1003 HardErrorStatus
= ZwRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH
,
1006 HardErrorParameters
,
1011 /* Check if the user pressed cancel */
1012 if (NT_SUCCESS(HardErrorStatus
) && Response
== ResponseCancel
)
1014 /* Remove the DLL from the lists */
1015 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1016 RemoveEntryList(&LdrEntry
->InMemoryOrderModuleList
);
1017 RemoveEntryList(&LdrEntry
->HashLinks
);
1019 /* Remove the LDR Entry */
1020 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrEntry
);
1022 /* Unmap and close section */
1023 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1024 NtClose(SectionHandle
);
1026 /* Did we do a hard error? */
1027 if (ImageNtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3)
1029 /* Yup, so increase fatal error count if we are initializing */
1030 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1033 /* Return failure */
1034 return STATUS_INVALID_IMAGE_FORMAT
;
1039 /* The image was valid. Is it a DLL? */
1040 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
1042 /* Set the DLL Flag */
1043 LdrEntry
->Flags
|= LDRP_IMAGE_DLL
;
1046 /* If we're not a DLL, clear the entrypoint */
1047 if (!(LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
1049 LdrEntry
->EntryPoint
= 0;
1053 /* Return it for the caller */
1054 *DataTableEntry
= LdrEntry
;
1056 /* Check if we loaded somewhere else */
1057 if (Status
== STATUS_IMAGE_NOT_AT_BASE
)
1059 /* Write the flag */
1060 LdrEntry
->Flags
|= LDRP_IMAGE_NOT_AT_BASE
;
1062 /* Find our region */
1063 ImageBase
= (ULONG_PTR
)NtHeaders
->OptionalHeader
.ImageBase
;
1064 ImageEnd
= ImageBase
+ ViewSize
;
1066 DPRINT1("LDR: LdrpMapDll Relocating Image Name %ws (%p -> %p)\n", DllName
, ImageBase
, ViewBase
);
1068 /* Scan all the modules */
1069 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
1070 NextEntry
= ListHead
->Flink
;
1071 while (NextEntry
!= ListHead
)
1074 CandidateEntry
= CONTAINING_RECORD(NextEntry
,
1075 LDR_DATA_TABLE_ENTRY
,
1077 NextEntry
= NextEntry
->Flink
;
1079 /* Get the entry's bounds */
1080 CandidateBase
= (ULONG_PTR
)CandidateEntry
->DllBase
;
1081 CandidateEnd
= CandidateBase
+ CandidateEntry
->SizeOfImage
;
1083 /* Make sure this entry isn't unloading */
1084 if (!CandidateEntry
->InMemoryOrderModuleList
.Flink
) continue;
1086 /* Check if our regions are colliding */
1087 if ((ImageBase
>= CandidateBase
&& ImageBase
<= CandidateEnd
) ||
1088 (ImageEnd
>= CandidateBase
&& ImageEnd
<= CandidateEnd
) ||
1089 (CandidateBase
>= ImageBase
&& CandidateBase
<= ImageEnd
))
1091 /* Found who is overlapping */
1092 OverlapDllFound
= TRUE
;
1093 OverlapDll
= CandidateEntry
->FullDllName
;
1098 /* Check if we found the DLL overlapping with us */
1099 if (!OverlapDllFound
)
1101 /* It's not another DLL, it's memory already here */
1102 RtlInitUnicodeString(&OverlapDll
, L
"Dynamically Allocated Memory");
1105 DPRINT1("Overlapping DLL: %wZ\n", &OverlapDll
);
1107 /* Are we dealing with a DLL? */
1108 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1110 /* Check if relocs were stripped */
1111 if (!(NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
))
1113 /* Get the relocation data */
1114 RelocData
= RtlImageDirectoryEntryToData(ViewBase
,
1116 IMAGE_DIRECTORY_ENTRY_BASERELOC
,
1119 /* Does the DLL not have any? */
1120 if (!RelocData
&& !RelocDataSize
)
1122 /* We'll allow this and simply continue */
1127 /* See if this is an Illegal DLL - IE: user32 and kernel32 */
1128 RtlInitUnicodeString(&IllegalDll
,L
"user32.dll");
1129 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1131 /* Can't relocate user32 */
1132 RelocatableDll
= FALSE
;
1136 RtlInitUnicodeString(&IllegalDll
, L
"kernel32.dll");
1137 if (RtlEqualUnicodeString(&BaseDllName
, &IllegalDll
, TRUE
))
1139 /* Can't relocate kernel32 */
1140 RelocatableDll
= FALSE
;
1144 /* Check if this was a non-relocatable DLL or a known dll */
1145 if (!RelocatableDll
&& KnownDll
)
1147 /* Setup for hard error */
1148 HardErrorParameters
[0] = (ULONG_PTR
)&IllegalDll
;
1149 HardErrorParameters
[1] = (ULONG_PTR
)&OverlapDll
;
1151 /* Raise the error */
1152 ZwRaiseHardError(STATUS_ILLEGAL_DLL_RELOCATION
,
1155 HardErrorParameters
,
1159 /* If initializing, increase the error count */
1160 if (LdrpInLdrInit
) LdrpFatalHardErrorCount
++;
1162 /* Don't do relocation */
1163 Status
= STATUS_CONFLICTING_ADDRESSES
;
1167 /* Change the protection to prepare for relocation */
1168 Status
= LdrpSetProtection(ViewBase
, FALSE
);
1170 /* Make sure we changed the protection */
1171 if (NT_SUCCESS(Status
))
1173 /* Do the relocation */
1174 Status
= LdrRelocateImageWithBias(ViewBase
, 0LL, NULL
, STATUS_SUCCESS
,
1175 STATUS_CONFLICTING_ADDRESSES
, STATUS_INVALID_IMAGE_FORMAT
);
1177 if (NT_SUCCESS(Status
))
1179 /* Stuff the image name in the TIB, for the debugger */
1180 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1181 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1184 Status
= NtMapViewOfSection(SectionHandle
,
1196 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1198 /* Return the protection */
1199 Status
= LdrpSetProtection(ViewBase
, TRUE
);
1203 /* Handle any kind of failure */
1204 if (!NT_SUCCESS(Status
))
1206 /* Remove it from the lists */
1207 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
1208 RemoveEntryList(&LdrEntry
->InMemoryOrderModuleList
);
1209 RemoveEntryList(&LdrEntry
->HashLinks
);
1211 /* Unmap it, clear the entry */
1212 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1216 /* Show debug message */
1219 DPRINT1("LDR: Fixups %successfully re-applied @ %p\n",
1220 NT_SUCCESS(Status
) ? "s" : "uns", ViewBase
);
1226 /* Not a DLL, or no relocation needed */
1227 Status
= STATUS_SUCCESS
;
1229 /* Stuff the image name in the TIB, for the debugger */
1230 ArbitraryUserPointer
= Teb
->NtTib
.ArbitraryUserPointer
;
1231 Teb
->NtTib
.ArbitraryUserPointer
= FullDllName
.Buffer
;
1234 Status
= NtMapViewOfSection(SectionHandle
,
1246 Teb
->NtTib
.ArbitraryUserPointer
= ArbitraryUserPointer
;
1248 /* Show debug message */
1251 DPRINT1("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase
);
1256 // FIXME: LdrpCheckCorImage() is missing
1258 /* Check if this is an SMP Machine and a DLL */
1259 if ((LdrpNumberOfProcessors
> 1) &&
1260 (LdrEntry
&& (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)))
1262 /* Validate the image for MP */
1263 LdrpValidateImageForMp(LdrEntry
);
1266 // FIXME: LdrpCorUnloadImage() is missing
1268 /* Close section and return status */
1269 NtClose(SectionHandle
);
1273 PLDR_DATA_TABLE_ENTRY
1275 LdrpAllocateDataTableEntry(IN PVOID BaseAddress
)
1277 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1278 PIMAGE_NT_HEADERS NtHeader
= RtlImageNtHeader(BaseAddress
);
1280 DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress
, NtHeader
);
1282 /* Make sure the header is valid */
1285 /* Allocate an entry */
1286 LdrEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
1288 sizeof(LDR_DATA_TABLE_ENTRY
));
1290 /* Make sure we got one */
1294 LdrEntry
->DllBase
= BaseAddress
;
1295 LdrEntry
->SizeOfImage
= NtHeader
->OptionalHeader
.SizeOfImage
;
1296 LdrEntry
->TimeDateStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
1300 /* Return the entry */
1306 LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1308 PPEB_LDR_DATA PebData
= NtCurrentPeb()->Ldr
;
1311 /* Get the Hash entry */
1312 i
= LDR_GET_HASH_ENTRY(LdrEntry
->BaseDllName
.Buffer
[0]);
1314 InsertTailList(&LdrpHashTable
[i
], &LdrEntry
->HashLinks
);
1315 InsertTailList(&PebData
->InLoadOrderModuleList
, &LdrEntry
->InLoadOrderLinks
);
1316 InsertTailList(&PebData
->InMemoryOrderModuleList
, &LdrEntry
->InMemoryOrderModuleList
);
1321 LdrpFinalizeAndDeallocateDataTableEntry(PLDR_DATA_TABLE_ENTRY Entry
)
1323 ASSERT(Entry
!= NULL
);
1325 /* Release the activation context if it exists */
1326 if (Entry
->EntryPointActivationContext
)
1328 /* Check if it wasn't already released */
1329 if ((HANDLE
)Entry
->EntryPointActivationContext
!= INVALID_HANDLE_VALUE
)
1331 RtlReleaseActivationContext(Entry
->EntryPointActivationContext
);
1333 /* Mark it as invalid */
1334 Entry
->EntryPointActivationContext
= INVALID_HANDLE_VALUE
;
1338 /* Release the full dll name string */
1339 if (Entry
->FullDllName
.Buffer
)
1340 LdrpFreeUnicodeString(&Entry
->FullDllName
);
1342 /* Finally free the entry's memory */
1343 RtlFreeHeap(RtlGetProcessHeap(), 0, Entry
);
1348 LdrpCheckForLoadedDllHandle(IN PVOID Base
,
1349 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1351 PLDR_DATA_TABLE_ENTRY Current
;
1352 PLIST_ENTRY ListHead
, Next
;
1354 /* Check the cache first */
1355 if (LdrpLoadedDllHandleCache
&& LdrpLoadedDllHandleCache
->DllBase
== Base
)
1357 /* We got lucky, return the cached entry */
1358 *LdrEntry
= LdrpLoadedDllHandleCache
;
1362 /* Time for a lookup */
1363 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1364 Next
= ListHead
->Flink
;
1365 while(Next
!= ListHead
)
1367 /* Get the current entry */
1368 Current
= CONTAINING_RECORD(Next
,
1369 LDR_DATA_TABLE_ENTRY
,
1372 /* Make sure it's not unloading and check for a match */
1373 if ((Current
->InMemoryOrderModuleList
.Flink
) && (Base
== Current
->DllBase
))
1376 LdrpLoadedDllHandleCache
= Current
;
1379 *LdrEntry
= Current
;
1383 /* Move to the next one */
1393 LdrpCheckForLoadedDll(IN PWSTR DllPath
,
1394 IN PUNICODE_STRING DllName
,
1396 IN BOOLEAN RedirectedDll
,
1397 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
1400 PLIST_ENTRY ListHead
, ListEntry
;
1401 PLDR_DATA_TABLE_ENTRY CurEntry
;
1402 BOOLEAN FullPath
= FALSE
;
1405 UNICODE_STRING FullDllName
, NtPathName
;
1407 OBJECT_ATTRIBUTES ObjectAttributes
;
1409 HANDLE FileHandle
, SectionHandle
;
1410 IO_STATUS_BLOCK Iosb
;
1411 PVOID ViewBase
= NULL
;
1412 SIZE_T ViewSize
= 0;
1413 PIMAGE_NT_HEADERS NtHeader
, NtHeader2
;
1415 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath
, DllName
, Flag
, RedirectedDll
, LdrEntry
);
1417 /* Check if a dll name was provided */
1418 if (!DllName
->Buffer
|| !DllName
->Buffer
[0]) return FALSE
;
1420 /* Look in the hash table if flag was set */
1424 /* Get hash index */
1425 HashIndex
= LDR_GET_HASH_ENTRY(DllName
->Buffer
[0]);
1427 /* Traverse that list */
1428 ListHead
= &LdrpHashTable
[HashIndex
];
1429 ListEntry
= ListHead
->Flink
;
1430 while (ListEntry
!= ListHead
)
1432 /* Get the current entry */
1433 CurEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1435 /* Check base name of that module */
1436 if (RtlEqualUnicodeString(DllName
, &CurEntry
->BaseDllName
, TRUE
))
1438 /* It matches, return it */
1439 *LdrEntry
= CurEntry
;
1443 /* Advance to the next entry */
1444 ListEntry
= ListEntry
->Flink
;
1447 /* Module was not found, return failure */
1451 /* Check if there is a full path in this DLL */
1452 wc
= DllName
->Buffer
;
1455 /* Check for a slash in the current position*/
1456 if (*wc
== L
'\\' || *wc
== L
'/')
1458 /* Found the slash, so dll name contains path */
1461 /* Setup full dll name string */
1462 FullDllName
.Buffer
= NameBuf
;
1464 Length
= RtlDosSearchPath_U(DllPath
? DllPath
: LdrpDefaultPath
.Buffer
,
1467 sizeof(NameBuf
) - sizeof(UNICODE_NULL
),
1471 /* Check if that was successful */
1472 if (!Length
|| Length
> sizeof(NameBuf
) - sizeof(UNICODE_NULL
))
1476 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %ws: 0x%08x\n",
1477 DllName
->Buffer
, Length
);
1480 /* Return failure */
1484 /* Full dll name is found */
1485 FullDllName
.Length
= Length
;
1486 FullDllName
.MaximumLength
= FullDllName
.Length
+ sizeof(UNICODE_NULL
);
1493 /* Go check the hash table */
1500 /* Now go through the InLoadOrder module list */
1501 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1502 ListEntry
= ListHead
->Flink
;
1504 while (ListEntry
!= ListHead
)
1506 /* Get the containing record of the current entry and advance to the next one */
1507 CurEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1508 ListEntry
= ListEntry
->Flink
;
1510 /* Check if it's already being unloaded */
1511 if (!CurEntry
->InMemoryOrderModuleList
.Flink
) continue;
1513 /* Check if name matches */
1514 if (RtlEqualUnicodeString(&FullDllName
,
1515 &CurEntry
->FullDllName
,
1519 *LdrEntry
= CurEntry
;
1521 /* Find activation context */
1522 Status
= RtlFindActivationContextSectionString(0, NULL
, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
, DllName
, NULL
);
1523 if (!NT_SUCCESS(Status
))
1530 /* The DLL was not found in the load order modules list. Perform a complex check */
1532 /* Convert given path to NT path */
1533 if (!RtlDosPathNameToNtPathName_U(FullDllName
.Buffer
,
1538 /* Fail if conversion failed */
1542 /* Initialize object attributes and open it */
1543 InitializeObjectAttributes(&ObjectAttributes
,
1545 OBJ_CASE_INSENSITIVE
,
1549 Status
= NtOpenFile(&FileHandle
,
1550 SYNCHRONIZE
| FILE_EXECUTE
,
1553 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1554 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
1556 /* Free NT path name */
1557 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
1559 /* If opening the file failed - return failure */
1560 if (!NT_SUCCESS(Status
)) return FALSE
;
1562 /* Create a section for this file */
1563 Status
= NtCreateSection(&SectionHandle
,
1564 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
| SECTION_MAP_WRITE
,
1571 /* Close file handle */
1572 NtClose(FileHandle
);
1574 /* If creating section failed - return failure */
1575 if (!NT_SUCCESS(Status
)) return FALSE
;
1577 /* Map view of this section */
1578 Status
= ZwMapViewOfSection(SectionHandle
,
1588 /* Close section handle */
1589 NtClose(SectionHandle
);
1591 /* If section mapping failed - return failure */
1592 if (!NT_SUCCESS(Status
)) return FALSE
;
1594 /* Get pointer to the NT header of this section */
1595 NtHeader
= RtlImageNtHeader(ViewBase
);
1598 /* Unmap the section and fail */
1599 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1603 /* Go through the list of modules */
1604 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1605 ListEntry
= ListHead
->Flink
;
1607 while (ListEntry
!= ListHead
)
1609 CurEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1610 ListEntry
= ListEntry
->Flink
;
1612 /* Check if it's already being unloaded */
1613 if (!CurEntry
->InMemoryOrderModuleList
.Flink
) continue;
1617 /* Check if timedate stamp and sizes match */
1618 if (CurEntry
->TimeDateStamp
== NtHeader
->FileHeader
.TimeDateStamp
&&
1619 CurEntry
->SizeOfImage
== NtHeader
->OptionalHeader
.SizeOfImage
)
1621 /* Time, date and size match. Let's compare their headers */
1622 NtHeader2
= RtlImageNtHeader(CurEntry
->DllBase
);
1624 if (RtlCompareMemory(NtHeader2
, NtHeader
, sizeof(IMAGE_NT_HEADERS
)))
1626 /* Headers match too! Finally ask the kernel to compare mapped files */
1627 Status
= ZwAreMappedFilesTheSame(CurEntry
->DllBase
, ViewBase
);
1629 if (!NT_SUCCESS(Status
))
1631 _SEH2_YIELD(continue;)
1635 /* This is our entry! */
1636 *LdrEntry
= CurEntry
;
1638 /* Unmap the section */
1639 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1641 _SEH2_YIELD(return TRUE
;)
1646 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
1653 /* Unmap the section */
1654 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1661 LdrpGetProcedureAddress(IN PVOID BaseAddress
,
1662 IN PANSI_STRING Name
,
1664 OUT PVOID
*ProcedureAddress
,
1665 IN BOOLEAN ExecuteInit
)
1667 NTSTATUS Status
= STATUS_SUCCESS
;
1668 UCHAR ImportBuffer
[64];
1669 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1670 IMAGE_THUNK_DATA Thunk
;
1672 PIMAGE_IMPORT_BY_NAME ImportName
= NULL
;
1673 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1674 ULONG ExportDirSize
;
1677 /* Show debug message */
1678 if (ShowSnaps
) DPRINT1("LDR: LdrGetProcedureAddress by ");
1680 /* Check if we got a name */
1683 /* Show debug message */
1684 if (ShowSnaps
) DbgPrint("NAME - %s\n", Name
->Buffer
);
1686 /* Make sure it's not too long */
1687 if ((Name
->Length
+ sizeof(CHAR
) + sizeof(USHORT
)) > MAXLONG
)
1689 /* Won't have enough space to add the hint */
1690 return STATUS_NAME_TOO_LONG
;
1693 /* Check if our buffer is large enough */
1694 if (Name
->Length
>= (sizeof(ImportBuffer
) - sizeof(CHAR
)))
1696 /* Allocate from heap, plus 2 bytes for the Hint */
1697 ImportName
= RtlAllocateHeap(RtlGetProcessHeap(),
1699 Name
->Length
+ sizeof(CHAR
) +
1704 /* Use our internal buffer */
1705 ImportName
= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
;
1708 /* Clear the hint */
1709 ImportName
->Hint
= 0;
1711 /* Copy the name and null-terminate it */
1712 RtlMoveMemory(ImportName
->Name
, Name
->Buffer
, Name
->Length
);
1713 ImportName
->Name
[Name
->Length
] = 0;
1715 /* Clear the high bit */
1716 ImageBase
= ImportName
;
1717 Thunk
.u1
.AddressOfData
= 0;
1721 /* Do it by ordinal */
1724 /* Show debug message */
1725 if (ShowSnaps
) DbgPrint("ORDINAL - %lx\n", Ordinal
);
1729 Thunk
.u1
.Ordinal
= Ordinal
| IMAGE_ORDINAL_FLAG
;
1734 DPRINT1("No ordinal and no name\n");
1735 return STATUS_INVALID_PARAMETER
;
1739 /* Acquire lock unless we are initting */
1740 if (!LdrpInLdrInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
1744 /* Try to find the loaded DLL */
1745 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1748 DPRINT1("Invalid base address %p\n", BaseAddress
);
1749 Status
= STATUS_DLL_NOT_FOUND
;
1750 _SEH2_YIELD(goto Quickie
;)
1753 /* Get the pointer to the export directory */
1754 ExportDir
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1756 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1761 DPRINT1("Image %wZ has no exports, but were trying to get procedure %s. BaseAddress asked %p, got entry BA %p\n", &LdrEntry
->BaseDllName
, Name
? Name
->Buffer
: NULL
, BaseAddress
, LdrEntry
->DllBase
);
1762 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1763 _SEH2_YIELD(goto Quickie
;)
1766 /* Now get the thunk */
1767 Status
= LdrpSnapThunk(LdrEntry
->DllBase
,
1776 /* Finally, see if we're supposed to run the init routines */
1780 * It's possible a forwarded entry had us load the DLL. In that case,
1781 * then we will call its DllMain. Use the last loaded DLL for this.
1783 Entry
= NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
.Blink
;
1784 LdrEntry
= CONTAINING_RECORD(Entry
,
1785 LDR_DATA_TABLE_ENTRY
,
1786 InInitializationOrderModuleList
);
1788 /* Make sure we didn't process it yet*/
1789 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
1791 /* Call the init routine */
1794 Status
= LdrpRunInitializeRoutines(NULL
);
1796 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1798 /* Get the exception code */
1799 Status
= _SEH2_GetExceptionCode();
1805 /* Make sure we're OK till here */
1806 if (NT_SUCCESS(Status
))
1808 /* Return the address */
1809 *ProcedureAddress
= (PVOID
)Thunk
.u1
.Function
;
1812 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1814 /* Just ignore exceptions */
1820 if (ImportName
&& (ImportName
!= (PIMAGE_IMPORT_BY_NAME
)ImportBuffer
))
1822 /* We allocated from heap, free it */
1823 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName
);
1826 /* Release the CS if we entered it */
1827 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(&LdrpLoaderLock
);
1835 LdrpLoadDll(IN BOOLEAN Redirected
,
1836 IN PWSTR DllPath OPTIONAL
,
1837 IN PULONG DllCharacteristics OPTIONAL
,
1838 IN PUNICODE_STRING DllName
,
1839 OUT PVOID
*BaseAddress
,
1840 IN BOOLEAN CallInit
)
1842 PPEB Peb
= NtCurrentPeb();
1843 NTSTATUS Status
= STATUS_SUCCESS
;
1845 WCHAR NameBuffer
[266];
1847 UNICODE_STRING RawDllNameString
;
1848 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1849 BOOLEAN InInit
= LdrpInLdrInit
;
1851 /* Find the name without the extension */
1852 p1
= DllName
->Buffer
;
1861 else if (*p1
== L
'\\')
1867 /* Save the Raw DLL Name */
1868 RawDllName
= NameBuffer
;
1869 if (DllName
->Length
>= sizeof(NameBuffer
))
1871 /* The DLL's name is too long */
1872 return STATUS_NAME_TOO_LONG
;
1874 RtlMoveMemory(RawDllName
, DllName
->Buffer
, DllName
->Length
);
1876 /* Check if no extension was found or if we got a slash */
1877 if (!p2
|| *p2
== '\\')
1879 /* Check that we have space to add one */
1880 if (DllName
->Length
+ LdrApiDefaultExtension
.Length
>= sizeof(NameBuffer
))
1882 /* No space to add the extension */
1883 return STATUS_NAME_TOO_LONG
;
1887 RtlMoveMemory((PVOID
)((ULONG_PTR
)RawDllName
+ DllName
->Length
),
1888 LdrApiDefaultExtension
.Buffer
,
1889 LdrApiDefaultExtension
.Length
);
1891 /* Save the length to a unicode string */
1892 RawDllNameString
.Length
= DllName
->Length
+ LdrApiDefaultExtension
.Length
;
1894 /* Null terminate it */
1895 RawDllName
[RawDllNameString
.Length
/ sizeof(WCHAR
)] = 0;
1899 /* Null terminate it */
1900 RawDllName
[DllName
->Length
/ sizeof(WCHAR
)] = 0;
1902 /* Save the length to a unicode string */
1903 RawDllNameString
.Length
= DllName
->Length
;
1906 /* Now create a unicode string for the DLL's name */
1907 RawDllNameString
.MaximumLength
= sizeof(NameBuffer
);
1908 RawDllNameString
.Buffer
= NameBuffer
;
1910 /* Check for init flag and acquire lock */
1911 if (!InInit
) RtlEnterCriticalSection(&LdrpLoaderLock
);
1913 /* Show debug message */
1916 DPRINT1("LDR: LdrLoadDll, loading %ws from %ws\n",
1918 DllPath
? DllPath
: L
"");
1921 /* Check if the DLL is already loaded */
1922 if (!LdrpCheckForLoadedDll(DllPath
,
1929 Status
= LdrpMapDll(DllPath
,
1936 if (!NT_SUCCESS(Status
)) goto Quickie
;
1938 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */
1939 if (DllCharacteristics
&&
1940 (*DllCharacteristics
& IMAGE_FILE_EXECUTABLE_IMAGE
))
1942 LdrEntry
->EntryPoint
= NULL
;
1943 LdrEntry
->Flags
&= ~LDRP_IMAGE_DLL
;
1946 /* FIXME Mark the DLL Ranges for Stack Traces later */
1948 /* Make sure it's a DLL */
1949 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1951 /* Check if this is a .NET Image */
1952 if (!(LdrEntry
->Flags
& LDRP_COR_IMAGE
))
1954 /* Walk the Import Descriptor */
1955 Status
= LdrpWalkImportDescriptor(DllPath
, LdrEntry
);
1958 /* Update load count, unless it's locked */
1959 if (LdrEntry
->LoadCount
!= -1) LdrEntry
->LoadCount
++;
1960 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
1962 /* Check if we failed */
1963 if (!NT_SUCCESS(Status
))
1965 /* Clear entrypoint, and insert into list */
1966 LdrEntry
->EntryPoint
= NULL
;
1967 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
1968 &LdrEntry
->InInitializationOrderModuleList
);
1970 /* Cancel the load and unload the DLL */
1971 LdrpClearLoadInProgress();
1972 LdrUnloadDll(LdrEntry
->DllBase
);
1974 /* Return the error */
1978 else if (LdrEntry
->LoadCount
!= -1)
1980 /* Increase load count */
1981 LdrEntry
->LoadCount
++;
1984 /* Insert it into the list */
1985 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
1986 &LdrEntry
->InInitializationOrderModuleList
);
1988 /* If we have to run the entrypoint, make sure the DB is ready */
1989 if (CallInit
&& LdrpLdrDatabaseIsSetup
)
1991 /* FIXME: Notify Shim Engine */
1993 /* Run the init routine */
1994 Status
= LdrpRunInitializeRoutines(NULL
);
1995 if (!NT_SUCCESS(Status
))
1997 /* Failed, unload the DLL */
1998 LdrUnloadDll(LdrEntry
->DllBase
);
2003 /* The DB isn't ready, which means we were loaded because of a forwarder */
2004 Status
= STATUS_SUCCESS
;
2009 /* We were already loaded. Are we a DLL? */
2010 if ((LdrEntry
->Flags
& LDRP_IMAGE_DLL
) && (LdrEntry
->LoadCount
!= -1))
2012 /* Increase load count */
2013 LdrEntry
->LoadCount
++;
2014 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2016 /* Clear the load in progress */
2017 LdrpClearLoadInProgress();
2021 /* Not a DLL, just increase the load count */
2022 if (LdrEntry
->LoadCount
!= -1) LdrEntry
->LoadCount
++;
2027 /* Release the lock */
2028 if (!InInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
2030 /* Check for success */
2031 if (NT_SUCCESS(Status
))
2033 /* Return the base address */
2034 *BaseAddress
= LdrEntry
->DllBase
;
2039 *BaseAddress
= NULL
;
2051 LdrUnloadDll(IN PVOID BaseAddress
)
2053 NTSTATUS Status
= STATUS_SUCCESS
;
2054 PPEB Peb
= NtCurrentPeb();
2055 PLDR_DATA_TABLE_ENTRY LdrEntry
, CurrentEntry
;
2057 PLIST_ENTRY NextEntry
;
2058 LIST_ENTRY UnloadList
;
2059 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
2061 ULONG ComSectionSize
;
2063 /* Get the LDR Lock */
2064 if (!LdrpInLdrInit
) RtlEnterCriticalSection(Peb
->LoaderLock
);
2066 /* Increase the unload count */
2067 LdrpActiveUnloadCount
++;
2070 if (LdrpShutdownInProgress
) goto Quickie
;
2072 /* Make sure the DLL is valid and get its entry */
2073 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
2075 Status
= STATUS_DLL_NOT_FOUND
;
2079 /* Check the current Load Count */
2080 if (LdrEntry
->LoadCount
!= -1)
2083 LdrEntry
->LoadCount
--;
2086 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
2088 /* Set up the Act Ctx */
2089 ActCtx
.Size
= sizeof(ActCtx
);
2091 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
2093 /* Activate the ActCtx */
2094 RtlActivateActivationContextUnsafeFast(&ActCtx
,
2095 LdrEntry
->EntryPointActivationContext
);
2097 /* Update the load count */
2098 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_DEREFCOUNT
);
2100 /* Release the context */
2101 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
2106 /* The DLL is locked */
2110 /* Show debug message */
2111 if (ShowSnaps
) DPRINT1("LDR: UNINIT LIST\n");
2113 /* Check if this is our only unload */
2114 if (LdrpActiveUnloadCount
== 1)
2116 /* Initialize the unload list */
2117 InitializeListHead(&LdrpUnloadHead
);
2120 /* Loop the modules to build the list */
2121 NextEntry
= Peb
->Ldr
->InInitializationOrderModuleList
.Blink
;
2122 while (NextEntry
!= &Peb
->Ldr
->InInitializationOrderModuleList
)
2125 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
2126 NextEntry
= NextEntry
->Blink
;
2129 LdrEntry
->Flags
&= ~LDRP_UNLOAD_IN_PROGRESS
;
2131 /* If the load count is now 0 */
2132 if (!LdrEntry
->LoadCount
)
2137 DPRINT1("(%d) [%ws] %ws (%lx) deinit %lx\n",
2138 LdrpActiveUnloadCount
,
2139 LdrEntry
->BaseDllName
.Buffer
,
2140 LdrEntry
->FullDllName
.Buffer
,
2141 (ULONG
)LdrEntry
->LoadCount
,
2142 LdrEntry
->EntryPoint
);
2145 /* FIXME: Call Shim Engine and notify */
2148 CurrentEntry
= LdrEntry
;
2149 RemoveEntryList(&CurrentEntry
->InInitializationOrderModuleList
);
2150 RemoveEntryList(&CurrentEntry
->InMemoryOrderModuleList
);
2151 RemoveEntryList(&CurrentEntry
->HashLinks
);
2153 /* If there's more then one active unload */
2154 if (LdrpActiveUnloadCount
> 1)
2156 /* Flush the cached DLL handle and clear the list */
2157 LdrpLoadedDllHandleCache
= NULL
;
2158 CurrentEntry
->InMemoryOrderModuleList
.Flink
= NULL
;
2161 /* Add the entry on the unload list */
2162 InsertTailList(&LdrpUnloadHead
, &CurrentEntry
->HashLinks
);
2166 /* Only call the entrypoints once */
2167 if (LdrpActiveUnloadCount
> 1) goto Quickie
;
2169 /* Now loop the unload list and create our own */
2170 InitializeListHead(&UnloadList
);
2171 CurrentEntry
= NULL
;
2172 NextEntry
= LdrpUnloadHead
.Flink
;
2173 while (NextEntry
!= &LdrpUnloadHead
)
2175 /* If we have an active entry */
2179 RemoveEntryList(&CurrentEntry
->InLoadOrderLinks
);
2180 CurrentEntry
= NULL
;
2182 /* Reset list pointers */
2183 NextEntry
= LdrpUnloadHead
.Flink
;
2184 if (NextEntry
== &LdrpUnloadHead
) break;
2187 /* Get the current entry */
2188 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
2190 /* Log the Unload Event */
2191 //LdrpRecordUnloadEvent(LdrEntry);
2193 /* Set the entry and clear it from the list */
2194 CurrentEntry
= LdrEntry
;
2195 LdrpLoadedDllHandleCache
= NULL
;
2196 CurrentEntry
->InMemoryOrderModuleList
.Flink
= NULL
;
2198 /* Move it from the global to the local list */
2199 RemoveEntryList(&CurrentEntry
->HashLinks
);
2200 InsertTailList(&UnloadList
, &CurrentEntry
->HashLinks
);
2202 /* Get the entrypoint */
2203 EntryPoint
= LdrEntry
->EntryPoint
;
2205 /* Check if we should call it */
2206 if (EntryPoint
&& (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
))
2211 DPRINT1("LDR: Calling deinit %lx\n", EntryPoint
);
2214 /* Set up the Act Ctx */
2215 ActCtx
.Size
= sizeof(ActCtx
);
2217 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
2219 /* Activate the ActCtx */
2220 RtlActivateActivationContextUnsafeFast(&ActCtx
,
2221 LdrEntry
->EntryPointActivationContext
);
2223 /* Call the entrypoint */
2224 LdrpCallDllEntry(LdrEntry
->EntryPoint
,
2229 /* Release the context */
2230 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
2233 /* Remove it from the list */
2234 RemoveEntryList(&CurrentEntry
->InLoadOrderLinks
);
2235 CurrentEntry
= NULL
;
2236 NextEntry
= LdrpUnloadHead
.Flink
;
2239 /* Now loop our local list */
2240 NextEntry
= UnloadList
.Flink
;
2241 while (NextEntry
!= &UnloadList
)
2244 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
2245 NextEntry
= NextEntry
->Flink
;
2246 CurrentEntry
= LdrEntry
;
2248 /* Notify Application Verifier */
2249 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
2251 DPRINT1("We don't support Application Verifier yet\n");
2257 DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry
->BaseDllName
.Buffer
);
2260 /* Check if this is a .NET executable */
2261 if ((CorImageData
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
2263 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
2267 DPRINT1(".NET Images are not supported yet\n");
2270 /* Check if we should unmap*/
2271 if (!(CurrentEntry
->Flags
& LDR_COR_OWNS_UNMAP
))
2274 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
2275 CurrentEntry
->DllBase
);
2278 /* Unload the alternate resource module, if any */
2279 LdrUnloadAlternateResourceModule(CurrentEntry
->DllBase
);
2281 /* Send shutdown notification */
2282 //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
2284 /* Check if a Hotpatch is active */
2285 if (LdrEntry
->PatchInformation
)
2288 DPRINT1("We don't support Hotpatching yet\n");
2291 /* Deallocate the Entry */
2292 LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry
);
2294 /* If this is the cached entry, invalide it */
2295 if (LdrpGetModuleHandleCache
== CurrentEntry
)
2297 LdrpGetModuleHandleCache
= NULL
;
2302 /* Decrease unload count */
2303 LdrpActiveUnloadCount
--;
2304 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
2306 /* FIXME: Rundown the Hotpatch data, if present */
2308 /* Return to caller */
2314 LdrpClearLoadInProgress()
2316 PLIST_ENTRY ListHead
;
2318 PLDR_DATA_TABLE_ENTRY Module
;
2319 ULONG ModulesCount
= 0;
2321 /* Traverse the init list */
2322 ListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
2323 Entry
= ListHead
->Flink
;
2325 while (Entry
!= ListHead
)
2327 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
2329 /* Clear load in progress flag */
2330 Module
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2332 /* Increase counter for modules with entry point count but not processed yet */
2333 if (Module
->EntryPoint
&&
2334 !(Module
->Flags
& LDRP_ENTRY_PROCESSED
)) ModulesCount
++;
2336 /* Advance to the next entry */
2337 Entry
= Entry
->Flink
;
2340 return ModulesCount
;
2347 LdrAddRefDll(IN ULONG Flags
,
2348 IN PVOID BaseAddress
)
2350 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2351 NTSTATUS Status
= STATUS_SUCCESS
;
2353 BOOLEAN Locked
= FALSE
;
2355 /* Check for invalid flags */
2356 if (Flags
& ~(LDR_PIN_MODULE
))
2358 /* Fail with invalid parameter status if so */
2359 Status
= STATUS_INVALID_PARAMETER
;
2363 /* Acquire the loader lock if not in init phase */
2366 /* Acquire the lock */
2367 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
2368 if (!NT_SUCCESS(Status
)) goto quickie
;
2372 /* Get this module's data table entry */
2373 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
2377 /* Shouldn't happen */
2378 Status
= STATUS_INTERNAL_ERROR
;
2382 /* If this is not a pinned module */
2383 if (LdrEntry
->LoadCount
!= -1)
2385 /* Update its load count */
2386 if (Flags
& LDR_PIN_MODULE
)
2388 /* Pin it by setting load count to -1 */
2389 LdrEntry
->LoadCount
= -1;
2390 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_PIN
);
2394 /* Increase its load count by one */
2395 LdrEntry
->LoadCount
++;
2396 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
2399 /* Clear load in progress */
2400 LdrpClearLoadInProgress();
2405 /* There was an error getting this module's handle, return invalid param status */
2406 Status
= STATUS_INVALID_PARAMETER
;
2411 if (!NT_SUCCESS(Status
))
2414 (Status
!= STATUS_NO_SUCH_FILE
&&
2415 Status
!= STATUS_DLL_NOT_FOUND
&&
2416 Status
!= STATUS_OBJECT_NAME_NOT_FOUND
))
2418 DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress
);
2422 /* Release the lock if needed */
2423 if (Locked
) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
2431 LdrpFreeUnicodeString(PUNICODE_STRING String
)
2433 BOOLEAN Result
= FALSE
;
2435 ASSERT(String
!= NULL
);
2437 /* If Buffer is not NULL - free it */
2439 Result
= RtlFreeHeap(RtlGetProcessHeap(), 0, String
->Buffer
);
2443 String
->MaximumLength
= 0;
2444 String
->Buffer
= NULL
;