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