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 *****************************************************************/
17 /* GLOBALS *******************************************************************/
19 LIST_ENTRY LdrpUnloadHead
;
20 LONG LdrpLoaderLockAcquisitonCount
;
21 BOOLEAN LdrpShowRecursiveLoads
, LdrpBreakOnRecursiveDllLoads
;
22 UNICODE_STRING LdrApiDefaultExtension
= RTL_CONSTANT_STRING(L
".DLL");
23 ULONG AlternateResourceModuleCount
;
25 /* FUNCTIONS *****************************************************************/
29 LdrFindCreateProcessManifest(IN ULONG Flags
,
32 IN ULONG IdPathLength
,
33 IN PVOID OutDataEntry
)
36 return STATUS_NOT_IMPLEMENTED
;
41 LdrDestroyOutOfProcessImage(IN PVOID Image
)
44 return STATUS_NOT_IMPLEMENTED
;
49 LdrCreateOutOfProcessImage(IN ULONG Flags
,
50 IN HANDLE ProcessHandle
,
55 return STATUS_NOT_IMPLEMENTED
;
60 LdrAccessOutOfProcessResource(IN PVOID Unknown
,
67 return STATUS_NOT_IMPLEMENTED
;
72 LdrSetDllManifestProber(IN PVOID ProberFunction
)
79 LdrAlternateResourcesEnabled(VOID
)
81 /* ReactOS does not support this */
89 /* Generate a cookie */
90 return (((ULONG_PTR
)NtCurrentTeb()->RealClientId
.UniqueThread
& 0xFFF) << 16) |
91 (_InterlockedIncrement(&LdrpLoaderLockAcquisitonCount
) & 0xFFFF);
99 LdrUnlockLoaderLock(IN ULONG Flags
,
100 IN ULONG Cookie OPTIONAL
)
102 NTSTATUS Status
= STATUS_SUCCESS
;
104 DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags
, Cookie
);
106 /* Check for valid flags */
107 if (Flags
& ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
109 /* Flags are invalid, check how to fail */
110 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
112 /* The caller wants us to raise status */
113 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
116 /* A normal failure */
117 return STATUS_INVALID_PARAMETER_1
;
120 /* If we don't have a cookie, just return */
121 if (!Cookie
) return STATUS_SUCCESS
;
123 /* Validate the cookie */
124 if ((Cookie
& 0xF0000000) ||
125 ((Cookie
>> 16) ^ ((ULONG
)(NtCurrentTeb()->RealClientId
.UniqueThread
) & 0xFFF)))
127 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
129 /* Invalid cookie, check how to fail */
130 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
132 /* The caller wants us to raise status */
133 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
136 /* A normal failure */
137 return STATUS_INVALID_PARAMETER_2
;
140 /* Ready to release the lock */
141 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
143 /* Do a direct leave */
144 RtlLeaveCriticalSection(&LdrpLoaderLock
);
148 /* Wrap this in SEH, since we're not supposed to raise */
152 RtlLeaveCriticalSection(&LdrpLoaderLock
);
154 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
156 /* We should use the LDR Filter instead */
157 Status
= _SEH2_GetExceptionCode();
171 LdrLockLoaderLock(IN ULONG Flags
,
172 OUT PULONG Disposition OPTIONAL
,
173 OUT PULONG_PTR Cookie OPTIONAL
)
175 NTSTATUS Status
= STATUS_SUCCESS
;
176 BOOLEAN InInit
= LdrpInLdrInit
;
178 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags
, Disposition
, Cookie
);
180 /* Zero out the outputs */
181 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID
;
182 if (Cookie
) *Cookie
= 0;
184 /* Validate the flags */
185 if (Flags
& ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
|
186 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
))
188 /* Flags are invalid, check how to fail */
189 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
191 /* The caller wants us to raise status */
192 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
195 /* A normal failure */
196 return STATUS_INVALID_PARAMETER_1
;
199 /* Make sure we got a cookie */
202 /* No cookie check how to fail */
203 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
205 /* The caller wants us to raise status */
206 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3
);
209 /* A normal failure */
210 return STATUS_INVALID_PARAMETER_3
;
213 /* Do or Do Not. There is no Try */
214 ASSERT((Disposition
!= NULL
) || !(Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
));
216 /* If the flag is set, make sure we have a valid pointer to use */
217 if ((Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
) && !(Disposition
))
219 /* No pointer to return the data to */
220 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
222 /* The caller wants us to raise status */
223 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
227 return STATUS_INVALID_PARAMETER_2
;
230 /* Return now if we are in the init phase */
231 if (InInit
) return STATUS_SUCCESS
;
233 /* Check what locking semantic to use */
234 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
236 /* Check if we should enter or simply try */
237 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
240 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
243 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
248 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
249 *Cookie
= LdrpMakeCookie();
255 RtlEnterCriticalSection(&LdrpLoaderLock
);
257 /* See if result was requested */
258 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
259 *Cookie
= LdrpMakeCookie();
264 /* Wrap this in SEH, since we're not supposed to raise */
267 /* Check if we should enter or simply try */
268 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
271 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
274 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
279 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
280 *Cookie
= LdrpMakeCookie();
286 RtlEnterCriticalSection(&LdrpLoaderLock
);
288 /* See if result was requested */
289 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
290 *Cookie
= LdrpMakeCookie();
293 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
295 /* We should use the LDR Filter instead */
296 Status
= _SEH2_GetExceptionCode();
311 LdrLoadDll(IN PWSTR SearchPath OPTIONAL
,
312 IN PULONG DllCharacteristics OPTIONAL
,
313 IN PUNICODE_STRING DllName
,
314 OUT PVOID
*BaseAddress
)
316 WCHAR StringBuffer
[MAX_PATH
];
317 UNICODE_STRING DllString1
, DllString2
;
318 BOOLEAN RedirectedDll
= FALSE
;
321 PUNICODE_STRING OldTldDll
;
322 PTEB Teb
= NtCurrentTeb();
324 /* Initialize the strings */
325 RtlInitEmptyUnicodeString(&DllString1
, StringBuffer
, sizeof(StringBuffer
));
326 RtlInitEmptyUnicodeString(&DllString2
, NULL
, 0);
328 /* Check if the SxS Assemblies specify another file */
329 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
331 &LdrApiDefaultExtension
,
340 if (NT_SUCCESS(Status
))
343 RedirectedDll
= TRUE
;
345 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
347 /* Unrecoverable SxS failure; did we get a string? */
348 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
352 /* Lock the loader lock */
353 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
355 /* Check if there's a TLD DLL being loaded */
356 OldTldDll
= LdrpTopLevelDllBeingLoaded
;
359 /* This is a recursive load, do something about it? */
360 if ((ShowSnaps
) || (LdrpShowRecursiveLoads
) || (LdrpBreakOnRecursiveDllLoads
))
362 /* Print out debug messages */
363 DPRINT1("[%p, %p] LDR: Recursive DLL Load\n",
364 Teb
->RealClientId
.UniqueProcess
,
365 Teb
->RealClientId
.UniqueThread
);
366 DPRINT1("[%p, %p] Previous DLL being loaded \"%wZ\"\n",
367 Teb
->RealClientId
.UniqueProcess
,
368 Teb
->RealClientId
.UniqueThread
,
370 DPRINT1("[%p, %p] DLL being requested \"%wZ\"\n",
371 Teb
->RealClientId
.UniqueProcess
,
372 Teb
->RealClientId
.UniqueThread
,
375 /* Was it initializing too? */
376 if (!LdrpCurrentDllInitializer
)
378 DPRINT1("[%p, %p] LDR: No DLL Initializer was running\n",
379 Teb
->RealClientId
.UniqueProcess
,
380 Teb
->RealClientId
.UniqueThread
);
384 DPRINT1("[%p, %p] DLL whose initializer was currently running \"%wZ\"\n",
385 Teb
->ClientId
.UniqueProcess
,
386 Teb
->ClientId
.UniqueThread
,
387 &LdrpCurrentDllInitializer
->BaseDllName
);
392 /* Set this one as the TLD DLL being loaded*/
393 LdrpTopLevelDllBeingLoaded
= DllName
;
396 Status
= LdrpLoadDll(RedirectedDll
,
402 if (NT_SUCCESS(Status
))
404 Status
= STATUS_SUCCESS
;
406 else if ((Status
!= STATUS_NO_SUCH_FILE
) &&
407 (Status
!= STATUS_DLL_NOT_FOUND
) &&
408 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
) &&
409 (Status
!= STATUS_DLL_INIT_FAILED
))
411 DbgPrintEx(DPFLTR_LDR_ID
,
412 DPFLTR_WARNING_LEVEL
,
413 "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n",
419 /* Restore the old TLD DLL */
420 LdrpTopLevelDllBeingLoaded
= OldTldDll
;
422 /* Release the lock */
423 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
425 /* Do we have a redirect string? */
426 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
437 LdrFindEntryForAddress(PVOID Address
,
438 PLDR_DATA_TABLE_ENTRY
*Module
)
440 PLIST_ENTRY ListHead
, NextEntry
;
441 PLDR_DATA_TABLE_ENTRY LdrEntry
;
442 PIMAGE_NT_HEADERS NtHeader
;
443 PPEB_LDR_DATA Ldr
= NtCurrentPeb()->Ldr
;
444 ULONG_PTR DllBase
, DllEnd
;
446 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
449 if (!Ldr
) return STATUS_NO_MORE_ENTRIES
;
451 /* Get the current entry */
452 LdrEntry
= Ldr
->EntryInProgress
;
455 /* Get the NT Headers */
456 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
459 /* Get the Image Base */
460 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
461 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
463 /* Check if they match */
464 if (((ULONG_PTR
)Address
>= DllBase
) &&
465 ((ULONG_PTR
)Address
< DllEnd
))
469 return STATUS_SUCCESS
;
474 /* Loop the module list */
475 ListHead
= &Ldr
->InMemoryOrderModuleList
;
476 NextEntry
= ListHead
->Flink
;
477 while (NextEntry
!= ListHead
)
479 /* Get the entry and NT Headers */
480 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderModuleList
);
481 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
484 /* Get the Image Base */
485 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
486 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
488 /* Check if they match */
489 if (((ULONG_PTR
)Address
>= DllBase
) &&
490 ((ULONG_PTR
)Address
< DllEnd
))
494 return STATUS_SUCCESS
;
498 NextEntry
= NextEntry
->Flink
;
503 DbgPrintEx(DPFLTR_LDR_ID
,
504 DPFLTR_WARNING_LEVEL
,
505 "LDR: %s() exiting 0x%08lx\n",
507 STATUS_NO_MORE_ENTRIES
);
508 return STATUS_NO_MORE_ENTRIES
;
516 LdrGetDllHandleEx(IN ULONG Flags
,
517 IN PWSTR DllPath OPTIONAL
,
518 IN PULONG DllCharacteristics OPTIONAL
,
519 IN PUNICODE_STRING DllName
,
520 OUT PVOID
*DllHandle OPTIONAL
)
523 PLDR_DATA_TABLE_ENTRY LdrEntry
;
524 UNICODE_STRING RedirectName
, DllString1
, RawDllName
;
525 PUNICODE_STRING pRedirectName
, CompareName
;
527 BOOLEAN Locked
, RedirectedDll
;
529 ULONG LoadFlag
, Length
;
531 /* Initialize the strings */
532 RtlInitEmptyUnicodeString(&DllString1
, NULL
, 0);
533 RtlInitEmptyUnicodeString(&RawDllName
, NULL
, 0);
534 RedirectName
= *DllName
;
535 pRedirectName
= &RedirectName
;
537 /* Initialize state */
538 RedirectedDll
= Locked
= FALSE
;
542 /* Clear the handle */
543 if (DllHandle
) *DllHandle
= NULL
;
545 /* Check for a valid flag combination */
546 if ((Flags
& ~(LDR_GET_DLL_HANDLE_EX_PIN
| LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
)) ||
547 (!DllHandle
&& !(Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)))
549 DPRINT1("Flags are invalid or no DllHandle given\n");
550 Status
= STATUS_INVALID_PARAMETER
;
554 /* If not initializing */
557 /* Acquire the lock */
558 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
559 if (!NT_SUCCESS(Status
)) goto Quickie
;
561 /* Remember we own it */
565 /* Check if the SxS Assemblies specify another file */
566 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
568 &LdrApiDefaultExtension
,
577 if (NT_SUCCESS(Status
))
580 RedirectedDll
= TRUE
;
582 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
584 /* Unrecoverable SxS failure; */
589 ASSERT(pRedirectName
== &RedirectName
);
592 /* Set default failure code */
593 Status
= STATUS_DLL_NOT_FOUND
;
595 /* Use the cache if we can */
596 if (LdrpGetModuleHandleCache
)
598 /* Check if we were redirected */
602 if (!(LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
))
607 /* Use the right name */
608 CompareName
= &LdrpGetModuleHandleCache
->FullDllName
;
613 if (LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
)
618 /* Use the right name */
619 CompareName
= &LdrpGetModuleHandleCache
->BaseDllName
;
622 /* Check if the name matches */
623 if (RtlEqualUnicodeString(pRedirectName
,
628 LdrEntry
= LdrpGetModuleHandleCache
;
631 Status
= STATUS_SUCCESS
;
637 /* Find the name without the extension */
638 p1
= pRedirectName
->Buffer
;
640 p3
= &p1
[pRedirectName
->Length
/ sizeof(WCHAR
)];
647 else if (*p1
== L
'\\')
653 /* Check if no extension was found or if we got a slash */
654 if (!(p2
) || (*p2
== L
'\\') || (*p2
== L
'/'))
656 /* Check that we have space to add one */
657 Length
= pRedirectName
->Length
+
658 LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
);
659 if (Length
>= UNICODE_STRING_MAX_BYTES
)
661 /* No space to add the extension */
662 Status
= STATUS_NAME_TOO_LONG
;
666 /* Setup the string */
667 RawDllName
.MaximumLength
= Length
;
668 ASSERT(Length
>= sizeof(UNICODE_NULL
));
669 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
671 RawDllName
.MaximumLength
);
672 if (!RawDllName
.Buffer
)
674 Status
= STATUS_NO_MEMORY
;
678 /* Copy the string and add extension */
679 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
680 RtlAppendUnicodeStringToString(&RawDllName
, &LdrApiDefaultExtension
);
684 /* Check if there's something in the name */
685 Length
= pRedirectName
->Length
;
688 /* Check and remove trailing period */
689 if (pRedirectName
->Buffer
[Length
/ sizeof(WCHAR
) - sizeof(ANSI_NULL
)] == '.')
691 /* Decrease the size */
692 pRedirectName
->Length
-= sizeof(WCHAR
);
696 /* Setup the string */
697 RawDllName
.MaximumLength
= pRedirectName
->Length
+ sizeof(WCHAR
);
698 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
700 RawDllName
.MaximumLength
);
701 if (!RawDllName
.Buffer
)
703 Status
= STATUS_NO_MEMORY
;
707 /* Copy the string */
708 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
711 /* Display debug string */
714 DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n",
716 DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"");
720 if (LdrpCheckForLoadedDll(DllPath
,
722 ((ULONG_PTR
)DllPath
== 1) ? TRUE
: FALSE
,
726 /* Update cached entry */
727 LdrpGetModuleHandleCache
= LdrEntry
;
730 Status
= STATUS_SUCCESS
;
734 /* Make sure to NULL this */
738 /* The success path must have a valid loader entry */
739 ASSERT((LdrEntry
!= NULL
) == NT_SUCCESS(Status
));
741 /* Check if we got an entry and success */
742 DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry
? &LdrEntry
->BaseDllName
: NULL
);
743 if ((LdrEntry
) && (NT_SUCCESS(Status
)))
745 /* Check if the DLL is locked */
746 if ((LdrEntry
->LoadCount
!= 0xFFFF) &&
747 !(Flags
& LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
))
749 /* Check what to do with the load count */
750 if (Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)
753 LdrEntry
->LoadCount
= 0xFFFF;
754 LoadFlag
= LDRP_UPDATE_PIN
;
758 /* Increase the load count */
759 LdrEntry
->LoadCount
++;
760 LoadFlag
= LDRP_UPDATE_REFCOUNT
;
763 /* Update the load count now */
764 LdrpUpdateLoadCount2(LdrEntry
, LoadFlag
);
765 LdrpClearLoadInProgress();
768 /* Check if the caller is requesting the handle */
769 if (DllHandle
) *DllHandle
= LdrEntry
->DllBase
;
772 /* Free string if needed */
773 if (DllString1
.Buffer
) RtlFreeUnicodeString(&DllString1
);
775 /* Free the raw DLL Name if needed */
776 if (RawDllName
.Buffer
)
778 /* Free the heap-allocated buffer */
779 RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName
.Buffer
);
780 RawDllName
.Buffer
= NULL
;
786 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
,
799 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL
,
800 IN PULONG DllCharacteristics OPTIONAL
,
801 IN PUNICODE_STRING DllName
,
802 OUT PVOID
*DllHandle
)
804 /* Call the newer API */
805 return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
,
817 LdrGetProcedureAddress(IN PVOID BaseAddress
,
818 IN PANSI_STRING Name
,
820 OUT PVOID
*ProcedureAddress
)
822 /* Call the internal routine and tell it to execute DllInit */
823 return LdrpGetProcedureAddress(BaseAddress
, Name
, Ordinal
, ProcedureAddress
, TRUE
);
831 LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle
,
832 IN PLDR_CALLBACK Callback
,
833 IN PVOID CallbackContext
,
834 OUT PUSHORT ImageCharacteristics
)
836 FILE_STANDARD_INFORMATION FileStandardInfo
;
837 PIMAGE_IMPORT_DESCRIPTOR ImportData
;
838 PIMAGE_SECTION_HEADER LastSection
= NULL
;
839 IO_STATUS_BLOCK IoStatusBlock
;
840 PIMAGE_NT_HEADERS NtHeader
;
841 HANDLE SectionHandle
;
844 BOOLEAN Result
, NoActualCheck
;
848 DPRINT("LdrVerifyImageMatchesChecksum() called\n");
850 /* If the handle has the magic KnownDll flag, skip actual checksums */
851 NoActualCheck
= ((ULONG_PTR
)FileHandle
& 1);
853 /* Create the section */
854 Status
= NtCreateSection(&SectionHandle
,
861 if (!NT_SUCCESS(Status
))
863 DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status
);
867 /* Map the section */
870 Status
= NtMapViewOfSection(SectionHandle
,
880 if (!NT_SUCCESS(Status
))
882 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
883 NtClose(SectionHandle
);
887 /* Get the file information */
888 Status
= NtQueryInformationFile(FileHandle
,
891 sizeof(FILE_STANDARD_INFORMATION
),
892 FileStandardInformation
);
893 if (!NT_SUCCESS(Status
))
895 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
896 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
897 NtClose(SectionHandle
);
901 /* Protect with SEH */
904 /* Check if this is the KnownDll hack */
907 /* Don't actually do it */
912 /* Verify the checksum */
913 Result
= LdrVerifyMappedImageMatchesChecksum(ViewBase
,
914 FileStandardInfo
.EndOfFile
.LowPart
,
915 FileStandardInfo
.EndOfFile
.LowPart
);
918 /* Check if a callback was supplied */
919 if ((Result
) && (Callback
))
921 /* Get the NT Header */
922 NtHeader
= RtlImageNtHeader(ViewBase
);
924 /* Check if caller requested this back */
925 if (ImageCharacteristics
)
927 /* Return to caller */
928 *ImageCharacteristics
= NtHeader
->FileHeader
.Characteristics
;
931 /* Get the Import Directory Data */
932 ImportData
= RtlImageDirectoryEntryToData(ViewBase
,
934 IMAGE_DIRECTORY_ENTRY_IMPORT
,
937 /* Make sure there is one */
940 /* Loop the imports */
941 while (ImportData
->Name
)
944 ImportName
= RtlImageRvaToVa(NtHeader
,
949 /* Notify the callback */
950 Callback(CallbackContext
, ImportName
);
956 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
958 /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */
963 /* Unmap file and close handle */
964 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
965 NtClose(SectionHandle
);
968 return Result
? Status
: STATUS_IMAGE_CHECKSUM_MISMATCH
;
973 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId
,
975 OUT PRTL_PROCESS_MODULES ModuleInformation
,
977 OUT PULONG ReturnedSize OPTIONAL
)
979 PLIST_ENTRY ModuleListHead
, InitListHead
;
980 PLIST_ENTRY Entry
, InitEntry
;
981 PLDR_DATA_TABLE_ENTRY Module
, InitModule
;
982 PRTL_PROCESS_MODULE_INFORMATION ModulePtr
= NULL
;
983 NTSTATUS Status
= STATUS_SUCCESS
;
984 ULONG UsedSize
= sizeof(ULONG
);
985 ANSI_STRING AnsiString
;
988 DPRINT("LdrQueryProcessModuleInformation() called\n");
990 /* Acquire loader lock */
991 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
995 /* Check if we were given enough space */
998 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1002 ModuleInformation
->NumberOfModules
= 0;
1003 ModulePtr
= &ModuleInformation
->Modules
[0];
1004 Status
= STATUS_SUCCESS
;
1007 /* Traverse the list of modules */
1008 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1009 Entry
= ModuleListHead
->Flink
;
1011 while (Entry
!= ModuleListHead
)
1013 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1015 DPRINT(" Module %wZ\n", &Module
->FullDllName
);
1017 /* Increase the used size */
1018 UsedSize
+= sizeof(RTL_PROCESS_MODULE_INFORMATION
);
1020 if (UsedSize
> Size
)
1022 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1026 ModulePtr
->ImageBase
= Module
->DllBase
;
1027 ModulePtr
->ImageSize
= Module
->SizeOfImage
;
1028 ModulePtr
->Flags
= Module
->Flags
;
1029 ModulePtr
->LoadCount
= Module
->LoadCount
;
1030 ModulePtr
->MappedBase
= NULL
;
1031 ModulePtr
->InitOrderIndex
= 0;
1032 ModulePtr
->LoadOrderIndex
= ModuleInformation
->NumberOfModules
;
1034 /* Now get init order index by traversing init list */
1035 InitListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1036 InitEntry
= InitListHead
->Flink
;
1038 while (InitEntry
!= InitListHead
)
1040 InitModule
= CONTAINING_RECORD(InitEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
1042 /* Increase the index */
1043 ModulePtr
->InitOrderIndex
++;
1045 /* Quit the loop if our module is found */
1046 if (InitModule
== Module
) break;
1048 /* Advance to the next entry */
1049 InitEntry
= InitEntry
->Flink
;
1052 /* Prepare ANSI string with the module's name */
1053 AnsiString
.Length
= 0;
1054 AnsiString
.MaximumLength
= sizeof(ModulePtr
->FullPathName
);
1055 AnsiString
.Buffer
= ModulePtr
->FullPathName
;
1056 RtlUnicodeStringToAnsiString(&AnsiString
,
1057 &Module
->FullDllName
,
1060 /* Calculate OffsetToFileName field */
1061 p
= strrchr(ModulePtr
->FullPathName
, '\\');
1063 ModulePtr
->OffsetToFileName
= p
- ModulePtr
->FullPathName
+ 1;
1065 ModulePtr
->OffsetToFileName
= 0;
1067 /* Advance to the next module in the output list */
1070 /* Increase number of modules */
1071 if (ModuleInformation
)
1072 ModuleInformation
->NumberOfModules
++;
1075 /* Go to the next entry in the modules list */
1076 Entry
= Entry
->Flink
;
1079 /* Set returned size if it was provided */
1081 *ReturnedSize
= UsedSize
;
1083 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1085 /* Ignoring the exception */
1088 /* Release the lock */
1089 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1091 DPRINT("LdrQueryProcessModuleInformation() done\n");
1101 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation
,
1103 OUT PULONG ReturnedSize OPTIONAL
)
1105 /* Call Ex version of the API */
1106 return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation
, Size
, ReturnedSize
);
1114 LdrEnumerateLoadedModules(IN BOOLEAN ReservedFlag
,
1115 IN PLDR_ENUM_CALLBACK EnumProc
,
1118 PLIST_ENTRY ListHead
, ListEntry
;
1119 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1122 BOOLEAN Stop
= FALSE
;
1124 /* Check parameters */
1125 if ((ReservedFlag
) || !(EnumProc
)) return STATUS_INVALID_PARAMETER
;
1127 /* Acquire the loader lock */
1128 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1129 if (!NT_SUCCESS(Status
)) return Status
;
1131 /* Loop all the modules and call enum proc */
1132 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1133 ListEntry
= ListHead
->Flink
;
1134 while (ListHead
!= ListEntry
)
1137 LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1139 /* Call the enumeration proc inside SEH */
1142 EnumProc(LdrEntry
, Context
, &Stop
);
1144 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1146 /* Ignoring the exception */
1149 /* Break if we were asked to stop enumeration */
1152 /* Release loader lock */
1153 Status
= LdrUnlockLoaderLock(0, Cookie
);
1155 /* Reset any successful status to STATUS_SUCCESS, but leave
1156 failure to the caller */
1157 if (NT_SUCCESS(Status
))
1158 Status
= STATUS_SUCCESS
;
1160 /* Return any possible failure status */
1164 /* Advance to the next module */
1165 ListEntry
= ListEntry
->Flink
;
1168 /* Release loader lock, it must succeed this time */
1169 Status
= LdrUnlockLoaderLock(0, Cookie
);
1170 ASSERT(NT_SUCCESS(Status
));
1172 /* Return success */
1173 return STATUS_SUCCESS
;
1181 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
1183 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1187 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress
);
1189 /* Don't do it during shutdown */
1190 if (LdrpShutdownInProgress
) return STATUS_SUCCESS
;
1192 /* Check if we should grab the lock */
1197 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1198 if (!NT_SUCCESS(Status
)) return Status
;
1202 /* Make sure the DLL is valid and get its entry */
1203 Status
= STATUS_DLL_NOT_FOUND
;
1204 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1206 /* Get if it has a TLS slot */
1207 if (!LdrEntry
->TlsIndex
)
1209 /* It doesn't, so you're allowed to call this */
1210 LdrEntry
->Flags
|= LDRP_DONT_CALL_FOR_THREADS
;
1211 Status
= STATUS_SUCCESS
;
1215 /* Check if the lock was held */
1219 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1222 /* Return the status */
1231 LdrAddRefDll(IN ULONG Flags
,
1232 IN PVOID BaseAddress
)
1234 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1235 NTSTATUS Status
= STATUS_SUCCESS
;
1237 BOOLEAN Locked
= FALSE
;
1239 /* Check for invalid flags */
1240 if (Flags
& ~(LDR_ADDREF_DLL_PIN
))
1242 /* Fail with invalid parameter status if so */
1243 Status
= STATUS_INVALID_PARAMETER
;
1247 /* Acquire the loader lock if not in init phase */
1250 /* Acquire the lock */
1251 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1252 if (!NT_SUCCESS(Status
)) goto quickie
;
1256 /* Get this module's data table entry */
1257 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1261 /* Shouldn't happen */
1262 Status
= STATUS_INTERNAL_ERROR
;
1266 /* If this is not a pinned module */
1267 if (LdrEntry
->LoadCount
!= 0xFFFF)
1269 /* Update its load count */
1270 if (Flags
& LDR_ADDREF_DLL_PIN
)
1272 /* Pin it by setting load count to -1 */
1273 LdrEntry
->LoadCount
= 0xFFFF;
1274 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_PIN
);
1278 /* Increase its load count by one */
1279 LdrEntry
->LoadCount
++;
1280 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
1283 /* Clear load in progress */
1284 LdrpClearLoadInProgress();
1289 /* There was an error getting this module's handle, return invalid param status */
1290 Status
= STATUS_INVALID_PARAMETER
;
1294 /* Check for error case */
1295 if (!NT_SUCCESS(Status
))
1297 /* Print debug information */
1298 if ((ShowSnaps
) || ((Status
!= STATUS_NO_SUCH_FILE
) &&
1299 (Status
!= STATUS_DLL_NOT_FOUND
) &&
1300 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)))
1302 DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress
, Status
);
1306 /* Release the lock if needed */
1307 if (Locked
) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1316 LdrUnloadDll(IN PVOID BaseAddress
)
1318 NTSTATUS Status
= STATUS_SUCCESS
;
1319 PPEB Peb
= NtCurrentPeb();
1320 PLDR_DATA_TABLE_ENTRY LdrEntry
, CurrentEntry
;
1322 PLIST_ENTRY NextEntry
;
1323 LIST_ENTRY UnloadList
;
1324 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
1326 ULONG ComSectionSize
;
1328 /* Get the LDR Lock */
1329 if (!LdrpInLdrInit
) RtlEnterCriticalSection(Peb
->LoaderLock
);
1331 /* Increase the unload count */
1332 LdrpActiveUnloadCount
++;
1335 if (LdrpShutdownInProgress
) goto Quickie
;
1337 /* Make sure the DLL is valid and get its entry */
1338 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1340 Status
= STATUS_DLL_NOT_FOUND
;
1344 /* Check the current Load Count */
1345 if (LdrEntry
->LoadCount
!= 0xFFFF)
1348 LdrEntry
->LoadCount
--;
1351 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1353 /* Set up the Act Ctx */
1354 ActCtx
.Size
= sizeof(ActCtx
);
1355 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1356 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1358 /* Activate the ActCtx */
1359 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1360 LdrEntry
->EntryPointActivationContext
);
1362 /* Update the load count */
1363 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_DEREFCOUNT
);
1365 /* Release the context */
1366 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1371 /* The DLL is locked */
1375 /* Show debug message */
1376 if (ShowSnaps
) DPRINT1("LDR: UNINIT LIST\n");
1378 /* Check if this is our only unload and initialize the list if so */
1379 if (LdrpActiveUnloadCount
== 1) InitializeListHead(&LdrpUnloadHead
);
1381 /* Loop the modules to build the list */
1382 NextEntry
= Peb
->Ldr
->InInitializationOrderModuleList
.Blink
;
1383 while (NextEntry
!= &Peb
->Ldr
->InInitializationOrderModuleList
)
1386 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1387 LDR_DATA_TABLE_ENTRY
,
1388 InInitializationOrderModuleList
);
1389 NextEntry
= NextEntry
->Blink
;
1392 LdrEntry
->Flags
&= ~LDRP_UNLOAD_IN_PROGRESS
;
1394 /* If the load count is now 0 */
1395 if (!LdrEntry
->LoadCount
)
1400 DPRINT1("(%lu) [%ws] %ws (%lx) deinit %p\n",
1401 LdrpActiveUnloadCount
,
1402 LdrEntry
->BaseDllName
.Buffer
,
1403 LdrEntry
->FullDllName
.Buffer
,
1404 (ULONG
)LdrEntry
->LoadCount
,
1405 LdrEntry
->EntryPoint
);
1408 /* FIXME: Call Shim Engine and notify */
1411 CurrentEntry
= LdrEntry
;
1412 RemoveEntryList(&CurrentEntry
->InInitializationOrderModuleList
);
1413 RemoveEntryList(&CurrentEntry
->InMemoryOrderModuleList
);
1414 RemoveEntryList(&CurrentEntry
->HashLinks
);
1416 /* If there's more then one active unload */
1417 if (LdrpActiveUnloadCount
> 1)
1419 /* Flush the cached DLL handle and clear the list */
1420 LdrpLoadedDllHandleCache
= NULL
;
1421 CurrentEntry
->InMemoryOrderModuleList
.Flink
= NULL
;
1424 /* Add the entry on the unload list */
1425 InsertTailList(&LdrpUnloadHead
, &CurrentEntry
->HashLinks
);
1429 /* Only call the entrypoints once */
1430 if (LdrpActiveUnloadCount
> 1) goto Quickie
;
1432 /* Now loop the unload list and create our own */
1433 InitializeListHead(&UnloadList
);
1434 CurrentEntry
= NULL
;
1435 NextEntry
= LdrpUnloadHead
.Flink
;
1436 while (NextEntry
!= &LdrpUnloadHead
)
1438 /* Get the current entry */
1439 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1441 /* FIXME: Log the Unload Event */
1442 //LdrpRecordUnloadEvent(LdrEntry);
1444 /* Set the entry and clear it from the list */
1445 CurrentEntry
= LdrEntry
;
1446 LdrpLoadedDllHandleCache
= NULL
;
1447 CurrentEntry
->InMemoryOrderModuleList
.Flink
= NULL
;
1449 /* Move it from the global to the local list */
1450 RemoveEntryList(&CurrentEntry
->HashLinks
);
1451 InsertTailList(&UnloadList
, &CurrentEntry
->HashLinks
);
1453 /* Get the entrypoint */
1454 EntryPoint
= LdrEntry
->EntryPoint
;
1456 /* Check if we should call it */
1457 if ((EntryPoint
) && (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
))
1462 DPRINT1("LDR: Calling deinit %p\n", EntryPoint
);
1465 /* Set up the Act Ctx */
1466 ActCtx
.Size
= sizeof(ActCtx
);
1467 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1468 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1470 /* Activate the ActCtx */
1471 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1472 LdrEntry
->EntryPointActivationContext
);
1474 /* Call the entrypoint */
1475 LdrpCallInitRoutine(LdrEntry
->EntryPoint
,
1480 /* Release the context */
1481 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1484 /* Remove it from the list */
1485 RemoveEntryList(&CurrentEntry
->InLoadOrderLinks
);
1486 CurrentEntry
= NULL
;
1487 NextEntry
= LdrpUnloadHead
.Flink
;
1490 /* Now loop our local list */
1491 NextEntry
= UnloadList
.Flink
;
1492 while (NextEntry
!= &UnloadList
)
1495 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1496 NextEntry
= NextEntry
->Flink
;
1497 CurrentEntry
= LdrEntry
;
1499 /* Notify Application Verifier */
1500 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
1502 DPRINT1("We don't support Application Verifier yet\n");
1508 DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry
->BaseDllName
.Buffer
);
1511 /* Check if this is a .NET executable */
1512 CorImageData
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1514 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
1519 DPRINT1(".NET Images are not supported yet\n");
1522 /* Check if we should unmap*/
1523 if (!(CurrentEntry
->Flags
& LDR_COR_OWNS_UNMAP
))
1526 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
1527 CurrentEntry
->DllBase
);
1528 ASSERT(NT_SUCCESS(Status
));
1531 /* Unload the alternate resource module, if any */
1532 LdrUnloadAlternateResourceModule(CurrentEntry
->DllBase
);
1534 /* FIXME: Send shutdown notification */
1535 //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
1537 /* Check if a Hotpatch is active */
1538 if (LdrEntry
->PatchInformation
)
1541 DPRINT1("We don't support Hotpatching yet\n");
1544 /* Deallocate the Entry */
1545 LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry
);
1547 /* If this is the cached entry, invalidate it */
1548 if (LdrpGetModuleHandleCache
== CurrentEntry
)
1550 LdrpGetModuleHandleCache
= NULL
;
1555 /* Decrease unload count */
1556 LdrpActiveUnloadCount
--;
1557 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
1559 /* Return to caller */
1568 RtlDllShutdownInProgress(VOID
)
1570 /* Return the internal global */
1571 return LdrpShutdownInProgress
;
1577 PIMAGE_BASE_RELOCATION
1579 LdrProcessRelocationBlock(IN ULONG_PTR Address
,
1581 IN PUSHORT TypeOffset
,
1584 return LdrProcessRelocationBlockLongLong(Address
, Count
, TypeOffset
, Delta
);
1587 /* FIXME: Add to ntstatus.mc */
1588 #define STATUS_MUI_FILE_NOT_FOUND ((NTSTATUS)0xC00B0001L)
1595 LdrLoadAlternateResourceModule(IN PVOID Module
,
1598 /* Is MUI Support enabled? */
1599 if (!LdrAlternateResourcesEnabled()) return STATUS_SUCCESS
;
1602 return STATUS_MUI_FILE_NOT_FOUND
;
1610 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress
)
1614 /* Acquire the loader lock */
1615 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
1617 /* Check if there's any alternate resources loaded */
1618 if (AlternateResourceModuleCount
)
1623 /* Release the loader lock */
1624 LdrUnlockLoaderLock(1, Cookie
);
1635 LdrFlushAlternateResourceModules(VOID
)