[LDR] Guard some sections where we grab a lock.
[reactos.git] / dll / ntdll / ldr / ldrapi.c
1 /*
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)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 LIST_ENTRY LdrpUnloadHead;
20 LONG LdrpLoaderLockAcquisitionCount;
21 BOOLEAN LdrpShowRecursiveLoads, LdrpBreakOnRecursiveDllLoads;
22 UNICODE_STRING LdrApiDefaultExtension = RTL_CONSTANT_STRING(L".DLL");
23 ULONG AlternateResourceModuleCount;
24 extern PLDR_MANIFEST_PROBER_ROUTINE LdrpManifestProberRoutine;
25
26 /* FUNCTIONS *****************************************************************/
27
28 NTSTATUS
29 NTAPI
30 LdrFindCreateProcessManifest(IN ULONG Flags,
31 IN PVOID Image,
32 IN PVOID IdPath,
33 IN ULONG IdPathLength,
34 IN PVOID OutDataEntry)
35 {
36 UNIMPLEMENTED;
37 return STATUS_NOT_IMPLEMENTED;
38 }
39
40 NTSTATUS
41 NTAPI
42 LdrDestroyOutOfProcessImage(IN PVOID Image)
43 {
44 UNIMPLEMENTED;
45 return STATUS_NOT_IMPLEMENTED;
46 }
47
48 NTSTATUS
49 NTAPI
50 LdrCreateOutOfProcessImage(IN ULONG Flags,
51 IN HANDLE ProcessHandle,
52 IN HANDLE DllHandle,
53 IN PVOID Unknown3)
54 {
55 UNIMPLEMENTED;
56 return STATUS_NOT_IMPLEMENTED;
57 }
58
59 NTSTATUS
60 NTAPI
61 LdrAccessOutOfProcessResource(IN PVOID Unknown,
62 IN PVOID Image,
63 IN PVOID Unknown1,
64 IN PVOID Unknown2,
65 IN PVOID Unknown3)
66 {
67 UNIMPLEMENTED;
68 return STATUS_NOT_IMPLEMENTED;
69 }
70
71 VOID
72 NTAPI
73 LdrSetDllManifestProber(
74 _In_ PLDR_MANIFEST_PROBER_ROUTINE Routine)
75 {
76 LdrpManifestProberRoutine = Routine;
77 }
78
79 BOOLEAN
80 NTAPI
81 LdrAlternateResourcesEnabled(VOID)
82 {
83 /* ReactOS does not support this */
84 return FALSE;
85 }
86
87 FORCEINLINE
88 ULONG_PTR
89 LdrpMakeCookie(VOID)
90 {
91 /* Generate a cookie */
92 return (((ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) |
93 (_InterlockedIncrement(&LdrpLoaderLockAcquisitionCount) & 0xFFFF);
94 }
95
96 /*
97 * @implemented
98 */
99 NTSTATUS
100 NTAPI
101 LdrUnlockLoaderLock(IN ULONG Flags,
102 IN ULONG Cookie OPTIONAL)
103 {
104 NTSTATUS Status = STATUS_SUCCESS;
105
106 DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags, Cookie);
107
108 /* Check for valid flags */
109 if (Flags & ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
110 {
111 /* Flags are invalid, check how to fail */
112 if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
113 {
114 /* The caller wants us to raise status */
115 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
116 }
117
118 /* A normal failure */
119 return STATUS_INVALID_PARAMETER_1;
120 }
121
122 /* If we don't have a cookie, just return */
123 if (!Cookie) return STATUS_SUCCESS;
124
125 /* Validate the cookie */
126 if ((Cookie & 0xF0000000) ||
127 ((Cookie >> 16) ^ (HandleToUlong(NtCurrentTeb()->RealClientId.UniqueThread) & 0xFFF)))
128 {
129 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
130
131 /* Invalid cookie, check how to fail */
132 if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
133 {
134 /* The caller wants us to raise status */
135 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
136 }
137
138 /* A normal failure */
139 return STATUS_INVALID_PARAMETER_2;
140 }
141
142 /* Ready to release the lock */
143 if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
144 {
145 /* Do a direct leave */
146 RtlLeaveCriticalSection(&LdrpLoaderLock);
147 }
148 else
149 {
150 /* Wrap this in SEH, since we're not supposed to raise */
151 _SEH2_TRY
152 {
153 /* Leave the lock */
154 RtlLeaveCriticalSection(&LdrpLoaderLock);
155 }
156 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
157 {
158 /* We should use the LDR Filter instead */
159 Status = _SEH2_GetExceptionCode();
160 }
161 _SEH2_END;
162 }
163
164 /* All done */
165 return Status;
166 }
167
168 /*
169 * @implemented
170 */
171 NTSTATUS
172 NTAPI
173 LdrLockLoaderLock(IN ULONG Flags,
174 OUT PULONG Disposition OPTIONAL,
175 OUT PULONG_PTR Cookie OPTIONAL)
176 {
177 NTSTATUS Status = STATUS_SUCCESS;
178 BOOLEAN InInit = LdrpInLdrInit;
179
180 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Disposition, Cookie);
181
182 /* Zero out the outputs */
183 if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID;
184 if (Cookie) *Cookie = 0;
185
186 /* Validate the flags */
187 if (Flags & ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS |
188 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY))
189 {
190 /* Flags are invalid, check how to fail */
191 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
192 {
193 /* The caller wants us to raise status */
194 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
195 }
196
197 /* A normal failure */
198 return STATUS_INVALID_PARAMETER_1;
199 }
200
201 /* Make sure we got a cookie */
202 if (!Cookie)
203 {
204 /* No cookie check how to fail */
205 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
206 {
207 /* The caller wants us to raise status */
208 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3);
209 }
210
211 /* A normal failure */
212 return STATUS_INVALID_PARAMETER_3;
213 }
214
215 /* If the flag is set, make sure we have a valid pointer to use */
216 if ((Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) && !(Disposition))
217 {
218 /* No pointer to return the data to */
219 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
220 {
221 /* The caller wants us to raise status */
222 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
223 }
224
225 /* Fail */
226 return STATUS_INVALID_PARAMETER_2;
227 }
228
229 /* Return now if we are in the init phase */
230 if (InInit) return STATUS_SUCCESS;
231
232 /* Check what locking semantic to use */
233 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
234 {
235 /* Check if we should enter or simply try */
236 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)
237 {
238 /* Do a try */
239 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
240 {
241 /* It's locked */
242 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
243 }
244 else
245 {
246 /* It worked */
247 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
248 *Cookie = LdrpMakeCookie();
249 }
250 }
251 else
252 {
253 /* Do a enter */
254 RtlEnterCriticalSection(&LdrpLoaderLock);
255
256 /* See if result was requested */
257 if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
258 *Cookie = LdrpMakeCookie();
259 }
260 }
261 else
262 {
263 /* Wrap this in SEH, since we're not supposed to raise */
264 _SEH2_TRY
265 {
266 /* Check if we should enter or simply try */
267 if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)
268 {
269 /* Do a try */
270 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
271 {
272 /* It's locked */
273 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
274 }
275 else
276 {
277 /* It worked */
278 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
279 *Cookie = LdrpMakeCookie();
280 }
281 }
282 else
283 {
284 /* Do an enter */
285 RtlEnterCriticalSection(&LdrpLoaderLock);
286
287 /* See if result was requested */
288 if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
289 *Cookie = LdrpMakeCookie();
290 }
291 }
292 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
293 {
294 /* We should use the LDR Filter instead */
295 Status = _SEH2_GetExceptionCode();
296 }
297 _SEH2_END;
298 }
299
300 /* Return status */
301 return Status;
302 }
303
304 /*
305 * @implemented
306 */
307 NTSTATUS
308 NTAPI
309 DECLSPEC_HOTPATCH
310 LdrLoadDll(IN PWSTR SearchPath OPTIONAL,
311 IN PULONG DllCharacteristics OPTIONAL,
312 IN PUNICODE_STRING DllName,
313 OUT PVOID *BaseAddress)
314 {
315 WCHAR StringBuffer[MAX_PATH];
316 UNICODE_STRING DllString1, DllString2;
317 BOOLEAN RedirectedDll = FALSE;
318 NTSTATUS Status;
319 ULONG_PTR Cookie;
320 PUNICODE_STRING OldTldDll;
321 PTEB Teb = NtCurrentTeb();
322
323 /* Initialize the strings */
324 RtlInitEmptyUnicodeString(&DllString1, StringBuffer, sizeof(StringBuffer));
325 RtlInitEmptyUnicodeString(&DllString2, NULL, 0);
326
327 /* Check if the SxS Assemblies specify another file */
328 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
329 DllName,
330 &LdrApiDefaultExtension,
331 &DllString1,
332 &DllString2,
333 &DllName,
334 NULL,
335 NULL,
336 NULL);
337
338 /* Check success */
339 if (NT_SUCCESS(Status))
340 {
341 /* Let Ldrp know */
342 RedirectedDll = TRUE;
343 }
344 else if (Status != STATUS_SXS_KEY_NOT_FOUND)
345 {
346 /* Unrecoverable SxS failure; did we get a string? */
347 if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2);
348 return Status;
349 }
350
351 /* Lock the loader lock */
352 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
353
354 /* Check if there's a TLD DLL being loaded */
355 OldTldDll = LdrpTopLevelDllBeingLoaded;
356 _SEH2_TRY
357 {
358
359 if (OldTldDll)
360 {
361 /* This is a recursive load, do something about it? */
362 if ((ShowSnaps) || (LdrpShowRecursiveLoads) || (LdrpBreakOnRecursiveDllLoads))
363 {
364 /* Print out debug messages */
365 DPRINT1("[%p, %p] LDR: Recursive DLL Load\n",
366 Teb->RealClientId.UniqueProcess,
367 Teb->RealClientId.UniqueThread);
368 DPRINT1("[%p, %p] Previous DLL being loaded \"%wZ\"\n",
369 Teb->RealClientId.UniqueProcess,
370 Teb->RealClientId.UniqueThread,
371 OldTldDll);
372 DPRINT1("[%p, %p] DLL being requested \"%wZ\"\n",
373 Teb->RealClientId.UniqueProcess,
374 Teb->RealClientId.UniqueThread,
375 DllName);
376
377 /* Was it initializing too? */
378 if (!LdrpCurrentDllInitializer)
379 {
380 DPRINT1("[%p, %p] LDR: No DLL Initializer was running\n",
381 Teb->RealClientId.UniqueProcess,
382 Teb->RealClientId.UniqueThread);
383 }
384 else
385 {
386 DPRINT1("[%p, %p] DLL whose initializer was currently running \"%wZ\"\n",
387 Teb->ClientId.UniqueProcess,
388 Teb->ClientId.UniqueThread,
389 &LdrpCurrentDllInitializer->BaseDllName);
390 }
391 }
392 }
393
394 /* Set this one as the TLD DLL being loaded*/
395 LdrpTopLevelDllBeingLoaded = DllName;
396
397 /* Load the DLL */
398 Status = LdrpLoadDll(RedirectedDll,
399 SearchPath,
400 DllCharacteristics,
401 DllName,
402 BaseAddress,
403 TRUE);
404 if (NT_SUCCESS(Status))
405 {
406 Status = STATUS_SUCCESS;
407 }
408 else if ((Status != STATUS_NO_SUCH_FILE) &&
409 (Status != STATUS_DLL_NOT_FOUND) &&
410 (Status != STATUS_OBJECT_NAME_NOT_FOUND) &&
411 (Status != STATUS_DLL_INIT_FAILED))
412 {
413 DbgPrintEx(DPFLTR_LDR_ID,
414 DPFLTR_WARNING_LEVEL,
415 "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n",
416 __FUNCTION__,
417 DllName,
418 Status);
419 }
420 }
421 _SEH2_FINALLY
422 {
423 /* Restore the old TLD DLL */
424 LdrpTopLevelDllBeingLoaded = OldTldDll;
425
426 /* Release the lock */
427 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
428 }
429 _SEH2_END;
430
431 /* Do we have a redirect string? */
432 if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2);
433
434 /* Return */
435 return Status;
436 }
437
438 /*
439 * @implemented
440 */
441 NTSTATUS
442 NTAPI
443 LdrFindEntryForAddress(PVOID Address,
444 PLDR_DATA_TABLE_ENTRY *Module)
445 {
446 PLIST_ENTRY ListHead, NextEntry;
447 PLDR_DATA_TABLE_ENTRY LdrEntry;
448 PIMAGE_NT_HEADERS NtHeader;
449 PPEB_LDR_DATA Ldr = NtCurrentPeb()->Ldr;
450 ULONG_PTR DllBase, DllEnd;
451
452 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address);
453
454 /* Nothing to do */
455 if (!Ldr) return STATUS_NO_MORE_ENTRIES;
456
457 /* Get the current entry */
458 LdrEntry = Ldr->EntryInProgress;
459 if (LdrEntry)
460 {
461 /* Get the NT Headers */
462 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
463 if (NtHeader)
464 {
465 /* Get the Image Base */
466 DllBase = (ULONG_PTR)LdrEntry->DllBase;
467 DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage;
468
469 /* Check if they match */
470 if (((ULONG_PTR)Address >= DllBase) &&
471 ((ULONG_PTR)Address < DllEnd))
472 {
473 /* Return it */
474 *Module = LdrEntry;
475 return STATUS_SUCCESS;
476 }
477 }
478 }
479
480 /* Loop the module list */
481 ListHead = &Ldr->InMemoryOrderModuleList;
482 NextEntry = ListHead->Flink;
483 while (NextEntry != ListHead)
484 {
485 /* Get the entry and NT Headers */
486 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
487 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
488 if (NtHeader)
489 {
490 /* Get the Image Base */
491 DllBase = (ULONG_PTR)LdrEntry->DllBase;
492 DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage;
493
494 /* Check if they match */
495 if (((ULONG_PTR)Address >= DllBase) &&
496 ((ULONG_PTR)Address < DllEnd))
497 {
498 /* Return it */
499 *Module = LdrEntry;
500 return STATUS_SUCCESS;
501 }
502
503 /* Next Entry */
504 NextEntry = NextEntry->Flink;
505 }
506 }
507
508 /* Nothing found */
509 DbgPrintEx(DPFLTR_LDR_ID,
510 DPFLTR_WARNING_LEVEL,
511 "LDR: %s() exiting 0x%08lx\n",
512 __FUNCTION__,
513 STATUS_NO_MORE_ENTRIES);
514 return STATUS_NO_MORE_ENTRIES;
515 }
516
517 /*
518 * @implemented
519 */
520 NTSTATUS
521 NTAPI
522 LdrGetDllHandleEx(IN ULONG Flags,
523 IN PWSTR DllPath OPTIONAL,
524 IN PULONG DllCharacteristics OPTIONAL,
525 IN PUNICODE_STRING DllName,
526 OUT PVOID *DllHandle OPTIONAL)
527 {
528 NTSTATUS Status;
529 PLDR_DATA_TABLE_ENTRY LdrEntry;
530 UNICODE_STRING RedirectName, DllString1, RawDllName;
531 PUNICODE_STRING pRedirectName, CompareName;
532 PWCHAR p1, p2, p3;
533 BOOLEAN Locked, RedirectedDll;
534 ULONG_PTR Cookie;
535 ULONG LoadFlag, Length;
536
537 /* Initialize the strings */
538 RtlInitEmptyUnicodeString(&DllString1, NULL, 0);
539 RtlInitEmptyUnicodeString(&RawDllName, NULL, 0);
540 RedirectName = *DllName;
541 pRedirectName = &RedirectName;
542
543 /* Initialize state */
544 RedirectedDll = Locked = FALSE;
545 LdrEntry = NULL;
546 Cookie = 0;
547
548 /* Clear the handle */
549 if (DllHandle) *DllHandle = NULL;
550
551 /* Check for a valid flag combination */
552 if ((Flags & ~(LDR_GET_DLL_HANDLE_EX_PIN | LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT)) ||
553 (!DllHandle && !(Flags & LDR_GET_DLL_HANDLE_EX_PIN)))
554 {
555 DPRINT1("Flags are invalid or no DllHandle given\n");
556 Status = STATUS_INVALID_PARAMETER;
557 goto Quickie;
558 }
559
560 /* If not initializing */
561 if (!LdrpInLdrInit)
562 {
563 /* Acquire the lock */
564 Status = LdrLockLoaderLock(0, NULL, &Cookie);
565 if (!NT_SUCCESS(Status)) goto Quickie;
566
567 /* Remember we own it */
568 Locked = TRUE;
569 }
570
571 /* Check if the SxS Assemblies specify another file */
572 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
573 pRedirectName,
574 &LdrApiDefaultExtension,
575 NULL,
576 &DllString1,
577 &pRedirectName,
578 NULL,
579 NULL,
580 NULL);
581
582 /* Check success */
583 if (NT_SUCCESS(Status))
584 {
585 /* Let Ldrp know */
586 RedirectedDll = TRUE;
587 }
588 else if (Status != STATUS_SXS_KEY_NOT_FOUND)
589 {
590 /* Unrecoverable SxS failure */
591 goto Quickie;
592 }
593 else
594 {
595 ASSERT(pRedirectName == &RedirectName);
596 }
597
598 /* Set default failure code */
599 Status = STATUS_DLL_NOT_FOUND;
600
601 /* Use the cache if we can */
602 if (LdrpGetModuleHandleCache)
603 {
604 /* Check if we were redirected */
605 if (RedirectedDll)
606 {
607 /* Check the flag */
608 if (!(LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED))
609 {
610 goto DontCompare;
611 }
612
613 /* Use the right name */
614 CompareName = &LdrpGetModuleHandleCache->FullDllName;
615 }
616 else
617 {
618 /* Check the flag */
619 if (LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED)
620 {
621 goto DontCompare;
622 }
623
624 /* Use the right name */
625 CompareName = &LdrpGetModuleHandleCache->BaseDllName;
626 }
627
628 /* Check if the name matches */
629 if (RtlEqualUnicodeString(pRedirectName,
630 CompareName,
631 TRUE))
632 {
633 /* Skip the rest */
634 LdrEntry = LdrpGetModuleHandleCache;
635
636 /* Return success */
637 Status = STATUS_SUCCESS;
638 goto Quickie;
639 }
640 }
641
642 DontCompare:
643 /* Find the name without the extension */
644 p1 = pRedirectName->Buffer;
645 p2 = NULL;
646 p3 = &p1[pRedirectName->Length / sizeof(WCHAR)];
647 while (p1 != p3)
648 {
649 if (*p1++ == L'.')
650 {
651 p2 = p1;
652 }
653 else if (*p1 == L'\\')
654 {
655 p2 = NULL;
656 }
657 }
658
659 /* Check if no extension was found or if we got a slash */
660 if (!(p2) || (*p2 == L'\\') || (*p2 == L'/'))
661 {
662 /* Check that we have space to add one */
663 Length = pRedirectName->Length +
664 LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL);
665 if (Length >= UNICODE_STRING_MAX_BYTES)
666 {
667 /* No space to add the extension */
668 Status = STATUS_NAME_TOO_LONG;
669 goto Quickie;
670 }
671
672 /* Setup the string */
673 RawDllName.MaximumLength = Length;
674 ASSERT(Length >= sizeof(UNICODE_NULL));
675 RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
676 0,
677 RawDllName.MaximumLength);
678 if (!RawDllName.Buffer)
679 {
680 Status = STATUS_NO_MEMORY;
681 goto Quickie;
682 }
683
684 /* Copy the string and add extension */
685 RtlCopyUnicodeString(&RawDllName, pRedirectName);
686 RtlAppendUnicodeStringToString(&RawDllName, &LdrApiDefaultExtension);
687 }
688 else
689 {
690 /* Check if there's something in the name */
691 Length = pRedirectName->Length;
692 if (Length)
693 {
694 /* Check and remove trailing period */
695 if (pRedirectName->Buffer[Length / sizeof(WCHAR) - sizeof(ANSI_NULL)] == '.')
696 {
697 /* Decrease the size */
698 pRedirectName->Length -= sizeof(WCHAR);
699 }
700 }
701
702 /* Setup the string */
703 RawDllName.MaximumLength = pRedirectName->Length + sizeof(WCHAR);
704 RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
705 0,
706 RawDllName.MaximumLength);
707 if (!RawDllName.Buffer)
708 {
709 Status = STATUS_NO_MEMORY;
710 goto Quickie;
711 }
712
713 /* Copy the string */
714 RtlCopyUnicodeString(&RawDllName, pRedirectName);
715 }
716
717 /* Display debug string */
718 if (ShowSnaps)
719 {
720 DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n",
721 &RawDllName,
722 DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"");
723 }
724
725 /* Do the lookup */
726 if (LdrpCheckForLoadedDll(DllPath,
727 &RawDllName,
728 ((ULONG_PTR)DllPath == 1) ? TRUE : FALSE,
729 RedirectedDll,
730 &LdrEntry))
731 {
732 /* Update cached entry */
733 LdrpGetModuleHandleCache = LdrEntry;
734
735 /* Return success */
736 Status = STATUS_SUCCESS;
737 }
738 else
739 {
740 /* Make sure to NULL this */
741 LdrEntry = NULL;
742 }
743 Quickie:
744 /* The success path must have a valid loader entry */
745 ASSERT((LdrEntry != NULL) == NT_SUCCESS(Status));
746
747 /* Check if we got an entry and success */
748 DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry ? &LdrEntry->BaseDllName : NULL);
749 if ((LdrEntry) && (NT_SUCCESS(Status)))
750 {
751 /* Check if the DLL is locked */
752 if ((LdrEntry->LoadCount != 0xFFFF) &&
753 !(Flags & LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT))
754 {
755 /* Check what to do with the load count */
756 if (Flags & LDR_GET_DLL_HANDLE_EX_PIN)
757 {
758 /* Pin it */
759 LdrEntry->LoadCount = 0xFFFF;
760 LoadFlag = LDRP_UPDATE_PIN;
761 }
762 else
763 {
764 /* Increase the load count */
765 LdrEntry->LoadCount++;
766 LoadFlag = LDRP_UPDATE_REFCOUNT;
767 }
768
769 /* Update the load count now */
770 LdrpUpdateLoadCount2(LdrEntry, LoadFlag);
771 LdrpClearLoadInProgress();
772 }
773
774 /* Check if the caller is requesting the handle */
775 if (DllHandle) *DllHandle = LdrEntry->DllBase;
776 }
777
778 /* Free string if needed */
779 if (DllString1.Buffer) RtlFreeUnicodeString(&DllString1);
780
781 /* Free the raw DLL Name if needed */
782 if (RawDllName.Buffer)
783 {
784 /* Free the heap-allocated buffer */
785 RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName.Buffer);
786 RawDllName.Buffer = NULL;
787 }
788
789 /* Release lock */
790 if (Locked)
791 {
792 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS,
793 Cookie);
794 }
795
796 /* Return */
797 return Status;
798 }
799
800 /*
801 * @implemented
802 */
803 NTSTATUS
804 NTAPI
805 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
806 IN PULONG DllCharacteristics OPTIONAL,
807 IN PUNICODE_STRING DllName,
808 OUT PVOID *DllHandle)
809 {
810 /* Call the newer API */
811 return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT,
812 DllPath,
813 DllCharacteristics,
814 DllName,
815 DllHandle);
816 }
817
818 /*
819 * @implemented
820 */
821 NTSTATUS
822 NTAPI
823 LdrGetProcedureAddress(IN PVOID BaseAddress,
824 IN PANSI_STRING Name,
825 IN ULONG Ordinal,
826 OUT PVOID *ProcedureAddress)
827 {
828 /* Call the internal routine and tell it to execute DllInit */
829 return LdrpGetProcedureAddress(BaseAddress, Name, Ordinal, ProcedureAddress, TRUE);
830 }
831
832 /*
833 * @implemented
834 */
835 NTSTATUS
836 NTAPI
837 LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle,
838 IN PLDR_CALLBACK Callback,
839 IN PVOID CallbackContext,
840 OUT PUSHORT ImageCharacteristics)
841 {
842 FILE_STANDARD_INFORMATION FileStandardInfo;
843 PIMAGE_IMPORT_DESCRIPTOR ImportData;
844 PIMAGE_SECTION_HEADER LastSection = NULL;
845 IO_STATUS_BLOCK IoStatusBlock;
846 PIMAGE_NT_HEADERS NtHeader;
847 HANDLE SectionHandle;
848 SIZE_T ViewSize;
849 PVOID ViewBase;
850 BOOLEAN Result, NoActualCheck;
851 NTSTATUS Status;
852 PVOID ImportName;
853 ULONG Size;
854 DPRINT("LdrVerifyImageMatchesChecksum() called\n");
855
856 /* If the handle has the magic KnownDll flag, skip actual checksums */
857 NoActualCheck = ((ULONG_PTR)FileHandle & 1);
858
859 /* Create the section */
860 Status = NtCreateSection(&SectionHandle,
861 SECTION_MAP_EXECUTE,
862 NULL,
863 NULL,
864 PAGE_EXECUTE,
865 SEC_COMMIT,
866 FileHandle);
867 if (!NT_SUCCESS(Status))
868 {
869 DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status);
870 return Status;
871 }
872
873 /* Map the section */
874 ViewSize = 0;
875 ViewBase = NULL;
876 Status = NtMapViewOfSection(SectionHandle,
877 NtCurrentProcess(),
878 &ViewBase,
879 0,
880 0,
881 NULL,
882 &ViewSize,
883 ViewShare,
884 0,
885 PAGE_EXECUTE);
886 if (!NT_SUCCESS(Status))
887 {
888 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status);
889 NtClose(SectionHandle);
890 return Status;
891 }
892
893 /* Get the file information */
894 Status = NtQueryInformationFile(FileHandle,
895 &IoStatusBlock,
896 &FileStandardInfo,
897 sizeof(FILE_STANDARD_INFORMATION),
898 FileStandardInformation);
899 if (!NT_SUCCESS(Status))
900 {
901 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status);
902 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
903 NtClose(SectionHandle);
904 return Status;
905 }
906
907 /* Protect with SEH */
908 _SEH2_TRY
909 {
910 /* Check if this is the KnownDll hack */
911 if (NoActualCheck)
912 {
913 /* Don't actually do it */
914 Result = TRUE;
915 }
916 else
917 {
918 /* Verify the checksum */
919 Result = LdrVerifyMappedImageMatchesChecksum(ViewBase,
920 FileStandardInfo.EndOfFile.LowPart,
921 FileStandardInfo.EndOfFile.LowPart);
922 }
923
924 /* Check if a callback was supplied */
925 if ((Result) && (Callback))
926 {
927 /* Get the NT Header */
928 NtHeader = RtlImageNtHeader(ViewBase);
929
930 /* Check if caller requested this back */
931 if (ImageCharacteristics)
932 {
933 /* Return to caller */
934 *ImageCharacteristics = NtHeader->FileHeader.Characteristics;
935 }
936
937 /* Get the Import Directory Data */
938 ImportData = RtlImageDirectoryEntryToData(ViewBase,
939 FALSE,
940 IMAGE_DIRECTORY_ENTRY_IMPORT,
941 &Size);
942
943 /* Make sure there is one */
944 if (ImportData)
945 {
946 /* Loop the imports */
947 while (ImportData->Name)
948 {
949 /* Get the name */
950 ImportName = RtlImageRvaToVa(NtHeader,
951 ViewBase,
952 ImportData->Name,
953 &LastSection);
954
955 /* Notify the callback */
956 Callback(CallbackContext, ImportName);
957 ImportData++;
958 }
959 }
960 }
961 }
962 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
963 {
964 /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */
965 Result = FALSE;
966 }
967 _SEH2_END;
968
969 /* Unmap file and close handle */
970 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
971 NtClose(SectionHandle);
972
973 /* Return status */
974 return Result ? Status : STATUS_IMAGE_CHECKSUM_MISMATCH;
975 }
976
977 NTSTATUS
978 NTAPI
979 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId,
980 IN ULONG Reserved,
981 OUT PRTL_PROCESS_MODULES ModuleInformation,
982 IN ULONG Size,
983 OUT PULONG ReturnedSize OPTIONAL)
984 {
985 PLIST_ENTRY ModuleListHead, InitListHead;
986 PLIST_ENTRY Entry, InitEntry;
987 PLDR_DATA_TABLE_ENTRY Module, InitModule;
988 PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL;
989 NTSTATUS Status = STATUS_SUCCESS;
990 ULONG UsedSize = sizeof(ULONG);
991 ANSI_STRING AnsiString;
992 PCHAR p;
993
994 DPRINT("LdrQueryProcessModuleInformation() called\n");
995
996 /* Acquire loader lock */
997 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
998
999 _SEH2_TRY
1000 {
1001 /* Check if we were given enough space */
1002 if (Size < UsedSize)
1003 {
1004 Status = STATUS_INFO_LENGTH_MISMATCH;
1005 }
1006 else
1007 {
1008 ModuleInformation->NumberOfModules = 0;
1009 ModulePtr = &ModuleInformation->Modules[0];
1010 Status = STATUS_SUCCESS;
1011 }
1012
1013 /* Traverse the list of modules */
1014 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1015 Entry = ModuleListHead->Flink;
1016
1017 while (Entry != ModuleListHead)
1018 {
1019 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1020
1021 DPRINT(" Module %wZ\n", &Module->FullDllName);
1022
1023 /* Increase the used size */
1024 UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
1025
1026 if (UsedSize > Size)
1027 {
1028 Status = STATUS_INFO_LENGTH_MISMATCH;
1029 }
1030 else
1031 {
1032 ModulePtr->ImageBase = Module->DllBase;
1033 ModulePtr->ImageSize = Module->SizeOfImage;
1034 ModulePtr->Flags = Module->Flags;
1035 ModulePtr->LoadCount = Module->LoadCount;
1036 ModulePtr->MappedBase = NULL;
1037 ModulePtr->InitOrderIndex = 0;
1038 ModulePtr->LoadOrderIndex = ModuleInformation->NumberOfModules;
1039
1040 /* Now get init order index by traversing init list */
1041 InitListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1042 InitEntry = InitListHead->Flink;
1043
1044 while (InitEntry != InitListHead)
1045 {
1046 InitModule = CONTAINING_RECORD(InitEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
1047
1048 /* Increase the index */
1049 ModulePtr->InitOrderIndex++;
1050
1051 /* Quit the loop if our module is found */
1052 if (InitModule == Module) break;
1053
1054 /* Advance to the next entry */
1055 InitEntry = InitEntry->Flink;
1056 }
1057
1058 /* Prepare ANSI string with the module's name */
1059 AnsiString.Length = 0;
1060 AnsiString.MaximumLength = sizeof(ModulePtr->FullPathName);
1061 AnsiString.Buffer = ModulePtr->FullPathName;
1062 RtlUnicodeStringToAnsiString(&AnsiString,
1063 &Module->FullDllName,
1064 FALSE);
1065
1066 /* Calculate OffsetToFileName field */
1067 p = strrchr(ModulePtr->FullPathName, '\\');
1068 if (p != NULL)
1069 ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1;
1070 else
1071 ModulePtr->OffsetToFileName = 0;
1072
1073 /* Advance to the next module in the output list */
1074 ModulePtr++;
1075
1076 /* Increase number of modules */
1077 if (ModuleInformation)
1078 ModuleInformation->NumberOfModules++;
1079 }
1080
1081 /* Go to the next entry in the modules list */
1082 Entry = Entry->Flink;
1083 }
1084
1085 /* Set returned size if it was provided */
1086 if (ReturnedSize)
1087 *ReturnedSize = UsedSize;
1088 }
1089 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1090 {
1091 /* Ignoring the exception */
1092 } _SEH2_END;
1093
1094 /* Release the lock */
1095 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
1096
1097 DPRINT("LdrQueryProcessModuleInformation() done\n");
1098
1099 return Status;
1100 }
1101
1102 /*
1103 * @implemented
1104 */
1105 NTSTATUS
1106 NTAPI
1107 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation,
1108 IN ULONG Size,
1109 OUT PULONG ReturnedSize OPTIONAL)
1110 {
1111 /* Call Ex version of the API */
1112 return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation, Size, ReturnedSize);
1113 }
1114
1115 /*
1116 * @implemented
1117 */
1118 NTSTATUS
1119 NTAPI
1120 LdrEnumerateLoadedModules(IN BOOLEAN ReservedFlag,
1121 IN PLDR_ENUM_CALLBACK EnumProc,
1122 IN PVOID Context)
1123 {
1124 PLIST_ENTRY ListHead, ListEntry;
1125 PLDR_DATA_TABLE_ENTRY LdrEntry;
1126 NTSTATUS Status;
1127 ULONG_PTR Cookie;
1128 BOOLEAN Stop = FALSE;
1129
1130 /* Check parameters */
1131 if ((ReservedFlag) || !(EnumProc)) return STATUS_INVALID_PARAMETER;
1132
1133 /* Acquire the loader lock */
1134 Status = LdrLockLoaderLock(0, NULL, &Cookie);
1135 if (!NT_SUCCESS(Status)) return Status;
1136
1137 /* Loop all the modules and call enum proc */
1138 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1139 ListEntry = ListHead->Flink;
1140 while (ListHead != ListEntry)
1141 {
1142 /* Get the entry */
1143 LdrEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1144
1145 /* Call the enumeration proc inside SEH */
1146 _SEH2_TRY
1147 {
1148 EnumProc(LdrEntry, Context, &Stop);
1149 }
1150 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1151 {
1152 /* Ignoring the exception */
1153 } _SEH2_END;
1154
1155 /* Break if we were asked to stop enumeration */
1156 if (Stop)
1157 {
1158 /* Release loader lock */
1159 Status = LdrUnlockLoaderLock(0, Cookie);
1160
1161 /* Reset any successful status to STATUS_SUCCESS, but leave
1162 failure to the caller */
1163 if (NT_SUCCESS(Status))
1164 Status = STATUS_SUCCESS;
1165
1166 /* Return any possible failure status */
1167 return Status;
1168 }
1169
1170 /* Advance to the next module */
1171 ListEntry = ListEntry->Flink;
1172 }
1173
1174 /* Release loader lock, it must succeed this time */
1175 Status = LdrUnlockLoaderLock(0, Cookie);
1176 ASSERT(NT_SUCCESS(Status));
1177
1178 /* Return success */
1179 return STATUS_SUCCESS;
1180 }
1181
1182 /*
1183 * @implemented
1184 */
1185 NTSTATUS
1186 NTAPI
1187 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
1188 {
1189 PLDR_DATA_TABLE_ENTRY LdrEntry;
1190 NTSTATUS Status;
1191 BOOLEAN LockHeld;
1192 ULONG_PTR Cookie;
1193 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
1194
1195 /* Don't do it during shutdown */
1196 if (LdrpShutdownInProgress) return STATUS_SUCCESS;
1197
1198 /* Check if we should grab the lock */
1199 LockHeld = FALSE;
1200 if (!LdrpInLdrInit)
1201 {
1202 /* Grab the lock */
1203 Status = LdrLockLoaderLock(0, NULL, &Cookie);
1204 if (!NT_SUCCESS(Status)) return Status;
1205 LockHeld = TRUE;
1206 }
1207
1208 /* Make sure the DLL is valid and get its entry */
1209 Status = STATUS_DLL_NOT_FOUND;
1210 if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
1211 {
1212 /* Get if it has a TLS slot */
1213 if (!LdrEntry->TlsIndex)
1214 {
1215 /* It doesn't, so you're allowed to call this */
1216 LdrEntry->Flags |= LDRP_DONT_CALL_FOR_THREADS;
1217 Status = STATUS_SUCCESS;
1218 }
1219 }
1220
1221 /* Check if the lock was held */
1222 if (LockHeld)
1223 {
1224 /* Release it */
1225 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
1226 }
1227
1228 /* Return the status */
1229 return Status;
1230 }
1231
1232 /*
1233 * @implemented
1234 */
1235 NTSTATUS
1236 NTAPI
1237 LdrAddRefDll(IN ULONG Flags,
1238 IN PVOID BaseAddress)
1239 {
1240 PLDR_DATA_TABLE_ENTRY LdrEntry;
1241 NTSTATUS Status = STATUS_SUCCESS;
1242 ULONG_PTR Cookie;
1243 BOOLEAN Locked = FALSE;
1244
1245 /* Check for invalid flags */
1246 if (Flags & ~(LDR_ADDREF_DLL_PIN))
1247 {
1248 /* Fail with invalid parameter status if so */
1249 Status = STATUS_INVALID_PARAMETER;
1250 goto quickie;
1251 }
1252
1253 /* Acquire the loader lock if not in init phase */
1254 if (!LdrpInLdrInit)
1255 {
1256 /* Acquire the lock */
1257 Status = LdrLockLoaderLock(0, NULL, &Cookie);
1258 if (!NT_SUCCESS(Status)) goto quickie;
1259 Locked = TRUE;
1260 }
1261
1262 /* Get this module's data table entry */
1263 if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
1264 {
1265 if (!LdrEntry)
1266 {
1267 /* Shouldn't happen */
1268 Status = STATUS_INTERNAL_ERROR;
1269 goto quickie;
1270 }
1271
1272 /* If this is not a pinned module */
1273 if (LdrEntry->LoadCount != 0xFFFF)
1274 {
1275 /* Update its load count */
1276 if (Flags & LDR_ADDREF_DLL_PIN)
1277 {
1278 /* Pin it by setting load count to -1 */
1279 LdrEntry->LoadCount = 0xFFFF;
1280 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_PIN);
1281 }
1282 else
1283 {
1284 /* Increase its load count by one */
1285 LdrEntry->LoadCount++;
1286 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT);
1287 }
1288
1289 /* Clear load in progress */
1290 LdrpClearLoadInProgress();
1291 }
1292 }
1293 else
1294 {
1295 /* There was an error getting this module's handle, return invalid param status */
1296 Status = STATUS_INVALID_PARAMETER;
1297 }
1298
1299 quickie:
1300 /* Check for error case */
1301 if (!NT_SUCCESS(Status))
1302 {
1303 /* Print debug information */
1304 if ((ShowSnaps) || ((Status != STATUS_NO_SUCH_FILE) &&
1305 (Status != STATUS_DLL_NOT_FOUND) &&
1306 (Status != STATUS_OBJECT_NAME_NOT_FOUND)))
1307 {
1308 DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress, Status);
1309 }
1310 }
1311
1312 /* Release the lock if needed */
1313 if (Locked) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
1314 return Status;
1315 }
1316
1317 /*
1318 * @implemented
1319 */
1320 NTSTATUS
1321 NTAPI
1322 LdrUnloadDll(IN PVOID BaseAddress)
1323 {
1324 NTSTATUS Status = STATUS_SUCCESS;
1325 PPEB Peb = NtCurrentPeb();
1326 PLDR_DATA_TABLE_ENTRY LdrEntry, CurrentEntry;
1327 PVOID EntryPoint;
1328 PLIST_ENTRY NextEntry;
1329 LIST_ENTRY UnloadList;
1330 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
1331 PVOID CorImageData;
1332 ULONG ComSectionSize;
1333
1334 /* Get the LDR Lock */
1335 if (!LdrpInLdrInit) RtlEnterCriticalSection(Peb->LoaderLock);
1336
1337 /* Increase the unload count */
1338 LdrpActiveUnloadCount++;
1339
1340 /* Skip unload */
1341 if (LdrpShutdownInProgress) goto Quickie;
1342
1343 /* Make sure the DLL is valid and get its entry */
1344 if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
1345 {
1346 Status = STATUS_DLL_NOT_FOUND;
1347 goto Quickie;
1348 }
1349
1350 /* Check the current Load Count */
1351 if (LdrEntry->LoadCount != 0xFFFF)
1352 {
1353 /* Decrease it */
1354 LdrEntry->LoadCount--;
1355
1356 /* If it's a dll */
1357 if (LdrEntry->Flags & LDRP_IMAGE_DLL)
1358 {
1359 /* Set up the Act Ctx */
1360 ActCtx.Size = sizeof(ActCtx);
1361 ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
1362 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1363
1364 /* Activate the ActCtx */
1365 RtlActivateActivationContextUnsafeFast(&ActCtx,
1366 LdrEntry->EntryPointActivationContext);
1367
1368 /* Update the load count */
1369 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_DEREFCOUNT);
1370
1371 /* Release the context */
1372 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1373 }
1374 }
1375 else
1376 {
1377 /* The DLL is locked */
1378 goto Quickie;
1379 }
1380
1381 /* Show debug message */
1382 if (ShowSnaps) DPRINT1("LDR: UNINIT LIST\n");
1383
1384 /* Check if this is our only unload and initialize the list if so */
1385 if (LdrpActiveUnloadCount == 1) InitializeListHead(&LdrpUnloadHead);
1386
1387 /* Loop the modules to build the list */
1388 NextEntry = Peb->Ldr->InInitializationOrderModuleList.Blink;
1389 while (NextEntry != &Peb->Ldr->InInitializationOrderModuleList)
1390 {
1391 /* Get the entry */
1392 LdrEntry = CONTAINING_RECORD(NextEntry,
1393 LDR_DATA_TABLE_ENTRY,
1394 InInitializationOrderLinks);
1395 NextEntry = NextEntry->Blink;
1396
1397 /* Remove flag */
1398 LdrEntry->Flags &= ~LDRP_UNLOAD_IN_PROGRESS;
1399
1400 /* If the load count is now 0 */
1401 if (!LdrEntry->LoadCount)
1402 {
1403 /* Show message */
1404 if (ShowSnaps)
1405 {
1406 DPRINT1("(%lu) [%ws] %ws (%lx) deinit %p\n",
1407 LdrpActiveUnloadCount,
1408 LdrEntry->BaseDllName.Buffer,
1409 LdrEntry->FullDllName.Buffer,
1410 (ULONG)LdrEntry->LoadCount,
1411 LdrEntry->EntryPoint);
1412 }
1413
1414 /* Call Shim Engine and notify */
1415 if (g_ShimsEnabled)
1416 {
1417 VOID (NTAPI* SE_DllUnloaded)(PVOID) = RtlDecodeSystemPointer(g_pfnSE_DllUnloaded);
1418 SE_DllUnloaded(LdrEntry);
1419 }
1420
1421 /* Unlink it */
1422 CurrentEntry = LdrEntry;
1423 RemoveEntryList(&CurrentEntry->InInitializationOrderLinks);
1424 RemoveEntryList(&CurrentEntry->InMemoryOrderLinks);
1425 RemoveEntryList(&CurrentEntry->HashLinks);
1426
1427 /* If there's more then one active unload */
1428 if (LdrpActiveUnloadCount > 1)
1429 {
1430 /* Flush the cached DLL handle and clear the list */
1431 LdrpLoadedDllHandleCache = NULL;
1432 CurrentEntry->InMemoryOrderLinks.Flink = NULL;
1433 }
1434
1435 /* Add the entry on the unload list */
1436 InsertTailList(&LdrpUnloadHead, &CurrentEntry->HashLinks);
1437 }
1438 }
1439
1440 /* Only call the entrypoints once */
1441 if (LdrpActiveUnloadCount > 1) goto Quickie;
1442
1443 /* Now loop the unload list and create our own */
1444 InitializeListHead(&UnloadList);
1445 CurrentEntry = NULL;
1446 NextEntry = LdrpUnloadHead.Flink;
1447 while (NextEntry != &LdrpUnloadHead)
1448 {
1449 /* Get the current entry */
1450 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks);
1451
1452 /* FIXME: Log the Unload Event */
1453 //LdrpRecordUnloadEvent(LdrEntry);
1454
1455 /* Set the entry and clear it from the list */
1456 CurrentEntry = LdrEntry;
1457 LdrpLoadedDllHandleCache = NULL;
1458 CurrentEntry->InMemoryOrderLinks.Flink = NULL;
1459
1460 /* Move it from the global to the local list */
1461 RemoveEntryList(&CurrentEntry->HashLinks);
1462 InsertTailList(&UnloadList, &CurrentEntry->HashLinks);
1463
1464 /* Get the entrypoint */
1465 EntryPoint = LdrEntry->EntryPoint;
1466
1467 /* Check if we should call it */
1468 if ((EntryPoint) && (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED))
1469 {
1470 /* Show message */
1471 if (ShowSnaps)
1472 {
1473 DPRINT1("LDR: Calling deinit %p\n", EntryPoint);
1474 }
1475
1476 /* Set up the Act Ctx */
1477 ActCtx.Size = sizeof(ActCtx);
1478 ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
1479 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1480
1481 /* Activate the ActCtx */
1482 RtlActivateActivationContextUnsafeFast(&ActCtx,
1483 LdrEntry->EntryPointActivationContext);
1484
1485 /* Call the entrypoint */
1486 _SEH2_TRY
1487 {
1488 LdrpCallInitRoutine(LdrEntry->EntryPoint,
1489 LdrEntry->DllBase,
1490 DLL_PROCESS_DETACH,
1491 NULL);
1492 }
1493 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1494 {
1495 DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_PROCESS_DETACH) for %wZ\n",
1496 _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
1497 }
1498 _SEH2_END;
1499
1500 /* Release the context */
1501 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1502 }
1503
1504 /* Remove it from the list */
1505 RemoveEntryList(&CurrentEntry->InLoadOrderLinks);
1506 CurrentEntry = NULL;
1507 NextEntry = LdrpUnloadHead.Flink;
1508 }
1509
1510 /* Now loop our local list */
1511 NextEntry = UnloadList.Flink;
1512 while (NextEntry != &UnloadList)
1513 {
1514 /* Get the entry */
1515 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks);
1516 NextEntry = NextEntry->Flink;
1517 CurrentEntry = LdrEntry;
1518
1519 /* Notify Application Verifier */
1520 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK)
1521 {
1522 AVrfDllUnloadNotification(LdrEntry);
1523 }
1524
1525 /* Show message */
1526 if (ShowSnaps)
1527 {
1528 DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry->BaseDllName.Buffer);
1529 }
1530
1531 /* Check if this is a .NET executable */
1532 CorImageData = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
1533 TRUE,
1534 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
1535 &ComSectionSize);
1536 if (CorImageData)
1537 {
1538 /* FIXME */
1539 DPRINT1(".NET Images are not supported yet\n");
1540 }
1541
1542 /* Check if we should unmap*/
1543 if (!(CurrentEntry->Flags & LDR_COR_OWNS_UNMAP))
1544 {
1545 /* Unmap the DLL */
1546 Status = NtUnmapViewOfSection(NtCurrentProcess(),
1547 CurrentEntry->DllBase);
1548 ASSERT(NT_SUCCESS(Status));
1549 }
1550
1551 /* Unload the alternate resource module, if any */
1552 LdrUnloadAlternateResourceModule(CurrentEntry->DllBase);
1553
1554 /* FIXME: Send shutdown notification */
1555 //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
1556
1557 /* Check if a Hotpatch is active */
1558 if (LdrEntry->PatchInformation)
1559 {
1560 /* FIXME */
1561 DPRINT1("We don't support Hotpatching yet\n");
1562 }
1563
1564 /* Deallocate the Entry */
1565 LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry);
1566
1567 /* If this is the cached entry, invalidate it */
1568 if (LdrpGetModuleHandleCache == CurrentEntry)
1569 {
1570 LdrpGetModuleHandleCache = NULL;
1571 }
1572 }
1573
1574 Quickie:
1575 /* Decrease unload count */
1576 LdrpActiveUnloadCount--;
1577 if (!LdrpInLdrInit) RtlLeaveCriticalSection(Peb->LoaderLock);
1578
1579 /* Return to caller */
1580 return Status;
1581 }
1582
1583 /*
1584 * @implemented
1585 */
1586 BOOLEAN
1587 NTAPI
1588 RtlDllShutdownInProgress(VOID)
1589 {
1590 /* Return the internal global */
1591 return LdrpShutdownInProgress;
1592 }
1593
1594 /*
1595 * @implemented
1596 */
1597 PIMAGE_BASE_RELOCATION
1598 NTAPI
1599 LdrProcessRelocationBlock(IN ULONG_PTR Address,
1600 IN ULONG Count,
1601 IN PUSHORT TypeOffset,
1602 IN LONG_PTR Delta)
1603 {
1604 return LdrProcessRelocationBlockLongLong(Address, Count, TypeOffset, Delta);
1605 }
1606
1607 /* FIXME: Add to ntstatus.mc */
1608 #define STATUS_MUI_FILE_NOT_FOUND ((NTSTATUS)0xC00B0001L)
1609
1610 /*
1611 * @implemented
1612 */
1613 NTSTATUS
1614 NTAPI
1615 LdrLoadAlternateResourceModule(IN PVOID Module,
1616 IN PWSTR Buffer)
1617 {
1618 /* Is MUI Support enabled? */
1619 if (!LdrAlternateResourcesEnabled()) return STATUS_SUCCESS;
1620
1621 UNIMPLEMENTED;
1622 return STATUS_MUI_FILE_NOT_FOUND;
1623 }
1624
1625 /*
1626 * @implemented
1627 */
1628 BOOLEAN
1629 NTAPI
1630 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)
1631 {
1632 ULONG_PTR Cookie;
1633
1634 /* Acquire the loader lock */
1635 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
1636
1637 /* Check if there's any alternate resources loaded */
1638 if (AlternateResourceModuleCount)
1639 {
1640 UNIMPLEMENTED;
1641 }
1642
1643 /* Release the loader lock */
1644 LdrUnlockLoaderLock(1, Cookie);
1645
1646 /* All done */
1647 return TRUE;
1648 }
1649
1650 /*
1651 * @unimplemented
1652 */
1653 BOOLEAN
1654 NTAPI
1655 LdrFlushAlternateResourceModules(VOID)
1656 {
1657 UNIMPLEMENTED;
1658 return FALSE;
1659 }
1660
1661 /* EOF */