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