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)
10 /* INCLUDES *****************************************************************/
16 /* GLOBALS *******************************************************************/
18 LONG LdrpLoaderLockAcquisitonCount
;
19 BOOLEAN LdrpShowRecursiveLoads
;
20 UNICODE_STRING LdrApiDefaultExtension
= RTL_CONSTANT_STRING(L
".DLL");
22 /* FUNCTIONS *****************************************************************/
29 LdrUnlockLoaderLock(IN ULONG Flags
,
30 IN ULONG Cookie OPTIONAL
)
32 NTSTATUS Status
= STATUS_SUCCESS
;
34 DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags
, Cookie
);
36 /* Check for valid flags */
39 /* Flags are invalid, check how to fail */
40 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
42 /* The caller wants us to raise status */
43 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
47 /* A normal failure */
48 return STATUS_INVALID_PARAMETER_1
;
52 /* If we don't have a cookie, just return */
53 if (!Cookie
) return STATUS_SUCCESS
;
55 /* Validate the cookie */
56 if ((Cookie
& 0xF0000000) ||
57 ((Cookie
>> 16) ^ ((ULONG
)(NtCurrentTeb()->RealClientId
.UniqueThread
) & 0xFFF)))
59 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
61 /* Invalid cookie, check how to fail */
62 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
64 /* The caller wants us to raise status */
65 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
69 /* A normal failure */
70 return STATUS_INVALID_PARAMETER_2
;
74 /* Ready to release the lock */
75 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
77 /* Do a direct leave */
78 RtlLeaveCriticalSection(&LdrpLoaderLock
);
82 /* Wrap this in SEH, since we're not supposed to raise */
86 RtlLeaveCriticalSection(&LdrpLoaderLock
);
88 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
90 /* We should use the LDR Filter instead */
91 Status
= _SEH2_GetExceptionCode();
105 LdrLockLoaderLock(IN ULONG Flags
,
106 OUT PULONG Result OPTIONAL
,
107 OUT PULONG Cookie OPTIONAL
)
110 NTSTATUS Status
= STATUS_SUCCESS
;
111 BOOLEAN InInit
= LdrpInLdrInit
;
113 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags
, Result
, Cookie
);
115 /* Zero out the outputs */
116 if (Result
) *Result
= 0;
117 if (Cookie
) *Cookie
= 0;
119 /* Validate the flags */
120 if (Flags
& ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
|
121 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
))
123 /* Flags are invalid, check how to fail */
124 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
126 /* The caller wants us to raise status */
127 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
130 /* A normal failure */
131 return STATUS_INVALID_PARAMETER_1
;
134 /* Make sure we got a cookie */
137 /* No cookie check how to fail */
138 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
140 /* The caller wants us to raise status */
141 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3
);
144 /* A normal failure */
145 return STATUS_INVALID_PARAMETER_3
;
148 /* If the flag is set, make sure we have a valid pointer to use */
149 if ((Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
) && !(Result
))
151 /* No pointer to return the data to */
152 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
154 /* The caller wants us to raise status */
155 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
159 return STATUS_INVALID_PARAMETER_2
;
162 /* Return now if we are in the init phase */
163 if (InInit
) return STATUS_SUCCESS
;
165 /* Check what locking semantic to use */
166 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
168 /* Check if we should enter or simply try */
169 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
172 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
175 *Result
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
181 *Result
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
187 RtlEnterCriticalSection(&LdrpLoaderLock
);
189 /* See if result was requested */
190 if (Result
) *Result
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
193 /* Increase the acquisition count */
194 OldCount
= _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount
);
196 /* Generate a cookie */
197 *Cookie
= (((ULONG
)NtCurrentTeb()->RealClientId
.UniqueThread
& 0xFFF) << 16) | OldCount
;
201 /* Wrap this in SEH, since we're not supposed to raise */
204 /* Check if we should enter or simply try */
205 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
208 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
211 *Result
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
212 _SEH2_YIELD(return STATUS_SUCCESS
);
217 *Result
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
223 RtlEnterCriticalSection(&LdrpLoaderLock
);
225 /* See if result was requested */
226 if (Result
) *Result
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
229 /* Increase the acquisition count */
230 OldCount
= _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount
);
232 /* Generate a cookie */
233 *Cookie
= (((ULONG
)NtCurrentTeb()->RealClientId
.UniqueThread
& 0xFFF) << 16) | OldCount
;
235 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
237 /* We should use the LDR Filter instead */
238 Status
= _SEH2_GetExceptionCode();
252 LdrLoadDll(IN PWSTR SearchPath OPTIONAL
,
253 IN PULONG DllCharacteristics OPTIONAL
,
254 IN PUNICODE_STRING DllName
,
255 OUT PVOID
*BaseAddress
)
257 WCHAR StringBuffer
[MAX_PATH
];
258 UNICODE_STRING DllString1
, DllString2
;
259 BOOLEAN RedirectedDll
= FALSE
;
262 PUNICODE_STRING OldTldDll
;
263 PTEB Teb
= NtCurrentTeb();
265 /* Initialize the strings */
266 RtlInitUnicodeString(&DllString2
, NULL
);
267 DllString1
.Buffer
= StringBuffer
;
268 DllString1
.Length
= 0;
269 DllString1
.MaximumLength
= sizeof(StringBuffer
);
271 /* Check if the SxS Assemblies specify another file */
272 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
274 &LdrApiDefaultExtension
,
283 if (NT_SUCCESS(Status
))
286 RedirectedDll
= TRUE
;
288 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
290 /* Unrecoverable SxS failure; did we get a string? */
291 if (DllString2
.Buffer
)
293 /* Free the string */
294 RtlFreeUnicodeString(&DllString2
);
299 /* Lock the loader lock */
300 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
302 /* Check if there's a TLD DLL being loaded */
303 if ((OldTldDll
= LdrpTopLevelDllBeingLoaded
))
305 /* This is a recursive load, do something about it? */
306 if (ShowSnaps
|| LdrpShowRecursiveLoads
)
308 /* Print out debug messages */
309 DPRINT1("[%lx, %lx] LDR: Recursive DLL Load\n",
310 Teb
->RealClientId
.UniqueProcess
,
311 Teb
->RealClientId
.UniqueThread
);
312 DPRINT1("[%lx, %lx] Previous DLL being loaded \"%wZ\"\n",
313 Teb
->RealClientId
.UniqueProcess
,
314 Teb
->RealClientId
.UniqueThread
,
316 DPRINT1("[%lx, %lx] DLL being requested \"%wZ\"\n",
317 Teb
->RealClientId
.UniqueProcess
,
318 Teb
->RealClientId
.UniqueThread
,
321 /* Was it initializing too? */
322 if (!LdrpCurrentDllInitializer
)
324 DPRINT1("[%lx, %lx] LDR: No DLL Initializer was running\n",
325 Teb
->RealClientId
.UniqueProcess
,
326 Teb
->RealClientId
.UniqueThread
);
330 DPRINT1("[%lx, %lx] DLL whose initializer was currently running \"%wZ\"\n",
331 Teb
->ClientId
.UniqueProcess
,
332 Teb
->ClientId
.UniqueThread
,
333 &LdrpCurrentDllInitializer
->BaseDllName
);
338 /* Set this one as the TLD DLL being loaded*/
339 LdrpTopLevelDllBeingLoaded
= DllName
;
342 Status
= LdrpLoadDll(RedirectedDll
,
349 /* Restore the old TLD DLL */
350 LdrpTopLevelDllBeingLoaded
= OldTldDll
;
352 /* Release the lock */
353 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
355 /* Do we have a redirect string? */
356 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
367 LdrFindEntryForAddress(PVOID Address
,
368 PLDR_DATA_TABLE_ENTRY
*Module
)
370 PLIST_ENTRY ListHead
, NextEntry
;
371 PLDR_DATA_TABLE_ENTRY LdrEntry
;
372 PIMAGE_NT_HEADERS NtHeader
;
373 PPEB_LDR_DATA Ldr
= NtCurrentPeb()->Ldr
;
374 ULONG_PTR DllBase
, DllEnd
;
376 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
379 if (!Ldr
) return STATUS_NO_MORE_ENTRIES
;
381 /* Loop the module list */
382 ListHead
= &Ldr
->InMemoryOrderModuleList
;
383 NextEntry
= ListHead
->Flink
;
384 while (NextEntry
!= ListHead
)
386 /* Get the entry and NT Headers */
387 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderModuleList
);
388 if ((NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
)))
390 /* Get the Image Base */
391 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
392 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
394 /* Check if they match */
395 if (((ULONG_PTR
)Address
>= DllBase
) &&
396 ((ULONG_PTR
)Address
< DllEnd
))
400 return STATUS_SUCCESS
;
404 NextEntry
= NextEntry
->Flink
;
409 return STATUS_NO_MORE_ENTRIES
;
417 LdrGetDllHandleEx(IN ULONG Flags
,
418 IN PWSTR DllPath OPTIONAL
,
419 IN PULONG DllCharacteristics OPTIONAL
,
420 IN PUNICODE_STRING DllName
,
421 OUT PVOID
*DllHandle OPTIONAL
)
423 NTSTATUS Status
= STATUS_DLL_NOT_FOUND
;
424 PLDR_DATA_TABLE_ENTRY LdrEntry
;
425 UNICODE_STRING RedirectName
, DllString1
;
426 UNICODE_STRING RawDllName
;
427 PUNICODE_STRING pRedirectName
= &RedirectName
;
428 PUNICODE_STRING CompareName
;
430 BOOLEAN Locked
= FALSE
;
431 BOOLEAN RedirectedDll
= FALSE
;
435 /* Initialize the strings */
436 RtlInitUnicodeString(&DllString1
, NULL
);
437 RtlInitUnicodeString(&RawDllName
, NULL
);
438 RedirectName
= *DllName
;
440 /* Clear the handle */
441 if (DllHandle
) *DllHandle
= NULL
;
443 /* Check for a valid flag */
444 if ((Flags
& ~3) || (!DllHandle
&& !(Flags
& 2)))
446 DPRINT1("Flags are invalid or no DllHandle given\n");
447 return STATUS_INVALID_PARAMETER
;
450 /* If not initializing */
453 /* Acquire the lock */
454 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
458 /* Check if the SxS Assemblies specify another file */
459 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
461 &LdrApiDefaultExtension
,
470 if (NT_SUCCESS(Status
))
473 RedirectedDll
= TRUE
;
475 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
477 /* Unrecoverable SxS failure; */
481 /* Use the cache if we can */
482 if (LdrpGetModuleHandleCache
)
484 /* Check if we were redirected */
488 if (LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
)
490 /* Use the right name */
491 CompareName
= &LdrpGetModuleHandleCache
->FullDllName
;
501 if (!(LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
))
503 /* Use the right name */
504 CompareName
= &LdrpGetModuleHandleCache
->BaseDllName
;
512 /* Check if the name matches */
513 if (RtlEqualUnicodeString(pRedirectName
,
518 LdrEntry
= LdrpGetModuleHandleCache
;
521 Status
= STATUS_SUCCESS
;
528 /* Find the name without the extension */
529 p1
= pRedirectName
->Buffer
;
530 p3
= &p1
[pRedirectName
->Length
/ sizeof(WCHAR
)];
539 else if (*p1
== L
'\\')
545 /* Check if no extension was found or if we got a slash */
546 if (!p2
|| *p2
== L
'\\' || *p2
== L
'/')
548 /* Check that we have space to add one */
549 if (pRedirectName
->Length
+ LdrApiDefaultExtension
.Length
>= MAXLONG
)
551 /* No space to add the extension */
552 return STATUS_NAME_TOO_LONG
;
555 /* Setup the string */
556 RawDllName
.MaximumLength
= pRedirectName
->Length
+ LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
);
557 RawDllName
.Length
= RawDllName
.MaximumLength
- sizeof(UNICODE_NULL
);
558 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
560 RawDllName
.MaximumLength
);
562 /* Copy the buffer */
563 RtlMoveMemory(RawDllName
.Buffer
,
564 pRedirectName
->Buffer
,
565 pRedirectName
->Length
);
568 RtlMoveMemory((PVOID
)((ULONG_PTR
)RawDllName
.Buffer
+ pRedirectName
->Length
),
569 LdrApiDefaultExtension
.Buffer
,
570 LdrApiDefaultExtension
.Length
);
573 RawDllName
.Buffer
[RawDllName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
577 /* Check if there's something in the name */
578 if (pRedirectName
->Length
)
580 /* Check and remove trailing period */
581 if (pRedirectName
->Buffer
[(pRedirectName
->Length
- 2) /
582 sizeof(WCHAR
)] == '.')
584 /* Decrease the size */
585 pRedirectName
->Length
-= sizeof(WCHAR
);
589 /* Setup the string */
590 RawDllName
.MaximumLength
= pRedirectName
->Length
+ sizeof(WCHAR
);
591 RawDllName
.Length
= pRedirectName
->Length
;
592 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
594 RawDllName
.MaximumLength
);
596 /* Copy the buffer */
597 RtlMoveMemory(RawDllName
.Buffer
,
598 pRedirectName
->Buffer
,
599 pRedirectName
->Length
);
602 RawDllName
.Buffer
[RawDllName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
605 /* Display debug string */
608 DPRINT1("LDR: LdrGetDllHandle, searching for %wZ from %ws\n",
610 DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"");
614 if (LdrpCheckForLoadedDll(DllPath
,
616 ((ULONG_PTR
)DllPath
== 1) ? TRUE
: FALSE
,
620 /* Update cached entry */
621 LdrpGetModuleHandleCache
= LdrEntry
;
624 Status
= STATUS_SUCCESS
;
628 /* Make sure to NULL this */
632 DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry
? &LdrEntry
->BaseDllName
: NULL
);
634 /* Check if we got an entry */
637 /* Check for success */
638 if (NT_SUCCESS(Status
))
640 /* Check if the DLL is locked */
641 if (LdrEntry
->LoadCount
!= -1)
643 /* Check what flag we got */
646 /* Check what to do with the load count */
650 LdrEntry
->LoadCount
= -1;
651 LoadFlag
= LDRP_UPDATE_PIN
;
655 /* Increase the load count */
656 LdrEntry
->LoadCount
++;
657 LoadFlag
= LDRP_UPDATE_REFCOUNT
;
660 /* Update the load count now */
661 LdrpUpdateLoadCount2(LdrEntry
, LoadFlag
);
662 LdrpClearLoadInProgress();
666 /* Check if the caller is requesting the handle */
667 if (DllHandle
) *DllHandle
= LdrEntry
->DllBase
;
671 /* Free string if needed */
672 if (DllString1
.Buffer
) RtlFreeUnicodeString(&DllString1
);
674 /* Free the raw DLL Name if needed */
675 if (RawDllName
.Buffer
)
677 /* Free the heap-allocated buffer */
678 RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName
.Buffer
);
679 RawDllName
.Buffer
= NULL
;
683 if (Locked
) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
694 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL
,
695 IN PULONG DllCharacteristics OPTIONAL
,
696 IN PUNICODE_STRING DllName
,
697 OUT PVOID
*DllHandle
)
699 /* Call the newer API */
700 return LdrGetDllHandleEx(TRUE
,
712 LdrGetProcedureAddress(IN PVOID BaseAddress
,
713 IN PANSI_STRING Name
,
715 OUT PVOID
*ProcedureAddress
)
717 /* Call the internal routine and tell it to execute DllInit */
718 return LdrpGetProcedureAddress(BaseAddress
, Name
, Ordinal
, ProcedureAddress
, TRUE
);
726 LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle
,
727 IN PLDR_CALLBACK Callback
,
728 IN PVOID CallbackContext
,
729 OUT PUSHORT ImageCharacteristics
)
731 FILE_STANDARD_INFORMATION FileStandardInfo
;
732 PIMAGE_IMPORT_DESCRIPTOR ImportData
;
733 PIMAGE_SECTION_HEADER LastSection
;
734 IO_STATUS_BLOCK IoStatusBlock
;
735 PIMAGE_NT_HEADERS NtHeader
;
736 HANDLE SectionHandle
;
738 PVOID ViewBase
= NULL
;
744 DPRINT("LdrVerifyImageMatchesChecksum() called\n");
746 /* Create the section */
747 Status
= NtCreateSection(&SectionHandle
,
754 if (!NT_SUCCESS(Status
))
756 DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status
);
760 /* Map the section */
761 Status
= NtMapViewOfSection(SectionHandle
,
771 if (!NT_SUCCESS(Status
))
773 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
774 NtClose(SectionHandle
);
778 /* Get the file information */
779 Status
= NtQueryInformationFile(FileHandle
,
782 sizeof(FILE_STANDARD_INFORMATION
),
783 FileStandardInformation
);
784 if (!NT_SUCCESS(Status
))
786 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
787 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
788 NtClose(SectionHandle
);
792 /* Protect with SEH */
795 /* Verify the checksum */
796 Result
= LdrVerifyMappedImageMatchesChecksum(ViewBase
,
798 FileStandardInfo
.EndOfFile
.LowPart
);
800 /* Check if a callback was supplied */
801 if (Result
&& Callback
)
803 /* Get the NT Header */
804 NtHeader
= RtlImageNtHeader(ViewBase
);
806 /* Check if caller requested this back */
807 if (ImageCharacteristics
)
809 /* Return to caller */
810 *ImageCharacteristics
= NtHeader
->FileHeader
.Characteristics
;
813 /* Get the Import Directory Data */
814 ImportData
= RtlImageDirectoryEntryToData(ViewBase
,
816 IMAGE_DIRECTORY_ENTRY_IMPORT
,
819 /* Make sure there is one */
822 /* Loop the imports */
823 while (ImportData
->Name
)
826 ImportName
= RtlImageRvaToVa(NtHeader
,
831 /* Notify the callback */
832 Callback(CallbackContext
, ImportName
);
838 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
840 /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */
845 /* Unmap file and close handle */
846 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
847 NtClose(SectionHandle
);
850 return !Result
? STATUS_IMAGE_CHECKSUM_MISMATCH
: Status
;
855 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId
,
857 IN PRTL_PROCESS_MODULES ModuleInformation
,
859 OUT PULONG ReturnedSize OPTIONAL
)
861 PLIST_ENTRY ModuleListHead
, InitListHead
;
862 PLIST_ENTRY Entry
, InitEntry
;
863 PLDR_DATA_TABLE_ENTRY Module
, InitModule
;
864 PRTL_PROCESS_MODULE_INFORMATION ModulePtr
= NULL
;
865 NTSTATUS Status
= STATUS_SUCCESS
;
866 ULONG UsedSize
= sizeof(ULONG
);
867 ANSI_STRING AnsiString
;
870 DPRINT("LdrQueryProcessModuleInformation() called\n");
872 /* Acquire loader lock */
873 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
875 /* Check if we were given enough space */
878 Status
= STATUS_INFO_LENGTH_MISMATCH
;
882 ModuleInformation
->NumberOfModules
= 0;
883 ModulePtr
= &ModuleInformation
->Modules
[0];
884 Status
= STATUS_SUCCESS
;
887 /* Traverse the list of modules */
890 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
891 Entry
= ModuleListHead
->Flink
;
893 while (Entry
!= ModuleListHead
)
895 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
897 DPRINT(" Module %wZ\n", &Module
->FullDllName
);
899 /* Increase the used size */
900 UsedSize
+= sizeof(RTL_PROCESS_MODULE_INFORMATION
);
904 Status
= STATUS_INFO_LENGTH_MISMATCH
;
908 ModulePtr
->ImageBase
= Module
->DllBase
;
909 ModulePtr
->ImageSize
= Module
->SizeOfImage
;
910 ModulePtr
->Flags
= Module
->Flags
;
911 ModulePtr
->LoadCount
= Module
->LoadCount
;
912 ModulePtr
->MappedBase
= NULL
;
913 ModulePtr
->InitOrderIndex
= 0;
914 ModulePtr
->LoadOrderIndex
= ModuleInformation
->NumberOfModules
;
916 /* Now get init order index by traversing init list */
917 InitListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
918 InitEntry
= InitListHead
->Flink
;
920 while (InitEntry
!= InitListHead
)
922 InitModule
= CONTAINING_RECORD(InitEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
924 /* Increase the index */
925 ModulePtr
->InitOrderIndex
++;
927 /* Quit the loop if our module is found */
928 if (InitModule
== Module
) break;
930 /* Advance to the next entry */
931 InitEntry
= InitEntry
->Flink
;
934 /* Prepare ANSI string with the module's name */
935 AnsiString
.Length
= 0;
936 AnsiString
.MaximumLength
= sizeof(ModulePtr
->FullPathName
);
937 AnsiString
.Buffer
= ModulePtr
->FullPathName
;
938 RtlUnicodeStringToAnsiString(&AnsiString
,
939 &Module
->FullDllName
,
942 /* Calculate OffsetToFileName field */
943 p
= strrchr(ModulePtr
->FullPathName
, '\\');
945 ModulePtr
->OffsetToFileName
= p
- ModulePtr
->FullPathName
+ 1;
947 ModulePtr
->OffsetToFileName
= 0;
949 /* Advance to the next module in the output list */
952 /* Increase number of modules */
953 if (ModuleInformation
)
954 ModuleInformation
->NumberOfModules
++;
957 /* Go to the next entry in the modules list */
958 Entry
= Entry
->Flink
;
961 /* Set returned size if it was provided */
963 *ReturnedSize
= UsedSize
;
965 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
967 /* Ignoring the exception */
970 /* Release the lock */
971 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
973 DPRINT("LdrQueryProcessModuleInformation() done\n");
983 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation
,
985 OUT PULONG ReturnedSize OPTIONAL
)
987 /* Call Ex version of the API */
988 return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation
, Size
, ReturnedSize
);
993 LdrEnumerateLoadedModules(BOOLEAN ReservedFlag
, PLDR_ENUM_CALLBACK EnumProc
, PVOID Context
)
995 PLIST_ENTRY ListHead
, ListEntry
;
996 PLDR_DATA_TABLE_ENTRY LdrEntry
;
999 BOOLEAN Stop
= FALSE
;
1001 /* Check parameters */
1002 if (ReservedFlag
|| !EnumProc
) return STATUS_INVALID_PARAMETER
;
1004 /* Acquire the loader lock */
1005 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1006 if (!NT_SUCCESS(Status
)) return Status
;
1008 /* Loop all the modules and call enum proc */
1009 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1010 ListEntry
= ListHead
->Flink
;
1011 while (ListHead
!= ListEntry
)
1014 LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1016 /* Call the enumeration proc inside SEH */
1019 EnumProc(LdrEntry
, Context
, &Stop
);
1021 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1023 /* Ignoring the exception */
1026 /* Break if we were asked to stop enumeration */
1029 /* Release loader lock */
1030 Status
= LdrUnlockLoaderLock(0, Cookie
);
1032 /* Reset any successful status to STATUS_SUCCESS, but leave
1033 failure to the caller */
1034 if (NT_SUCCESS(Status
))
1035 Status
= STATUS_SUCCESS
;
1037 /* Return any possible failure status */
1041 /* Advance to the next module */
1042 ListEntry
= ListEntry
->Flink
;
1045 /* Release loader lock, it must succeed this time */
1046 Status
= LdrUnlockLoaderLock(0, Cookie
);
1047 ASSERT(NT_SUCCESS(Status
));
1049 /* Return success */
1050 return STATUS_SUCCESS
;