1 /* $Id: utils.c,v 1.65 2003/05/12 19:47:53 ekohl Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/utils.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 /* GLOBALS *******************************************************************/
36 static HANDLE LdrpKnownDllsDirHandle
= NULL
;
37 static UNICODE_STRING LdrpKnownDllPath
= {0, 0, NULL
};
40 /* PROTOTYPES ****************************************************************/
42 static NTSTATUS
LdrFindEntryForName(PUNICODE_STRING Name
, PLDR_MODULE
*Module
);
43 static PVOID
LdrFixupForward(PCHAR ForwardName
);
44 static PVOID
LdrGetExportByName(PVOID BaseAddress
, PUCHAR SymbolName
, USHORT Hint
);
47 /* FUNCTIONS *****************************************************************/
53 LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule
)
70 OBJECT_ATTRIBUTES ObjectAttributes
;
71 UNICODE_STRING LinkTarget
;
77 DPRINT("LdrpInitLoader() called\n");
79 /* Get handle to the 'KnownDlls' directory */
80 RtlInitUnicodeString(&Name
,
82 InitializeObjectAttributes(&ObjectAttributes
,
87 Status
= NtOpenDirectoryObject(&LdrpKnownDllsDirHandle
,
88 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
90 if (!NT_SUCCESS(Status
))
92 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status
);
93 LdrpKnownDllsDirHandle
= NULL
;
97 /* Allocate target name string */
98 LinkTarget
.Length
= 0;
99 LinkTarget
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
100 LinkTarget
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
102 MAX_PATH
* sizeof(WCHAR
));
103 if (LinkTarget
.Buffer
== NULL
)
105 NtClose(LdrpKnownDllsDirHandle
);
106 LdrpKnownDllsDirHandle
= NULL
;
110 RtlInitUnicodeString(&Name
,
112 InitializeObjectAttributes(&ObjectAttributes
,
114 OBJ_CASE_INSENSITIVE
| OBJ_OPENLINK
,
115 LdrpKnownDllsDirHandle
,
117 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
118 SYMBOLIC_LINK_ALL_ACCESS
,
120 if (!NT_SUCCESS(Status
))
122 RtlFreeUnicodeString(&LinkTarget
);
123 NtClose(LdrpKnownDllsDirHandle
);
124 LdrpKnownDllsDirHandle
= NULL
;
128 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
132 if (!NT_SUCCESS(Status
))
134 RtlFreeUnicodeString(&LinkTarget
);
135 NtClose(LdrpKnownDllsDirHandle
);
136 LdrpKnownDllsDirHandle
= NULL
;
139 RtlCreateUnicodeString(&LdrpKnownDllPath
,
142 RtlFreeUnicodeString(&LinkTarget
);
144 DPRINT("LdrpInitLoader() done\n");
148 /***************************************************************************
153 * Adjusts the name of a dll to a fully qualified name.
156 * FullDllName: Pointer to caller supplied storage for the fully
157 * qualified dll name.
158 * DllName: Pointer to the dll name.
159 * BaseName: TRUE: Only the file name is passed to FullDllName
160 * FALSE: The full path is preserved in FullDllName
168 * A given path is not affected by the adjustment, but the file
170 * ntdll --> ntdll.dll
172 * ntdll.xyz --> ntdll.xyz
176 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
177 PUNICODE_STRING DllName
,
180 WCHAR Buffer
[MAX_PATH
];
185 Length
= DllName
->Length
/ sizeof(WCHAR
);
187 if (BaseName
== TRUE
)
189 /* get the base dll name */
190 Pointer
= DllName
->Buffer
+ Length
;
197 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
200 Length
= Extension
- Pointer
;
201 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
202 Buffer
[Length
] = L
'\0';
206 /* get the full dll name */
207 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
208 Buffer
[DllName
->Length
/ sizeof(WCHAR
)] = L
'\0';
211 /* Build the DLL's absolute name */
212 Extension
= wcsrchr (Buffer
, L
'.');
213 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
215 /* with extension - remove dot if it's the last character */
216 if (Buffer
[Length
- 1] == L
'.')
222 /* name without extension - assume that it is .dll */
223 memmove (Buffer
+ Length
, L
".dll", 10);
226 RtlCreateUnicodeString(FullDllName
, Buffer
);
230 LdrAddModuleEntry(PVOID ImageBase
,
231 PIMAGE_NT_HEADERS NTHeaders
,
235 Module
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE
));
237 Module
->BaseAddress
= (PVOID
)ImageBase
;
238 Module
->EntryPoint
= NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
239 if (Module
->EntryPoint
!= 0)
240 Module
->EntryPoint
+= (ULONG
)Module
->BaseAddress
;
241 Module
->SizeOfImage
= NTHeaders
->OptionalHeader
.SizeOfImage
;
242 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
244 /* loading while app is running */
245 Module
->LoadCount
= 1;
248 * loading while app is initializing
249 * dll must not be unloaded
251 Module
->LoadCount
= -1;
254 Module
->TlsIndex
= 0;
255 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
256 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
258 RtlCreateUnicodeString (&Module
->FullDllName
,
260 RtlCreateUnicodeString (&Module
->BaseDllName
,
261 wcsrchr(FullDosName
, L
'\\') + 1);
262 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
264 /* FIXME: aquire loader lock */
265 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
266 &Module
->InLoadOrderModuleList
);
267 InsertTailList(&NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
,
268 &Module
->InInitializationOrderModuleList
);
269 /* FIXME: release loader lock */
276 LdrpMapKnownDll(IN PUNICODE_STRING DllName
,
277 OUT PUNICODE_STRING FullDosName
,
278 OUT PHANDLE SectionHandle
)
280 OBJECT_ATTRIBUTES ObjectAttributes
;
281 UNICODE_STRING ObjectDirName
;
284 DPRINT("LdrpMapKnownDll() called\n");
286 if (LdrpKnownDllsDirHandle
== NULL
)
288 DPRINT("Invalid 'KnownDlls' directory\n");
289 return STATUS_UNSUCCESSFUL
;
292 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath
);
294 InitializeObjectAttributes(&ObjectAttributes
,
296 OBJ_CASE_INSENSITIVE
,
297 LdrpKnownDllsDirHandle
,
299 Status
= NtOpenSection(SectionHandle
,
300 SECTION_MAP_READ
| SECTION_MAP_WRITE
| SECTION_MAP_EXECUTE
,
302 if (!NT_SUCCESS(Status
))
304 DPRINT("NtOpenSection() failed for '%wZ' (Status %lx)\n", DllName
, Status
);
308 FullDosName
->Length
= LdrpKnownDllPath
.Length
+ DllName
->Length
+ sizeof(WCHAR
);
309 FullDosName
->MaximumLength
= FullDosName
->Length
+ sizeof(WCHAR
);
310 FullDosName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
312 FullDosName
->MaximumLength
);
313 if (FullDosName
->Buffer
== NULL
)
315 FullDosName
->Length
= 0;
316 FullDosName
->MaximumLength
= 0;
317 return STATUS_SUCCESS
;
320 wcscpy(FullDosName
->Buffer
, LdrpKnownDllPath
.Buffer
);
321 wcscat(FullDosName
->Buffer
, L
"\\");
322 wcscat(FullDosName
->Buffer
, DllName
->Buffer
);
324 DPRINT("FullDosName '%wZ'\n", FullDosName
);
326 DPRINT("LdrpMapKnownDll() done\n");
328 return STATUS_SUCCESS
;
333 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL
,
334 IN PUNICODE_STRING DllName
,
335 OUT PUNICODE_STRING FullDosName
,
336 OUT PHANDLE SectionHandle
)
338 WCHAR SearchPathBuffer
[MAX_PATH
];
339 WCHAR DosName
[MAX_PATH
];
340 UNICODE_STRING FullNtFileName
;
341 OBJECT_ATTRIBUTES FileObjectAttributes
;
343 char BlockBuffer
[1024];
344 PIMAGE_DOS_HEADER DosHeader
;
345 PIMAGE_NT_HEADERS NTHeaders
;
350 DPRINT("LdrpMapDllImageFile() called\n");
352 if (SearchPath
== NULL
)
354 SearchPath
= SearchPathBuffer
;
355 wcscpy (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
356 wcscat (SearchPathBuffer
, L
"\\system32;");
357 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
358 wcscat (SearchPathBuffer
, L
";.");
361 DPRINT("SearchPath %S\n", SearchPath
);
363 if (RtlDosSearchPath_U (SearchPath
,
369 return STATUS_DLL_NOT_FOUND
;
371 DPRINT("DosName %S\n", DosName
);
373 if (!RtlDosPathNameToNtPathName_U (DosName
,
377 return STATUS_DLL_NOT_FOUND
;
379 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
381 InitializeObjectAttributes(&FileObjectAttributes
,
387 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
389 Status
= ZwOpenFile(&FileHandle
,
391 &FileObjectAttributes
,
395 if (!NT_SUCCESS(Status
))
397 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
398 &FullNtFileName
, Status
);
399 RtlFreeUnicodeString (&FullNtFileName
);
402 RtlFreeUnicodeString (&FullNtFileName
);
404 Status
= ZwReadFile(FileHandle
,
413 if (!NT_SUCCESS(Status
))
415 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
420 * Overlay DOS and NT headers structures to the
421 * buffer with DLL's header raw data.
423 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
424 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
426 * Check it is a PE image file.
428 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
429 || (DosHeader
->e_lfanew
== 0L)
430 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
432 DPRINT("NTDLL format invalid\n");
435 return STATUS_UNSUCCESSFUL
;
438 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
439 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
441 DPRINT("ImageBase 0x%08x\n", ImageBase
);
444 * Create a section for dll.
446 Status
= ZwCreateSection(SectionHandle
,
451 SEC_COMMIT
| SEC_IMAGE
,
455 if (!NT_SUCCESS(Status
))
457 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
461 RtlCreateUnicodeString(FullDosName
,
469 /***************************************************************************
486 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
488 IN PUNICODE_STRING Name
,
489 OUT PVOID
*BaseAddress OPTIONAL
)
491 UNICODE_STRING FullDosName
;
492 UNICODE_STRING AdjustedName
;
494 PIMAGE_NT_HEADERS NTHeaders
;
497 HANDLE SectionHandle
;
498 PDLLMAIN_FUNC Entrypoint
= NULL
;
504 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
505 return STATUS_SUCCESS
;
510 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
513 /* adjust the full dll name */
514 LdrAdjustDllName (&AdjustedName
,
517 DPRINT("AdjustedName: %wZ\n", &AdjustedName
);
520 * Test if dll is already loaded.
522 if (LdrFindEntryForName(&AdjustedName
, &Module
) == STATUS_SUCCESS
)
524 DPRINT("DLL %wZ already loaded.\n", &AdjustedName
);
525 if (Module
->LoadCount
!= -1)
527 *BaseAddress
= Module
->BaseAddress
;
528 return STATUS_SUCCESS
;
530 DPRINT("Loading \"%wZ\"\n", Name
);
532 /* Open or create dll image section */
533 Status
= LdrpMapKnownDll(&AdjustedName
,
536 if (!NT_SUCCESS(Status
))
538 Status
= LdrpMapDllImageFile(SearchPath
,
544 RtlFreeUnicodeString(&AdjustedName
);
546 if (!NT_SUCCESS(Status
))
548 DPRINT1("Failed to create or open dll section (Status %lx)\n", Status
);
553 * Map the dll into the process.
557 Status
= NtMapViewOfSection(SectionHandle
,
567 if (!NT_SUCCESS(Status
))
569 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n", Status
);
570 RtlFreeUnicodeString(&FullDosName
);
571 NtClose(SectionHandle
);
575 /* Get and check the NT headers */
576 NTHeaders
= RtlImageNtHeader(ImageBase
);
577 if (NTHeaders
== NULL
)
579 DPRINT1("RtlImageNtHeaders() failed\n");
580 RtlFreeUnicodeString(&FullDosName
);
581 return STATUS_UNSUCCESSFUL
;
584 /* relocate dll and fixup import table */
585 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
589 (PDLLMAIN_FUNC
) LdrPEStartup(ImageBase
, SectionHandle
, &Module
,
591 if (Entrypoint
== NULL
)
593 RtlFreeUnicodeString(&FullDosName
);
594 return(STATUS_UNSUCCESSFUL
);
598 RtlFreeUnicodeString(&FullDosName
);
602 LdrpLoadUserModuleSymbols(Module
);
607 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
610 if (Module
->EntryPoint
!= 0)
612 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
614 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
615 if (FALSE
== Entrypoint(Module
->BaseAddress
,
619 /* Do this as a DPRINT1 for now, until clean up and fail implemented */
620 DPRINT1("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
621 &Module
->BaseDllName
);
622 /* FIXME: should clean up and fail */
626 DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
627 &Module
->BaseDllName
);
632 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
633 &Module
->BaseDllName
);
637 *BaseAddress
= Module
->BaseAddress
;
638 return STATUS_SUCCESS
;
642 /***************************************************************************
644 * LdrFindEntryForAddress
658 LdrFindEntryForAddress(PVOID Address
,
661 PLIST_ENTRY ModuleListHead
;
663 PLDR_MODULE ModulePtr
;
665 DPRINT("NTDLL.LdrFindEntryForAddress(Address %p)\n", Address
);
667 if (NtCurrentPeb()->Ldr
== NULL
)
668 return(STATUS_NO_MORE_ENTRIES
);
670 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
671 Entry
= ModuleListHead
->Flink
;
672 if (Entry
== ModuleListHead
)
673 return(STATUS_NO_MORE_ENTRIES
);
675 while (Entry
!= ModuleListHead
)
677 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
679 DPRINT("Scanning %wZ at %p\n", &ModulePtr
->BaseDllName
, ModulePtr
->BaseAddress
);
681 if ((Address
>= ModulePtr
->BaseAddress
) &&
682 (Address
<= (ModulePtr
->BaseAddress
+ ModulePtr
->SizeOfImage
)))
685 return(STATUS_SUCCESS
);
688 Entry
= Entry
->Flink
;
691 DPRINT("Failed to find module entry.\n");
693 return(STATUS_NO_MORE_ENTRIES
);
697 /***************************************************************************
699 * LdrFindEntryForName
713 LdrFindEntryForName(PUNICODE_STRING Name
,
716 PLIST_ENTRY ModuleListHead
;
718 PLDR_MODULE ModulePtr
;
719 BOOLEAN ContainsPath
;
722 DPRINT("NTDLL.LdrFindEntryForName(Name %wZ)\n", Name
);
724 if (NtCurrentPeb()->Ldr
== NULL
)
725 return(STATUS_NO_MORE_ENTRIES
);
727 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
728 Entry
= ModuleListHead
->Flink
;
729 if (Entry
== ModuleListHead
)
730 return(STATUS_NO_MORE_ENTRIES
);
732 // NULL is the current process
735 *Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
736 return(STATUS_SUCCESS
);
739 ContainsPath
= (2 <= Name
->Length
&& L
':' == Name
->Buffer
[1]);
740 for (i
= 0; ! ContainsPath
&& i
< Name
->Length
; i
++)
742 ContainsPath
= L
'\\' == Name
->Buffer
[i
] ||
743 L
'/' == Name
->Buffer
[i
];
745 while (Entry
!= ModuleListHead
)
747 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
749 DPRINT("Scanning %wZ %wZ\n", &ModulePtr
->BaseDllName
, Name
);
751 if ((! ContainsPath
&&
752 0 == RtlCompareUnicodeString(&ModulePtr
->BaseDllName
, Name
, TRUE
)) ||
754 0 == RtlCompareUnicodeString(&ModulePtr
->FullDllName
, Name
, TRUE
)))
757 return(STATUS_SUCCESS
);
760 Entry
= Entry
->Flink
;
763 DPRINT("Failed to find dll %wZ\n", Name
);
765 return(STATUS_NO_MORE_ENTRIES
);
768 /**********************************************************************
784 LdrFixupForward(PCHAR ForwardName
)
786 CHAR NameBuffer
[128];
787 UNICODE_STRING DllName
;
788 UNICODE_STRING FunctionName
;
793 strcpy(NameBuffer
, ForwardName
);
794 p
= strchr(NameBuffer
, '.');
799 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
800 RtlCreateUnicodeStringFromAsciiz (&DllName
,
803 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
804 if (!NT_SUCCESS(Status
))
806 Status
= LdrLoadDll(NULL
,
810 if (!NT_SUCCESS(Status
))
812 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName
);
813 RtlFreeUnicodeString (&DllName
);
818 RtlFreeUnicodeString (&DllName
);
819 DPRINT("BaseAddress: %p\n", BaseAddress
);
821 return LdrGetExportByName(BaseAddress
, p
+1, -1);
828 /**********************************************************************
830 * LdrGetExportByOrdinal
844 LdrGetExportByOrdinal (
849 PIMAGE_EXPORT_DIRECTORY ExportDir
;
850 PDWORD
* ExFunctions
;
853 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
854 RtlImageDirectoryEntryToData (BaseAddress
,
856 IMAGE_DIRECTORY_ENTRY_EXPORT
,
860 ExOrdinals
= (USHORT
*)
863 ExportDir
->AddressOfNameOrdinals
865 ExFunctions
= (PDWORD
*)
868 ExportDir
->AddressOfFunctions
871 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
873 RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
875 return(RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] ));
879 /**********************************************************************
892 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
893 * both with NumberOfNames entries.
897 LdrGetExportByName(PVOID BaseAddress
,
901 PIMAGE_EXPORT_DIRECTORY ExportDir
;
902 PDWORD
* ExFunctions
;
912 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
914 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
915 RtlImageDirectoryEntryToData(BaseAddress
,
917 IMAGE_DIRECTORY_ENTRY_EXPORT
,
919 if (ExportDir
== NULL
)
921 DbgPrint("LdrGetExportByName(): no export directory!\n");
926 //The symbol names may be missing entirely
927 if (ExportDir
->AddressOfNames
== 0)
929 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
934 * Get header pointers
936 ExNames
= (PDWORD
*)RVA(BaseAddress
,
937 ExportDir
->AddressOfNames
);
938 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
939 ExportDir
->AddressOfNameOrdinals
);
940 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
941 ExportDir
->AddressOfFunctions
);
944 * Check the hint first
946 if (Hint
< ExportDir
->NumberOfNames
)
948 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
949 if (strcmp(ExName
, SymbolName
) == 0)
951 Ordinal
= ExOrdinals
[Hint
];
952 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
953 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
954 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
956 DPRINT("Forward: %s\n", (PCHAR
)Function
);
957 Function
= LdrFixupForward((PCHAR
)Function
);
959 if (Function
!= NULL
)
965 * Try a binary search first
968 maxn
= ExportDir
->NumberOfNames
;
974 mid
= (minn
+ maxn
) / 2;
976 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
977 res
= strcmp(ExName
, SymbolName
);
980 Ordinal
= ExOrdinals
[mid
];
981 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
982 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
983 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
985 DPRINT("Forward: %s\n", (PCHAR
)Function
);
986 Function
= LdrFixupForward((PCHAR
)Function
);
988 if (Function
!= NULL
)
991 else if (minn
== maxn
)
993 DPRINT("LdrGetExportByName(): binary search failed\n");
1007 * Fall back on a linear search
1009 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
1010 for (i
= 0; i
< ExportDir
->NumberOfNames
; i
++)
1012 ExName
= RVA(BaseAddress
, ExNames
[i
]);
1013 if (strcmp(ExName
,SymbolName
) == 0)
1015 Ordinal
= ExOrdinals
[i
];
1016 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1017 DPRINT("%x %x %x\n", Function
, ExportDir
, ExportDir
+ ExportDirSize
);
1018 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1019 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1021 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1022 Function
= LdrFixupForward((PCHAR
)Function
);
1027 DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1032 /**********************************************************************
1034 * LdrPerformRelocations
1037 * Relocate a DLL's memory image.
1048 static NTSTATUS
LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders
,
1051 USHORT NumberOfEntries
;
1053 ULONG RelocationRVA
;
1057 PRELOCATION_DIRECTORY RelocationDir
;
1058 PRELOCATION_ENTRY RelocationBlock
;
1060 PIMAGE_DATA_DIRECTORY RelocationDDir
;
1064 PIMAGE_SECTION_HEADER Sections
;
1069 (PIMAGE_SECTION_HEADER
)((PVOID
)NTHeaders
+ sizeof(IMAGE_NT_HEADERS
));
1071 for (i
= 0; i
< NTHeaders
->FileHeader
.NumberOfSections
; i
++)
1073 if (!(Sections
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
1077 (ULONG
)(Sections
[i
].VirtualAddress
+ Sections
[i
].Misc
.VirtualSize
);
1078 MaxExtend
= max(MaxExtend
, Extend
);
1083 &NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1084 RelocationRVA
= RelocationDDir
->VirtualAddress
;
1089 (PRELOCATION_DIRECTORY
)((PCHAR
)ImageBase
+ RelocationRVA
);
1091 while (RelocationDir
->SizeOfBlock
)
1093 if (RelocationDir
->VirtualAddress
> MaxExtend
)
1095 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
1097 (PRELOCATION_DIRECTORY
) (ImageBase
+ RelocationRVA
);
1101 Delta32
= (ULONG
)(ImageBase
- NTHeaders
->OptionalHeader
.ImageBase
);
1103 (PRELOCATION_ENTRY
) (RelocationRVA
+ ImageBase
+
1104 sizeof (RELOCATION_DIRECTORY
));
1106 RelocationDir
->SizeOfBlock
- sizeof (RELOCATION_DIRECTORY
);
1107 NumberOfEntries
= NumberOfEntries
/ sizeof (RELOCATION_ENTRY
);
1109 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1111 RelocationDir
->VirtualAddress
,
1115 if (!NT_SUCCESS(Status
))
1117 DPRINT1("Failed to unprotect relocation target.\n");
1121 if (RelocationDir
->VirtualAddress
+ PAGE_SIZE
< MaxExtend
)
1123 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1125 RelocationDir
->VirtualAddress
+ PAGE_SIZE
,
1129 if (!NT_SUCCESS(Status
))
1131 DPRINT1("Failed to unprotect relocation target (2).\n");
1132 NtProtectVirtualMemory(NtCurrentProcess(),
1134 RelocationDir
->VirtualAddress
,
1142 for (i
= 0; i
< NumberOfEntries
; i
++)
1144 Offset
= (RelocationBlock
[i
].TypeOffset
& 0xfff);
1145 Offset
+= (ULONG
)(RelocationDir
->VirtualAddress
+ ImageBase
);
1148 * What kind of relocations should we perform
1149 * for the current entry?
1151 switch (RelocationBlock
[i
].TypeOffset
>> 12)
1153 case TYPE_RELOC_ABSOLUTE
:
1156 case TYPE_RELOC_HIGH
:
1157 pValue16
= (PUSHORT
)Offset
;
1158 *pValue16
+= Delta32
>> 16;
1161 case TYPE_RELOC_LOW
:
1162 pValue16
= (PUSHORT
)Offset
;
1163 *pValue16
+= Delta32
& 0xffff;
1166 case TYPE_RELOC_HIGHLOW
:
1167 pValue32
= (PULONG
)Offset
;
1168 *pValue32
+= Delta32
;
1171 case TYPE_RELOC_HIGHADJ
:
1172 /* FIXME: do the highadjust fixup */
1173 DPRINT("TYPE_RELOC_HIGHADJ fixup not implemented, sorry\n");
1174 return(STATUS_UNSUCCESSFUL
);
1177 DPRINT("unexpected fixup type\n");
1178 return STATUS_UNSUCCESSFUL
;
1182 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1184 RelocationDir
->VirtualAddress
,
1188 if (!NT_SUCCESS(Status
))
1190 DPRINT1("Failed to protect relocation target.\n");
1194 if (RelocationDir
->VirtualAddress
+ PAGE_SIZE
< MaxExtend
)
1196 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1198 RelocationDir
->VirtualAddress
+ PAGE_SIZE
,
1202 if (!NT_SUCCESS(Status
))
1204 DPRINT1("Failed to protect relocation target2.\n");
1209 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
1211 (PRELOCATION_DIRECTORY
) (ImageBase
+ RelocationRVA
);
1214 return STATUS_SUCCESS
;
1218 /**********************************************************************
1223 * Compute the entry point for every symbol the DLL imports
1224 * from other modules.
1235 static NTSTATUS
LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders
,
1238 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1244 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders
,
1248 * Process each import module.
1250 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)(
1251 ImageBase
+ NTHeaders
->OptionalHeader
1252 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
1254 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
1256 while (ImportModuleDirectory
->dwRVAModuleName
)
1258 PVOID
* ImportAddressList
;
1259 PULONG FunctionNameList
;
1260 UNICODE_STRING DllName
;
1266 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
1267 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
1269 RtlCreateUnicodeStringFromAsciiz (&DllName
,
1270 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
1272 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
1273 if (!NT_SUCCESS(Status
))
1275 Status
= LdrLoadDll(NULL
,
1279 RtlFreeUnicodeString (&DllName
);
1280 if (!NT_SUCCESS(Status
))
1282 DbgPrint("LdrFixupImports:failed to load %s\n"
1284 + ImportModuleDirectory
->dwRVAModuleName
));
1291 * Get the import address list.
1293 ImportAddressList
= (PVOID
*)(ImageBase
1294 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
1297 * Get the list of functions to import.
1299 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1301 FunctionNameList
= (PULONG
) (
1303 + ImportModuleDirectory
->dwRVAFunctionNameList
1310 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
1314 * Get the size of IAT.
1317 while (FunctionNameList
[IATSize
] != 0L)
1323 * Unprotect the region we are about to write into.
1325 IATBase
= (PVOID
)ImportAddressList
;
1326 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1328 IATSize
* sizeof(PVOID
*),
1331 if (!NT_SUCCESS(Status
))
1333 DbgPrint("LDR: Failed to unprotect IAT.\n");
1338 * Walk through function list and fixup addresses.
1340 while (*FunctionNameList
!= 0L)
1342 if ((*FunctionNameList
) & 0x80000000)
1344 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
1345 *ImportAddressList
=
1346 LdrGetExportByOrdinal(BaseAddress
,
1351 pName
= (DWORD
) (ImageBase
+ *FunctionNameList
+ 2);
1352 pHint
= *(PWORD
)(ImageBase
+ *FunctionNameList
);
1354 *ImportAddressList
=
1355 LdrGetExportByName(BaseAddress
, (PUCHAR
)pName
, pHint
);
1356 if ((*ImportAddressList
) == NULL
)
1358 DbgPrint("Failed to import %s\n", pName
);
1359 return STATUS_UNSUCCESSFUL
;
1362 ImportAddressList
++;
1367 * Protect the region we are about to write into.
1369 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1371 IATSize
* sizeof(PVOID
*),
1374 if (!NT_SUCCESS(Status
))
1376 DbgPrint("LDR: Failed to protect IAT.\n");
1380 ImportModuleDirectory
++;
1382 return STATUS_SUCCESS
;
1386 /**********************************************************************
1391 * 1. Map the DLL's sections into memory.
1392 * 2. Relocate, if needed the DLL.
1393 * 3. Fixup any imported symbol.
1394 * 4. Compute the DLL's entry point.
1398 * Address at which the DLL's image
1402 * Handle of the section that contains
1406 * NULL on error; otherwise the entry point
1407 * to call for initializing the DLL.
1414 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
1415 HANDLE SectionHandle
,
1416 PLDR_MODULE
* Module
,
1420 PEPFUNC EntryPoint
= NULL
;
1421 PIMAGE_DOS_HEADER DosHeader
;
1422 PIMAGE_NT_HEADERS NTHeaders
;
1424 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1425 ImageBase
, (ULONG
)SectionHandle
);
1428 * Overlay DOS and WNT headers structures
1429 * to the DLL's image.
1431 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
1432 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
1435 * If the base address is different from the
1436 * one the DLL is actually loaded, perform any
1439 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1441 DbgPrint("LDR: Performing relocations\n");
1442 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
1443 if (!NT_SUCCESS(Status
))
1445 DbgPrint("LdrPerformRelocations() failed\n");
1452 *Module
= LdrAddModuleEntry(ImageBase
, NTHeaders
, FullDosName
);
1456 * If the DLL's imports symbols from other
1457 * modules, fixup the imported calls entry points.
1459 if (NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
1460 .VirtualAddress
!= 0)
1462 DPRINT("About to fixup imports\n");
1463 Status
= LdrFixupImports(NTHeaders
, ImageBase
);
1464 if (!NT_SUCCESS(Status
))
1466 DbgPrint("LdrFixupImports() failed\n");
1469 DPRINT("Fixup done\n");
1473 * Compute the DLL's entry point's address.
1475 DPRINT("ImageBase = %x\n",(ULONG
)ImageBase
);
1476 DPRINT("AddressOfEntryPoint = %x\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1477 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
1479 EntryPoint
= (PEPFUNC
) (ImageBase
1480 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1482 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
1488 LdrUnloadDll (IN PVOID BaseAddress
)
1490 PIMAGE_NT_HEADERS NtHeaders
;
1491 PDLLMAIN_FUNC Entrypoint
;
1492 PLIST_ENTRY ModuleListHead
;
1497 if (BaseAddress
== NULL
)
1498 return STATUS_SUCCESS
;
1500 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1501 Entry
= ModuleListHead
->Flink
;
1503 while (Entry
!= ModuleListHead
)
1505 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1506 if (Module
->BaseAddress
== BaseAddress
)
1508 if (Module
->LoadCount
== -1)
1510 /* never unload this dll */
1511 return STATUS_SUCCESS
;
1513 else if (Module
->LoadCount
> 1)
1515 Module
->LoadCount
--;
1516 return STATUS_SUCCESS
;
1519 NtHeaders
= RtlImageNtHeader (Module
->BaseAddress
);
1520 if ((NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) == IMAGE_FILE_DLL
)
1522 if (Module
->EntryPoint
!= 0)
1524 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1525 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1526 Entrypoint(Module
->BaseAddress
,
1532 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1535 Status
= ZwUnmapViewOfSection (NtCurrentProcess (),
1536 Module
->BaseAddress
);
1537 ZwClose (Module
->SectionHandle
);
1539 /* remove the module entry from the list */
1540 RtlFreeUnicodeString (&Module
->FullDllName
);
1541 RtlFreeUnicodeString (&Module
->BaseDllName
);
1542 RemoveEntryList (Entry
);
1543 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
1548 Entry
= Entry
->Flink
;
1551 DPRINT("NTDLL.LDR: Dll not found\n")
1553 return STATUS_UNSUCCESSFUL
;
1558 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
1560 PLIST_ENTRY ModuleListHead
;
1565 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress
);
1567 Status
= STATUS_DLL_NOT_FOUND
;
1568 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1569 Entry
= ModuleListHead
->Flink
;
1570 while (Entry
!= ModuleListHead
) {
1571 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1573 DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module
->BaseDllName
, Module
->BaseAddress
);
1575 if (Module
->BaseAddress
== BaseAddress
) {
1576 if (Module
->TlsIndex
== 0) {
1577 Module
->Flags
|= 0x00040000;
1578 Status
= STATUS_SUCCESS
;
1582 Entry
= Entry
->Flink
;
1589 LdrGetDllHandle(IN ULONG Unknown1
,
1591 IN PUNICODE_STRING DllName
,
1592 OUT PVOID
* BaseAddress
)
1594 UNICODE_STRING FullDllName
;
1595 PLIST_ENTRY ModuleListHead
;
1599 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1600 Unknown1
, Unknown2
, DllName
, BaseAddress
);
1602 /* NULL is the current executable */
1603 if (DllName
== NULL
) {
1604 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
1605 DPRINT("BaseAddress %x\n", *BaseAddress
);
1606 return STATUS_SUCCESS
;
1608 LdrAdjustDllName(&FullDllName
, DllName
, TRUE
);
1610 DPRINT("FullDllName %wZ\n", &FullDllName
);
1612 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1613 Entry
= ModuleListHead
->Flink
;
1614 while (Entry
!= ModuleListHead
) {
1615 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1617 DPRINT("EntryPoint %x\n", Module
->EntryPoint
);
1618 DPRINT("Comparing %wZ and %wZ\n", &Module
->BaseDllName
, &FullDllName
);
1620 if (!RtlCompareUnicodeString(&Module
->BaseDllName
, &FullDllName
, TRUE
)) {
1621 RtlFreeUnicodeString(&FullDllName
);
1622 *BaseAddress
= Module
->BaseAddress
;
1623 DPRINT("BaseAddress %x\n", *BaseAddress
);
1624 return STATUS_SUCCESS
;
1626 Entry
= Entry
->Flink
;
1629 DPRINT("Failed to find dll %wZ\n", &FullDllName
);
1631 RtlFreeUnicodeString(&FullDllName
);
1632 *BaseAddress
= NULL
;
1633 return STATUS_DLL_NOT_FOUND
;
1638 LdrGetProcedureAddress (IN PVOID BaseAddress
,
1639 IN PANSI_STRING Name
,
1641 OUT PVOID
*ProcedureAddress
)
1643 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1649 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1650 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
1652 /* Get the pointer to the export directory */
1653 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1654 RtlImageDirectoryEntryToData (BaseAddress
,
1656 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1659 DPRINT("ExportDir %x i %lu\n", ExportDir
, i
);
1661 if (!ExportDir
|| !i
|| !ProcedureAddress
)
1663 return STATUS_INVALID_PARAMETER
;
1666 AddressPtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfFunctions
);
1667 if (Name
&& Name
->Length
)
1670 OrdinalPtr
= (PUSHORT
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNameOrdinals
);
1671 NamePtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNames
);
1672 for( i
= 0; i
< ExportDir
->NumberOfNames
; i
++, NamePtr
++, OrdinalPtr
++)
1674 if (!_strnicmp(Name
->Buffer
, (char*)(BaseAddress
+ *NamePtr
), Name
->Length
))
1676 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[*OrdinalPtr
]);
1677 return STATUS_SUCCESS
;
1680 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
1685 Ordinal
&= 0x0000FFFF;
1686 if (Ordinal
- ExportDir
->Base
< ExportDir
->NumberOfFunctions
)
1688 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[Ordinal
- ExportDir
->Base
]);
1689 return STATUS_SUCCESS
;
1691 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
1694 return STATUS_PROCEDURE_NOT_FOUND
;
1699 LdrShutdownProcess (VOID
)
1701 PLIST_ENTRY ModuleListHead
;
1705 DPRINT("LdrShutdownProcess() called\n");
1707 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1709 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1710 Entry
= ModuleListHead
->Blink
;
1712 while (Entry
!= ModuleListHead
)
1714 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1716 DPRINT(" Unloading %wZ\n",
1717 &Module
->BaseDllName
);
1718 // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
1719 // they loaded dynamically, and when the last reference is gone, that lib will
1721 if (Module
->EntryPoint
!= 0 && Module
->LoadCount
== -1)
1723 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1725 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1726 Entrypoint (Module
->BaseAddress
,
1731 Entry
= Entry
->Blink
;
1734 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1736 DPRINT("LdrShutdownProcess() done\n");
1738 return STATUS_SUCCESS
;
1743 LdrShutdownThread (VOID
)
1745 PLIST_ENTRY ModuleListHead
;
1749 DPRINT("LdrShutdownThread() called\n");
1751 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1753 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1754 Entry
= ModuleListHead
->Blink
;
1756 while (Entry
!= ModuleListHead
)
1758 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1760 DPRINT(" Unloading %wZ\n",
1761 &Module
->BaseDllName
);
1763 if (Module
->EntryPoint
!= 0)
1765 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1767 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1768 Entrypoint (Module
->BaseAddress
,
1773 Entry
= Entry
->Blink
;
1776 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1778 DPRINT("LdrShutdownThread() done\n");
1780 return STATUS_SUCCESS
;
1784 /***************************************************************************
1786 * LdrQueryProcessModuleInformation
1799 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL
,
1800 IN ULONG Size OPTIONAL
,
1801 OUT PULONG ReturnedSize
)
1803 PLIST_ENTRY ModuleListHead
;
1806 PMODULE_ENTRY ModulePtr
= NULL
;
1807 NTSTATUS Status
= STATUS_SUCCESS
;
1808 ULONG UsedSize
= sizeof(ULONG
);
1809 ANSI_STRING AnsiString
;
1812 DPRINT("LdrQueryProcessModuleInformation() called\n");
1814 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1816 if (ModuleInformation
== NULL
|| Size
== 0)
1818 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1822 ModuleInformation
->ModuleCount
= 0;
1823 ModulePtr
= &ModuleInformation
->ModuleEntry
[0];
1824 Status
= STATUS_SUCCESS
;
1827 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1828 Entry
= ModuleListHead
->Flink
;
1830 while (Entry
!= ModuleListHead
)
1832 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1834 DPRINT(" Module %wZ\n",
1835 &Module
->FullDllName
);
1837 if (UsedSize
> Size
)
1839 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1841 else if (ModuleInformation
!= NULL
)
1843 ModulePtr
->Unknown0
= 0; // FIXME: ??
1844 ModulePtr
->Unknown1
= 0; // FIXME: ??
1845 ModulePtr
->BaseAddress
= Module
->BaseAddress
;
1846 ModulePtr
->SizeOfImage
= Module
->SizeOfImage
;
1847 ModulePtr
->Flags
= Module
->Flags
;
1848 ModulePtr
->Unknown2
= 0; // FIXME: load order index ??
1849 ModulePtr
->Unknown3
= 0; // FIXME: ??
1850 ModulePtr
->LoadCount
= Module
->LoadCount
;
1852 AnsiString
.Length
= 0;
1853 AnsiString
.MaximumLength
= 256;
1854 AnsiString
.Buffer
= ModulePtr
->ModuleName
;
1855 RtlUnicodeStringToAnsiString(&AnsiString
,
1856 &Module
->FullDllName
,
1858 p
= strrchr(ModulePtr
->ModuleName
, '\\');
1860 ModulePtr
->PathLength
= p
- ModulePtr
->ModuleName
+ 1;
1862 ModulePtr
->PathLength
= 0;
1865 ModuleInformation
->ModuleCount
++;
1867 UsedSize
+= sizeof(MODULE_ENTRY
);
1869 Entry
= Entry
->Flink
;
1872 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1874 if (ReturnedSize
!= 0)
1875 *ReturnedSize
= UsedSize
;
1877 DPRINT("LdrQueryProcessModuleInformation() done\n");