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