1 /* $Id: utils.c,v 1.51 2002/07/13 12:44:06 chorns Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/startup.c
6 * PURPOSE: Process startup for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
13 * - Fix calling of entry points
14 * - Handle loading flags correctly
18 /* INCLUDES *****************************************************************/
20 #include <reactos/config.h>
21 #include <ddk/ntddk.h>
25 #include <ntdll/ldr.h>
26 #include <ntos/minmax.h>
29 #ifdef DBG_NTDLL_LDR_UTILS
32 #include <ntdll/ntdll.h>
34 /* PROTOTYPES ****************************************************************/
37 /* Type for a DLL's entry point */
38 typedef WINBOOL STDCALL
39 (* PDLLMAIN_FUNC
)(HANDLE hInst
,
40 ULONG ul_reason_for_call
,
43 static NTSTATUS
LdrFindEntryForName(PUNICODE_STRING Name
, PLDR_MODULE
*Module
);
44 static PVOID
LdrFixupForward(PCHAR ForwardName
);
45 static PVOID
LdrGetExportByName(PVOID BaseAddress
, PUCHAR SymbolName
, USHORT Hint
);
48 /* FUNCTIONS *****************************************************************/
54 LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule
)
68 /***************************************************************************
73 * Adjusts the name of a dll to a fully qualified name.
76 * FullDllName: Pointer to caller supplied storage for the fully
78 * DllName: Pointer to the dll name.
79 * BaseName: TRUE: Only the file name is passed to FullDllName
80 * FALSE: The full path is preserved in FullDllName
88 * A given path is not affected by the adjustment, but the file
92 * ntdll.xyz --> ntdll.xyz
96 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
97 PUNICODE_STRING DllName
,
100 WCHAR Buffer
[MAX_PATH
];
105 Length
= DllName
->Length
/ sizeof(WCHAR
);
107 if (BaseName
== TRUE
)
109 /* get the base dll name */
110 Pointer
= DllName
->Buffer
+ Length
;
117 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
120 Length
= Extension
- Pointer
;
121 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
125 /* get the full dll name */
126 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
129 /* Build the DLL's absolute name */
130 Extension
= wcsrchr (Buffer
, L
'.');
131 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
133 /* with extension - remove dot if it's the last character */
134 if (Buffer
[Length
- 1] == L
'.')
140 /* name without extension - assume that it is .dll */
141 memmove (Buffer
+ Length
, L
".dll", 10);
144 RtlCreateUnicodeString (FullDllName
,
149 /***************************************************************************
166 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
168 IN PUNICODE_STRING Name
,
169 OUT PVOID
*BaseAddress OPTIONAL
)
171 WCHAR SearchPathBuffer
[MAX_PATH
];
172 WCHAR FullDosName
[MAX_PATH
];
173 UNICODE_STRING AdjustedName
;
174 UNICODE_STRING FullNtFileName
;
175 OBJECT_ATTRIBUTES FileObjectAttributes
;
176 char BlockBuffer
[1024];
177 PIMAGE_DOS_HEADER DosHeader
;
179 PIMAGE_NT_HEADERS NTHeaders
;
181 ULONG InitialViewSize
;
184 HANDLE SectionHandle
;
185 PDLLMAIN_FUNC Entrypoint
= NULL
;
190 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
191 return STATUS_SUCCESS
;
196 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
199 /* adjust the full dll name */
200 LdrAdjustDllName (&AdjustedName
,
203 DPRINT("AdjustedName: %wZ\n", &AdjustedName
);
206 * Test if dll is already loaded.
208 if (LdrFindEntryForName(&AdjustedName
, &Module
) == STATUS_SUCCESS
)
210 DPRINT("DLL %wZ already loaded.\n", &AdjustedName
);
211 if (Module
->LoadCount
!= -1)
213 *BaseAddress
= Module
->BaseAddress
;
214 return STATUS_SUCCESS
;
216 DPRINT("Loading \"%wZ\"\n", Name
);
218 if (SearchPath
== NULL
)
220 SearchPath
= SearchPathBuffer
;
221 wcscpy (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
222 wcscat (SearchPathBuffer
, L
"\\system32;");
223 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
224 wcscat (SearchPathBuffer
, L
";.");
227 DPRINT("SearchPath %S\n", SearchPath
);
229 if (RtlDosSearchPath_U (SearchPath
,
235 return STATUS_DLL_NOT_FOUND
;
237 DPRINT("FullDosName %S\n", FullDosName
);
239 RtlFreeUnicodeString (&AdjustedName
);
241 if (!RtlDosPathNameToNtPathName_U (FullDosName
,
245 return STATUS_DLL_NOT_FOUND
;
247 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
249 InitializeObjectAttributes(&FileObjectAttributes
,
255 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
257 Status
= ZwOpenFile(&FileHandle
,
259 &FileObjectAttributes
,
263 if (!NT_SUCCESS(Status
))
265 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
266 &FullNtFileName
, Status
);
267 RtlFreeUnicodeString (&FullNtFileName
);
270 RtlFreeUnicodeString (&FullNtFileName
);
272 Status
= ZwReadFile(FileHandle
,
281 if (!NT_SUCCESS(Status
))
283 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
288 * Overlay DOS and NT headers structures to the
289 * buffer with DLL's header raw data.
291 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
292 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
294 * Check it is a PE image file.
296 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
297 || (DosHeader
->e_lfanew
== 0L)
298 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
300 DPRINT("NTDLL format invalid\n");
303 return STATUS_UNSUCCESSFUL
;
306 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
307 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
309 DPRINT("ImageBase 0x%08x\n", ImageBase
);
312 * Create a section for dll.
314 Status
= ZwCreateSection(&SectionHandle
,
319 SEC_COMMIT
| SEC_IMAGE
,
321 if (!NT_SUCCESS(Status
))
323 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
329 * Map the dll into the process.
333 Status
= ZwMapViewOfSection(SectionHandle
,
343 if (!NT_SUCCESS(Status
))
345 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n",
352 /* relocate dll and fixup import table */
353 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
357 (PDLLMAIN_FUNC
) LdrPEStartup(ImageBase
, SectionHandle
);
358 if (Entrypoint
== NULL
)
360 return(STATUS_UNSUCCESSFUL
);
364 /* build module entry */
365 Module
= RtlAllocateHeap(RtlGetProcessHeap(),
367 sizeof (LDR_MODULE
));
369 Module
->BaseAddress
= (PVOID
)ImageBase
;
370 Module
->EntryPoint
= NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
371 if (Module
->EntryPoint
!= 0)
372 Module
->EntryPoint
+= (ULONG
)Module
->BaseAddress
;
373 Module
->SizeOfImage
= ImageSize
;
374 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
376 /* loading while app is running */
377 Module
->LoadCount
= 1;
382 * loading while app is initializing
383 * dll must not be unloaded
385 Module
->LoadCount
= -1;
388 Module
->TlsIndex
= 0;
389 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
390 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
392 RtlCreateUnicodeString (&Module
->FullDllName
,
394 RtlCreateUnicodeString (&Module
->BaseDllName
,
395 wcsrchr(FullDosName
, L
'\\') + 1);
396 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
398 /* FIXME: aquire loader lock */
399 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
400 &Module
->InLoadOrderModuleList
);
401 InsertTailList(&NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
,
402 &Module
->InInitializationOrderModuleList
);
403 /* FIXME: release loader lock */
407 LdrpLoadUserModuleSymbols(Module
);
412 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
415 if (Module
->EntryPoint
!= 0)
417 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
419 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
420 if (FALSE
== Entrypoint(Module
->BaseAddress
,
424 DPRINT("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
425 &Module
->BaseDllName
);
426 /* FIXME: should clean up and fail */
430 DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
431 &Module
->BaseDllName
);
436 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
437 &Module
->BaseDllName
);
441 *BaseAddress
= Module
->BaseAddress
;
442 return STATUS_SUCCESS
;
446 /***************************************************************************
448 * LdrFindEntryForAddress
462 LdrFindEntryForAddress(PVOID Address
,
465 PLIST_ENTRY ModuleListHead
;
467 PLDR_MODULE ModulePtr
;
469 DPRINT("NTDLL.LdrFindEntryForAddress(Address %p)\n", Address
);
471 if (NtCurrentPeb()->Ldr
== NULL
)
472 return(STATUS_NO_MORE_ENTRIES
);
474 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
475 Entry
= ModuleListHead
->Flink
;
476 if (Entry
== ModuleListHead
)
477 return(STATUS_NO_MORE_ENTRIES
);
479 while (Entry
!= ModuleListHead
)
481 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
483 DPRINT("Scanning %wZ at %p\n", &ModulePtr
->BaseDllName
, ModulePtr
->BaseAddress
);
485 if ((Address
>= ModulePtr
->BaseAddress
) &&
486 (Address
<= (ModulePtr
->BaseAddress
+ ModulePtr
->SizeOfImage
)))
489 return(STATUS_SUCCESS
);
492 Entry
= Entry
->Flink
;
495 DPRINT("Failed to find module entry.\n");
497 return(STATUS_NO_MORE_ENTRIES
);
501 /***************************************************************************
503 * LdrFindEntryForName
517 LdrFindEntryForName(PUNICODE_STRING Name
,
520 PLIST_ENTRY ModuleListHead
;
522 PLDR_MODULE ModulePtr
;
524 DPRINT("NTDLL.LdrFindEntryForName(Name %wZ)\n", Name
);
526 if (NtCurrentPeb()->Ldr
== NULL
)
527 return(STATUS_NO_MORE_ENTRIES
);
529 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
530 Entry
= ModuleListHead
->Flink
;
531 if (Entry
== ModuleListHead
)
532 return(STATUS_NO_MORE_ENTRIES
);
534 // NULL is the current process
537 *Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
538 return(STATUS_SUCCESS
);
541 while (Entry
!= ModuleListHead
)
543 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
545 DPRINT("Scanning %wZ %wZ\n", &ModulePtr
->BaseDllName
, Name
);
547 if (RtlCompareUnicodeString(&ModulePtr
->BaseDllName
, Name
, TRUE
) == 0)
550 return(STATUS_SUCCESS
);
553 Entry
= Entry
->Flink
;
556 DPRINT("Failed to find dll %wZ\n", Name
);
558 return(STATUS_NO_MORE_ENTRIES
);
561 /**********************************************************************
577 LdrFixupForward(PCHAR ForwardName
)
579 CHAR NameBuffer
[128];
580 UNICODE_STRING DllName
;
581 UNICODE_STRING FunctionName
;
586 strcpy(NameBuffer
, ForwardName
);
587 p
= strchr(NameBuffer
, '.');
592 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
593 RtlCreateUnicodeStringFromAsciiz (&DllName
,
596 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
597 if (!NT_SUCCESS(Status
))
599 Status
= LdrLoadDll(NULL
,
603 if (!NT_SUCCESS(Status
))
605 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName
);
606 RtlFreeUnicodeString (&DllName
);
611 RtlFreeUnicodeString (&DllName
);
612 DPRINT("BaseAddress: %p\n", BaseAddress
);
614 return LdrGetExportByName(BaseAddress
, p
+1, -1);
621 /**********************************************************************
623 * LdrGetExportByOrdinal
637 LdrGetExportByOrdinal (
642 PIMAGE_EXPORT_DIRECTORY ExportDir
;
643 PDWORD
* ExFunctions
;
646 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
647 RtlImageDirectoryEntryToData (BaseAddress
,
649 IMAGE_DIRECTORY_ENTRY_EXPORT
,
653 ExOrdinals
= (USHORT
*)
656 ExportDir
->AddressOfNameOrdinals
658 ExFunctions
= (PDWORD
*)
661 ExportDir
->AddressOfFunctions
664 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
666 ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]
668 return(ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]);
672 /**********************************************************************
688 LdrGetExportByName(PVOID BaseAddress
,
692 PIMAGE_EXPORT_DIRECTORY ExportDir
;
693 PDWORD
* ExFunctions
;
703 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
705 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
706 RtlImageDirectoryEntryToData(BaseAddress
,
708 IMAGE_DIRECTORY_ENTRY_EXPORT
,
710 if (ExportDir
== NULL
)
712 DbgPrint("LdrGetExportByName(): no export directory!\n");
717 * Get header pointers
719 ExNames
= (PDWORD
*)RVA(BaseAddress
,
720 ExportDir
->AddressOfNames
);
721 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
722 ExportDir
->AddressOfNameOrdinals
);
723 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
724 ExportDir
->AddressOfFunctions
);
727 * Check the hint first
729 if (Hint
< ExportDir
->NumberOfFunctions
)
731 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
732 if (strcmp(ExName
, SymbolName
) == 0)
734 Ordinal
= ExOrdinals
[Hint
];
735 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
736 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
737 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
739 DPRINT("Forward: %s\n", (PCHAR
)Function
);
740 Function
= LdrFixupForward((PCHAR
)Function
);
742 if (Function
!= NULL
)
748 * Try a binary search first
751 maxn
= ExportDir
->NumberOfFunctions
;
757 mid
= (minn
+ maxn
) / 2;
759 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
760 res
= strcmp(ExName
, SymbolName
);
763 Ordinal
= ExOrdinals
[mid
];
764 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
765 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
766 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
768 DPRINT("Forward: %s\n", (PCHAR
)Function
);
769 Function
= LdrFixupForward((PCHAR
)Function
);
771 if (Function
!= NULL
)
774 else if (minn
== maxn
)
776 DPRINT("LdrGetExportByName(): binary search failed\n");
790 * Fall back on a linear search
792 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
793 for (i
= 0; i
< ExportDir
->NumberOfFunctions
; i
++)
795 ExName
= RVA(BaseAddress
, ExNames
[i
]);
796 if (strcmp(ExName
,SymbolName
) == 0)
798 Ordinal
= ExOrdinals
[i
];
799 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
800 DPRINT("%x %x %x\n", Function
, ExportDir
, ExportDir
+ ExportDirSize
);
801 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
802 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
804 DPRINT("Forward: %s\n", (PCHAR
)Function
);
805 Function
= LdrFixupForward((PCHAR
)Function
);
810 DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName
);
815 /**********************************************************************
817 * LdrPerformRelocations
820 * Relocate a DLL's memory image.
831 static NTSTATUS
LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders
,
834 USHORT NumberOfEntries
;
840 PRELOCATION_DIRECTORY RelocationDir
;
841 PRELOCATION_ENTRY RelocationBlock
;
845 RelocationRVA
= NTHeaders
->OptionalHeader
846 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
]
851 RelocationDir
= (PRELOCATION_DIRECTORY
)
852 ((PCHAR
)ImageBase
+ RelocationRVA
);
854 while (RelocationDir
->SizeOfBlock
)
856 Delta32
= (ULONG
)(ImageBase
-
857 NTHeaders
->OptionalHeader
.ImageBase
);
858 RelocationBlock
= (PRELOCATION_ENTRY
) (
861 + sizeof (RELOCATION_DIRECTORY
)
864 RelocationDir
->SizeOfBlock
865 - sizeof (RELOCATION_DIRECTORY
)
867 / sizeof (RELOCATION_ENTRY
);
870 (i
< NumberOfEntries
);
875 RelocationBlock
[i
].TypeOffset
878 + RelocationDir
->VirtualAddress
;
880 * What kind of relocations should we perform
881 * for the current entry?
883 switch (RelocationBlock
[i
].TypeOffset
>> 12)
885 case TYPE_RELOC_ABSOLUTE
:
888 case TYPE_RELOC_HIGH
:
889 pValue16
= (PUSHORT
) (ImageBase
+ Offset
);
890 *pValue16
+= Delta32
>> 16;
894 pValue16
= (PUSHORT
)(ImageBase
+ Offset
);
895 *pValue16
+= Delta32
& 0xffff;
898 case TYPE_RELOC_HIGHLOW
:
899 pValue32
= (PULONG
) (ImageBase
+ Offset
);
900 *pValue32
+= Delta32
;
903 case TYPE_RELOC_HIGHADJ
:
904 /* FIXME: do the highadjust fixup */
906 "TYPE_RELOC_HIGHADJ fixup not implemented"
909 return(STATUS_UNSUCCESSFUL
);
912 DPRINT("unexpected fixup type\n");
913 return STATUS_UNSUCCESSFUL
;
916 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
917 RelocationDir
= (PRELOCATION_DIRECTORY
) (
923 return STATUS_SUCCESS
;
927 /**********************************************************************
932 * Compute the entry point for every symbol the DLL imports
933 * from other modules.
944 static NTSTATUS
LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders
,
947 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
952 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders
,
956 * Process each import module.
958 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)(
959 ImageBase
+ NTHeaders
->OptionalHeader
960 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
962 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
964 while (ImportModuleDirectory
->dwRVAModuleName
)
966 PVOID
* ImportAddressList
;
967 PULONG FunctionNameList
;
968 UNICODE_STRING DllName
;
972 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
973 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
975 RtlCreateUnicodeStringFromAsciiz (&DllName
,
976 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
978 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
979 if (!NT_SUCCESS(Status
))
981 Status
= LdrLoadDll(NULL
,
985 RtlFreeUnicodeString (&DllName
);
986 if (!NT_SUCCESS(Status
))
988 DbgPrint("LdrFixupImports:failed to load %s\n"
990 + ImportModuleDirectory
->dwRVAModuleName
));
997 * Get the import address list.
999 ImportAddressList
= (PVOID
*)(NTHeaders
->OptionalHeader
.ImageBase
1000 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
1003 * Get the list of functions to import.
1005 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1007 FunctionNameList
= (PULONG
) (
1009 + ImportModuleDirectory
->dwRVAFunctionNameList
1016 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
1019 * Walk through function list and fixup addresses.
1021 while (*FunctionNameList
!= 0L)
1023 if ((*FunctionNameList
) & 0x80000000)
1025 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
1026 *ImportAddressList
=
1027 LdrGetExportByOrdinal(BaseAddress
,
1032 pName
= (DWORD
) (ImageBase
+ *FunctionNameList
+ 2);
1033 pHint
= *(PWORD
)(ImageBase
+ *FunctionNameList
);
1035 *ImportAddressList
=
1036 LdrGetExportByName(BaseAddress
, (PUCHAR
)pName
, pHint
);
1037 if ((*ImportAddressList
) == NULL
)
1039 DbgPrint("Failed to import %s\n", pName
);
1040 return STATUS_UNSUCCESSFUL
;
1043 ImportAddressList
++;
1046 ImportModuleDirectory
++;
1048 return STATUS_SUCCESS
;
1052 /**********************************************************************
1057 * 1. Map the DLL's sections into memory.
1058 * 2. Relocate, if needed the DLL.
1059 * 3. Fixup any imported symbol.
1060 * 4. Compute the DLL's entry point.
1064 * Address at which the DLL's image
1068 * Handle of the section that contains
1072 * NULL on error; otherwise the entry point
1073 * to call for initializing the DLL.
1080 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
1081 HANDLE SectionHandle
)
1084 PEPFUNC EntryPoint
= NULL
;
1085 PIMAGE_DOS_HEADER DosHeader
;
1086 PIMAGE_NT_HEADERS NTHeaders
;
1088 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1089 ImageBase
, (ULONG
)SectionHandle
);
1092 * Overlay DOS and WNT headers structures
1093 * to the DLL's image.
1095 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
1096 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
1099 * If the base address is different from the
1100 * one the DLL is actually loaded, perform any
1103 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1105 DbgPrint("LDR: Performing relocations\n");
1106 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
1107 if (!NT_SUCCESS(Status
))
1109 DbgPrint("LdrPerformRelocations() failed\n");
1115 * If the DLL's imports symbols from other
1116 * modules, fixup the imported calls entry points.
1118 if (NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
1119 .VirtualAddress
!= 0)
1121 DPRINT("About to fixup imports\n");
1122 Status
= LdrFixupImports(NTHeaders
, ImageBase
);
1123 if (!NT_SUCCESS(Status
))
1125 DbgPrint("LdrFixupImports() failed\n");
1128 DPRINT("Fixup done\n");
1132 * Compute the DLL's entry point's address.
1134 DPRINT("ImageBase = %x\n",(ULONG
)ImageBase
);
1135 DPRINT("AddressOfEntryPoint = %x\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1136 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
1138 EntryPoint
= (PEPFUNC
) (ImageBase
1139 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1141 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
1147 LdrUnloadDll (IN PVOID BaseAddress
)
1149 PIMAGE_NT_HEADERS NtHeaders
;
1150 PDLLMAIN_FUNC Entrypoint
;
1151 PLIST_ENTRY ModuleListHead
;
1156 if (BaseAddress
== NULL
)
1157 return STATUS_SUCCESS
;
1159 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1160 Entry
= ModuleListHead
->Flink
;
1162 while (Entry
!= ModuleListHead
)
1164 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1165 if (Module
->BaseAddress
== BaseAddress
)
1167 if (Module
->LoadCount
== -1)
1169 /* never unload this dll */
1170 return STATUS_SUCCESS
;
1172 else if (Module
->LoadCount
> 1)
1174 Module
->LoadCount
--;
1175 return STATUS_SUCCESS
;
1178 NtHeaders
= RtlImageNtHeader (Module
->BaseAddress
);
1179 if ((NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) == IMAGE_FILE_DLL
)
1181 if (Module
->EntryPoint
!= 0)
1183 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1184 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1185 Entrypoint(Module
->BaseAddress
,
1191 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1194 Status
= ZwUnmapViewOfSection (NtCurrentProcess (),
1195 Module
->BaseAddress
);
1196 ZwClose (Module
->SectionHandle
);
1198 /* remove the module entry from the list */
1199 RtlFreeUnicodeString (&Module
->FullDllName
);
1200 RtlFreeUnicodeString (&Module
->BaseDllName
);
1201 RemoveEntryList (Entry
);
1202 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
1207 Entry
= Entry
->Flink
;
1210 DPRINT("NTDLL.LDR: Dll not found\n")
1212 return STATUS_UNSUCCESSFUL
;
1217 LdrFindResource_U(PVOID BaseAddress
,
1218 PLDR_RESOURCE_INFO ResourceInfo
,
1220 PIMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
)
1222 PIMAGE_RESOURCE_DIRECTORY ResDir
;
1223 PIMAGE_RESOURCE_DIRECTORY ResBase
;
1224 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
1225 NTSTATUS Status
= STATUS_SUCCESS
;
1231 DPRINT ("LdrFindResource_U()\n");
1233 /* Get the pointer to the resource directory */
1234 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1235 RtlImageDirectoryEntryToData (BaseAddress
,
1237 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1241 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1244 DPRINT("ResourceDirectory: %x\n", (ULONG
)ResDir
);
1248 /* Let's go into resource tree */
1249 for (i
= 0; i
< Level
; i
++)
1251 DPRINT("ResDir: %x\n", (ULONG
)ResDir
);
1252 Id
= ((PULONG
)ResourceInfo
)[i
];
1253 EntryCount
= ResDir
->NumberOfNamedEntries
;
1254 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
1255 DPRINT("ResEntry %x\n", (ULONG
)ResEntry
);
1256 if (Id
& 0xFFFF0000)
1258 /* Resource name is a unicode string */
1259 for (; EntryCount
--; ResEntry
++)
1261 /* Scan entries for equal name */
1262 if (ResEntry
->Name
& 0x80000000)
1264 ws
= (PWCHAR
)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
1265 if (!wcsncmp((PWCHAR
)Id
, ws
+ 1, *ws
) &&
1266 wcslen((PWCHAR
)Id
) == (int)*ws
)
1275 /* We use ID number instead of string */
1276 ResEntry
+= EntryCount
;
1277 EntryCount
= ResDir
->NumberOfIdEntries
;
1278 for (; EntryCount
--; ResEntry
++)
1280 /* Scan entries for equal name */
1281 if (ResEntry
->Name
== Id
)
1283 DPRINT("ID entry found %x\n", Id
);
1288 DPRINT("Error %lu\n", i
);
1293 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
1296 return STATUS_RESOURCE_NAME_NOT_FOUND
;
1299 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
)
1301 /* Use the first available language */
1302 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
1305 return STATUS_RESOURCE_LANG_NOT_FOUND
;
1308 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1311 return STATUS_INVALID_PARAMETER
;
1314 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResBase
+
1315 (ResEntry
->OffsetToData
& 0x7FFFFFFF));
1317 DPRINT("ResourceDataEntry: %x\n", (ULONG
)ResDir
);
1319 if (ResourceDataEntry
)
1321 *ResourceDataEntry
= (PVOID
)ResDir
;
1329 LdrAccessResource(IN PVOID BaseAddress
,
1330 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
,
1331 OUT PVOID
*Resource OPTIONAL
,
1332 OUT PULONG Size OPTIONAL
)
1334 PIMAGE_SECTION_HEADER Section
;
1335 PIMAGE_NT_HEADERS NtHeader
;
1342 Data
= (ULONG
)RtlImageDirectoryEntryToData (BaseAddress
,
1344 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1347 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1349 if ((ULONG
)BaseAddress
& 1)
1351 /* loaded as ordinary file */
1352 NtHeader
= RtlImageNtHeader((PVOID
)((ULONG
)BaseAddress
& ~1UL));
1353 Offset
= (ULONG
)BaseAddress
- Data
+ NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
;
1354 Section
= RtlImageRvaToSection (NtHeader
, BaseAddress
, NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
);
1355 if (Section
== NULL
)
1357 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1360 if (Section
->Misc
.VirtualSize
< ResourceDataEntry
->OffsetToData
)
1362 SectionRva
= RtlImageRvaToSection (NtHeader
, BaseAddress
, ResourceDataEntry
->OffsetToData
)->VirtualAddress
;
1363 SectionVa
= RtlImageRvaToVa(NtHeader
, BaseAddress
, SectionRva
, NULL
);
1364 Offset
= SectionRva
- SectionVa
+ Data
- Section
->VirtualAddress
;
1370 *Resource
= (PVOID
)(ResourceDataEntry
->OffsetToData
- Offset
+ (ULONG
)BaseAddress
);
1375 *Size
= ResourceDataEntry
->Size
;
1378 return STATUS_SUCCESS
;
1383 LdrDisableThreadCalloutsForDll (IN PVOID BaseAddress
)
1385 PLIST_ENTRY ModuleListHead
;
1390 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n",
1393 Status
= STATUS_DLL_NOT_FOUND
;
1395 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1396 Entry
= ModuleListHead
->Flink
;
1398 while (Entry
!= ModuleListHead
)
1400 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1402 DPRINT("BaseDllName %wZ BaseAddress %x\n",
1403 &Module
->BaseDllName
,
1404 Module
->BaseAddress
);
1406 if (Module
->BaseAddress
== BaseAddress
)
1408 if (Module
->TlsIndex
== 0)
1410 Module
->Flags
|= 0x00040000;
1411 Status
= STATUS_SUCCESS
;
1416 Entry
= Entry
->Flink
;
1424 LdrFindResourceDirectory_U (IN PVOID BaseAddress
,
1429 PIMAGE_RESOURCE_DIRECTORY ResDir
;
1430 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
1433 NTSTATUS Status
= STATUS_SUCCESS
;
1436 /* Get the pointer to the resource directory */
1437 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1438 RtlImageDirectoryEntryToData (BaseAddress
,
1440 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1444 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1447 /* Let's go into resource tree */
1448 for (i
= 0; i
< level
; i
++, name
++)
1450 EntryCount
= ResDir
->NumberOfNamedEntries
;
1451 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
1452 if ((ULONG
)(*name
) & 0xFFFF0000)
1454 /* Resource name is a unicode string */
1455 for (; EntryCount
--; ResEntry
++)
1457 /* Scan entries for equal name */
1458 if (ResEntry
->Name
& 0x80000000)
1460 ws
= (WCHAR
*)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
1461 if (!wcsncmp( *name
, ws
+ 1, *ws
) && wcslen( *name
) == (int)*ws
)
1470 /* We use ID number instead of string */
1471 ResEntry
+= EntryCount
;
1472 EntryCount
= ResDir
->NumberOfIdEntries
;
1473 for (; EntryCount
--; ResEntry
++)
1475 /* Scan entries for equal name */
1476 if (ResEntry
->Name
== (ULONG
)(*name
))
1484 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
1487 return STATUS_RESOURCE_NAME_NOT_FOUND
;
1490 Status
= STATUS_RESOURCE_LANG_NOT_FOUND
;
1491 /* Just use first language entry */
1492 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
)
1494 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
1500 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1503 return STATUS_INVALID_PARAMETER
;
1506 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResDir
+ ResEntry
->OffsetToData
);
1511 *addr
= (PVOID
)ResDir
;
1519 LdrGetDllHandle (IN ULONG Unknown1
,
1521 IN PUNICODE_STRING DllName
,
1522 OUT PVOID
*BaseAddress
)
1524 UNICODE_STRING FullDllName
;
1525 PLIST_ENTRY ModuleListHead
;
1529 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1530 Unknown1
, Unknown2
, DllName
, BaseAddress
);
1532 /* NULL is the current executable */
1533 if ( DllName
== NULL
)
1535 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
1536 DPRINT("BaseAddress %x\n", *BaseAddress
);
1537 return STATUS_SUCCESS
;
1540 LdrAdjustDllName (&FullDllName
,
1544 DPRINT("FullDllName %wZ\n",
1547 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1548 Entry
= ModuleListHead
->Flink
;
1550 while (Entry
!= ModuleListHead
)
1552 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1554 DPRINT("EntryPoint %x\n", Module
->EntryPoint
);
1555 DPRINT("Comparing %wZ and %wZ\n",
1556 &Module
->BaseDllName
,
1559 if (!RtlCompareUnicodeString(&Module
->BaseDllName
, &FullDllName
, TRUE
))
1561 RtlFreeUnicodeString (&FullDllName
);
1562 *BaseAddress
= Module
->BaseAddress
;
1563 DPRINT("BaseAddress %x\n", *BaseAddress
);
1564 return STATUS_SUCCESS
;
1567 Entry
= Entry
->Flink
;
1570 DPRINT("Failed to find dll %wZ\n", &FullDllName
);
1571 RtlFreeUnicodeString (&FullDllName
);
1572 *BaseAddress
= NULL
;
1573 return STATUS_DLL_NOT_FOUND
;
1578 LdrGetProcedureAddress (IN PVOID BaseAddress
,
1579 IN PANSI_STRING Name
,
1581 OUT PVOID
*ProcedureAddress
)
1583 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1589 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1590 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
1592 /* Get the pointer to the export directory */
1593 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1594 RtlImageDirectoryEntryToData (BaseAddress
,
1596 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1599 DPRINT("ExportDir %x i %lu\n", ExportDir
, i
);
1601 if (!ExportDir
|| !i
|| !ProcedureAddress
)
1603 return STATUS_INVALID_PARAMETER
;
1606 AddressPtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfFunctions
);
1607 if (Name
&& Name
->Length
)
1610 OrdinalPtr
= (PUSHORT
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNameOrdinals
);
1611 NamePtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNames
);
1612 for( i
= 0; i
< ExportDir
->NumberOfNames
; i
++, NamePtr
++, OrdinalPtr
++)
1614 if (!_strnicmp(Name
->Buffer
, (char*)(BaseAddress
+ *NamePtr
), Name
->Length
))
1616 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[*OrdinalPtr
]);
1617 return STATUS_SUCCESS
;
1620 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
1625 Ordinal
&= 0x0000FFFF;
1626 if (Ordinal
- ExportDir
->Base
< ExportDir
->NumberOfFunctions
)
1628 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[Ordinal
- ExportDir
->Base
]);
1629 return STATUS_SUCCESS
;
1631 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
1634 return STATUS_PROCEDURE_NOT_FOUND
;
1639 LdrShutdownProcess (VOID
)
1641 PLIST_ENTRY ModuleListHead
;
1645 DPRINT("LdrShutdownProcess() called\n");
1647 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1649 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1650 Entry
= ModuleListHead
->Blink
;
1652 while (Entry
!= ModuleListHead
)
1654 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1656 DPRINT(" Unloading %S\n",
1657 &Module
->BaseDllName
);
1658 // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
1659 // they loaded dynamically, and when the last reference is gone, that lib will
1661 if (Module
->EntryPoint
!= 0 && Module
->LoadCount
== -1)
1663 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1665 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1666 Entrypoint (Module
->BaseAddress
,
1671 Entry
= Entry
->Blink
;
1674 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1676 DPRINT("LdrShutdownProcess() done\n");
1678 return STATUS_SUCCESS
;
1683 LdrShutdownThread (VOID
)
1685 PLIST_ENTRY ModuleListHead
;
1689 DPRINT("LdrShutdownThread() called\n");
1691 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1693 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1694 Entry
= ModuleListHead
->Blink
;
1696 while (Entry
!= ModuleListHead
)
1698 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1700 DPRINT(" Unloading %wZ\n",
1701 &Module
->BaseDllName
);
1703 if (Module
->EntryPoint
!= 0)
1705 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1707 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1708 Entrypoint (Module
->BaseAddress
,
1713 Entry
= Entry
->Blink
;
1716 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1718 DPRINT("LdrShutdownThread() done\n");
1720 return STATUS_SUCCESS
;
1724 /***************************************************************************
1726 * LdrQueryProcessModuleInformation
1739 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL
,
1740 IN ULONG Size OPTIONAL
,
1741 OUT PULONG ReturnedSize
)
1744 PLIST_ENTRY ModuleListHead
;
1747 PMODULE_ENTRY ModulePtr
= NULL
;
1748 NTSTATUS Status
= STATUS_SUCCESS
;
1749 ULONG UsedSize
= sizeof(ULONG
);
1750 ANSI_STRING AnsiString
;
1753 DPRINT("LdrQueryProcessModuleInformation() called\n");
1755 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1757 if (ModuleInformation
== NULL
|| Size
== 0)
1759 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1763 ModuleInformation
->ModuleCount
= 0;
1764 ModulePtr
= &ModuleInformation
->ModuleEntry
[0];
1765 Status
= STATUS_SUCCESS
;
1768 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1769 Entry
= ModuleListHead
->Flink
;
1771 while (Entry
!= ModuleListHead
)
1773 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1775 DPRINT(" Module %wZ\n",
1776 &Module
->FullDllName
);
1778 if (UsedSize
> Size
)
1780 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1782 else if (ModuleInformation
!= NULL
)
1784 ModulePtr
->Unknown0
= 0; // FIXME: ??
1785 ModulePtr
->Unknown1
= 0; // FIXME: ??
1786 ModulePtr
->BaseAddress
= Module
->BaseAddress
;
1787 ModulePtr
->SizeOfImage
= Module
->SizeOfImage
;
1788 ModulePtr
->Flags
= Module
->Flags
;
1789 ModulePtr
->Unknown2
= 0; // FIXME: load order index ??
1790 ModulePtr
->Unknown3
= 0; // FIXME: ??
1791 ModulePtr
->LoadCount
= Module
->LoadCount
;
1793 AnsiString
.Length
= 0;
1794 AnsiString
.MaximumLength
= 256;
1795 AnsiString
.Buffer
= ModulePtr
->ModuleName
;
1796 RtlUnicodeStringToAnsiString(&AnsiString
,
1797 &Module
->FullDllName
,
1799 p
= strrchr(ModulePtr
->ModuleName
, '\\');
1801 ModulePtr
->PathLength
= p
- ModulePtr
->ModuleName
+ 1;
1803 ModulePtr
->PathLength
= 0;
1806 ModuleInformation
->ModuleCount
++;
1808 UsedSize
+= sizeof(MODULE_ENTRY
);
1810 Entry
= Entry
->Flink
;
1813 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1815 if (ReturnedSize
!= 0)
1816 *ReturnedSize
= UsedSize
;
1818 DPRINT("LdrQueryProcessModuleInformation() done\n");