xref: /reactos/dll/ntdll/ldr/ldrinit.c (revision df849213)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS NT User-Mode Library
4  * FILE:            dll/ntdll/ldr/ldrinit.c
5  * PURPOSE:         User-Mode Process/Thread Startup
6  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
7  *                  Aleksey Bragin (aleksey@reactos.org)
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include <ntdll.h>
13 #include <compat_undoc.h>
14 #include <compatguid_undoc.h>
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 
20 /* GLOBALS *******************************************************************/
21 
22 HANDLE ImageExecOptionsKey;
23 HANDLE Wow64ExecOptionsKey;
24 UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
25 UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
26 UNICODE_STRING NtDllString = RTL_CONSTANT_STRING(L"ntdll.dll");
27 
28 BOOLEAN LdrpInLdrInit;
29 LONG LdrpProcessInitialized;
30 BOOLEAN LdrpLoaderLockInit;
31 BOOLEAN LdrpLdrDatabaseIsSetup;
32 BOOLEAN LdrpShutdownInProgress;
33 HANDLE LdrpShutdownThreadId;
34 
35 BOOLEAN LdrpDllValidation;
36 
37 PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
38 PUNICODE_STRING LdrpTopLevelDllBeingLoaded;
39 WCHAR StringBuffer[156];
40 extern PTEB LdrpTopLevelDllBeingLoadedTeb; // defined in rtlsupp.c!
41 PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer;
42 PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry;
43 
44 RTL_BITMAP TlsBitMap;
45 RTL_BITMAP TlsExpansionBitMap;
46 RTL_BITMAP FlsBitMap;
47 BOOLEAN LdrpImageHasTls;
48 LIST_ENTRY LdrpTlsList;
49 ULONG LdrpNumberOfTlsEntries;
50 ULONG LdrpNumberOfProcessors;
51 PVOID NtDllBase;
52 extern LARGE_INTEGER RtlpTimeout;
53 BOOLEAN RtlpTimeoutDisable;
54 LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
55 LIST_ENTRY LdrpDllNotificationList;
56 HANDLE LdrpKnownDllObjectDirectory;
57 UNICODE_STRING LdrpKnownDllPath;
58 WCHAR LdrpKnownDllPathBuffer[128];
59 UNICODE_STRING LdrpDefaultPath;
60 
61 PEB_LDR_DATA PebLdr;
62 
63 RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug;
64 RTL_CRITICAL_SECTION LdrpLoaderLock =
65 {
66     &LdrpLoaderLockDebug,
67     -1,
68     0,
69     0,
70     0,
71     0
72 };
73 RTL_CRITICAL_SECTION FastPebLock;
74 
75 BOOLEAN ShowSnaps;
76 
77 ULONG LdrpFatalHardErrorCount;
78 ULONG LdrpActiveUnloadCount;
79 
80 //extern LIST_ENTRY RtlCriticalSectionList;
81 
82 VOID NTAPI RtlpInitializeVectoredExceptionHandling(VOID);
83 VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
84 VOID NTAPI RtlInitializeHeapManager(VOID);
85 
86 ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c
87 ULONG RtlpShutdownProcessFlags; // TODO: Use it
88 
89 NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase);
90 void actctx_init(void);
91 extern BOOLEAN RtlpUse16ByteSLists;
92 
93 #ifdef _WIN64
94 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
95 #else
96 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
97 #endif
98 
99 /* FUNCTIONS *****************************************************************/
100 
101 /*
102  * @implemented
103  */
104 NTSTATUS
105 NTAPI
106 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey,
107                            IN BOOLEAN Wow64,
108                            OUT PHANDLE NewKeyHandle)
109 {
110     PHANDLE RootKeyLocation;
111     HANDLE RootKey;
112     UNICODE_STRING SubKeyString;
113     OBJECT_ATTRIBUTES ObjectAttributes;
114     NTSTATUS Status;
115     PWCHAR p1;
116 
117     /* Check which root key to open */
118     if (Wow64)
119         RootKeyLocation = &Wow64ExecOptionsKey;
120     else
121         RootKeyLocation = &ImageExecOptionsKey;
122 
123     /* Get the current key */
124     RootKey = *RootKeyLocation;
125 
126     /* Setup the object attributes */
127     InitializeObjectAttributes(&ObjectAttributes,
128                                Wow64 ?
129                                &Wow64OptionsString : &ImageExecOptionsString,
130                                OBJ_CASE_INSENSITIVE,
131                                NULL,
132                                NULL);
133 
134     /* Open the root key */
135     Status = ZwOpenKey(&RootKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
136     if (NT_SUCCESS(Status))
137     {
138         /* Write the key handle */
139         if (InterlockedCompareExchangePointer(RootKeyLocation, RootKey, NULL) != NULL)
140         {
141             /* Someone already opened it, use it instead */
142             NtClose(RootKey);
143             RootKey = *RootKeyLocation;
144         }
145 
146         /* Extract the name */
147         SubKeyString = *SubKey;
148         p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length);
149         while (SubKeyString.Length)
150         {
151             if (p1[-1] == L'\\') break;
152             p1--;
153             SubKeyString.Length -= sizeof(*p1);
154         }
155         SubKeyString.Buffer = p1;
156         SubKeyString.Length = SubKey->Length - SubKeyString.Length;
157 
158         /* Setup the object attributes */
159         InitializeObjectAttributes(&ObjectAttributes,
160                                    &SubKeyString,
161                                    OBJ_CASE_INSENSITIVE,
162                                    RootKey,
163                                    NULL);
164 
165         /* Open the setting key */
166         Status = ZwOpenKey((PHANDLE)NewKeyHandle, GENERIC_READ, &ObjectAttributes);
167     }
168 
169     /* Return to caller */
170     return Status;
171 }
172 
173 /*
174  * @implemented
175  */
176 NTSTATUS
177 NTAPI
178 LdrQueryImageFileKeyOption(IN HANDLE KeyHandle,
179                            IN PCWSTR ValueName,
180                            IN ULONG Type,
181                            OUT PVOID Buffer,
182                            IN ULONG BufferSize,
183                            OUT PULONG ReturnedLength OPTIONAL)
184 {
185     ULONG KeyInfo[256];
186     UNICODE_STRING ValueNameString, IntegerString;
187     ULONG KeyInfoSize, ResultSize;
188     PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyInfo;
189     BOOLEAN FreeHeap = FALSE;
190     NTSTATUS Status;
191 
192     /* Build a string for the value name */
193     Status = RtlInitUnicodeStringEx(&ValueNameString, ValueName);
194     if (!NT_SUCCESS(Status)) return Status;
195 
196     /* Query the value */
197     Status = ZwQueryValueKey(KeyHandle,
198                              &ValueNameString,
199                              KeyValuePartialInformation,
200                              KeyValueInformation,
201                              sizeof(KeyInfo),
202                              &ResultSize);
203     if (Status == STATUS_BUFFER_OVERFLOW)
204     {
205         /* Our local buffer wasn't enough, allocate one */
206         KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
207                       KeyValueInformation->DataLength;
208         KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(),
209                                               0,
210                                               KeyInfoSize);
211         if (KeyValueInformation != NULL)
212         {
213             /* Try again */
214             Status = ZwQueryValueKey(KeyHandle,
215                                      &ValueNameString,
216                                      KeyValuePartialInformation,
217                                      KeyValueInformation,
218                                      KeyInfoSize,
219                                      &ResultSize);
220             FreeHeap = TRUE;
221         }
222         else
223         {
224             /* Give up this time */
225             Status = STATUS_NO_MEMORY;
226         }
227     }
228 
229     /* Check for success */
230     if (NT_SUCCESS(Status))
231     {
232         /* Handle binary data */
233         if (KeyValueInformation->Type == REG_BINARY)
234         {
235             /* Check validity */
236             if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize))
237             {
238                 /* Copy into buffer */
239                 RtlMoveMemory(Buffer,
240                               &KeyValueInformation->Data,
241                               KeyValueInformation->DataLength);
242             }
243             else
244             {
245                 Status = STATUS_BUFFER_OVERFLOW;
246             }
247 
248             /* Copy the result length */
249             if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
250         }
251         else if (KeyValueInformation->Type == REG_DWORD)
252         {
253             /* Check for valid type */
254             if (KeyValueInformation->Type != Type)
255             {
256                 /* Error */
257                 Status = STATUS_OBJECT_TYPE_MISMATCH;
258             }
259             else
260             {
261                 /* Check validity */
262                 if ((Buffer) &&
263                     (BufferSize == sizeof(ULONG)) &&
264                     (KeyValueInformation->DataLength <= BufferSize))
265                 {
266                     /* Copy into buffer */
267                     RtlMoveMemory(Buffer,
268                                   &KeyValueInformation->Data,
269                                   KeyValueInformation->DataLength);
270                 }
271                 else
272                 {
273                     Status = STATUS_BUFFER_OVERFLOW;
274                 }
275 
276                 /* Copy the result length */
277                 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
278             }
279         }
280         else if (KeyValueInformation->Type != REG_SZ)
281         {
282             /* We got something weird */
283             Status = STATUS_OBJECT_TYPE_MISMATCH;
284         }
285         else
286         {
287             /*  String, check what you requested */
288             if (Type == REG_DWORD)
289             {
290                 /* Validate */
291                 if (BufferSize != sizeof(ULONG))
292                 {
293                     /* Invalid size */
294                     BufferSize = 0;
295                     Status = STATUS_INFO_LENGTH_MISMATCH;
296                 }
297                 else
298                 {
299                     /* OK, we know what you want... */
300                     IntegerString.Buffer = (PWSTR)KeyValueInformation->Data;
301                     IntegerString.Length = (USHORT)KeyValueInformation->DataLength -
302                                            sizeof(WCHAR);
303                     IntegerString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
304                     Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer);
305                 }
306             }
307             else
308             {
309                 /* Validate */
310                 if (KeyValueInformation->DataLength > BufferSize)
311                 {
312                     /* Invalid */
313                     Status = STATUS_BUFFER_OVERFLOW;
314                 }
315                 else
316                 {
317                     /* Set the size */
318                     BufferSize = KeyValueInformation->DataLength;
319                 }
320 
321                 /* Copy the string */
322                 RtlMoveMemory(Buffer, &KeyValueInformation->Data, BufferSize);
323             }
324 
325             /* Copy the result length */
326             if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
327         }
328     }
329 
330     /* Check if buffer was in heap */
331     if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation);
332 
333     /* Return status */
334     return Status;
335 }
336 
337 /*
338  * @implemented
339  */
340 NTSTATUS
341 NTAPI
342 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey,
343                                     IN PCWSTR ValueName,
344                                     IN ULONG Type,
345                                     OUT PVOID Buffer,
346                                     IN ULONG BufferSize,
347                                     OUT PULONG ReturnedLength OPTIONAL,
348                                     IN BOOLEAN Wow64)
349 {
350     NTSTATUS Status;
351     HANDLE KeyHandle;
352 
353     /* Open a handle to the key */
354     Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle);
355 
356     /* Check for success */
357     if (NT_SUCCESS(Status))
358     {
359         /* Query the data */
360         Status = LdrQueryImageFileKeyOption(KeyHandle,
361                                             ValueName,
362                                             Type,
363                                             Buffer,
364                                             BufferSize,
365                                             ReturnedLength);
366 
367         /* Close the key */
368         NtClose(KeyHandle);
369     }
370 
371     /* Return to caller */
372     return Status;
373 }
374 
375 /*
376  * @implemented
377  */
378 NTSTATUS
379 NTAPI
380 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
381                                   IN PCWSTR ValueName,
382                                   IN ULONG Type,
383                                   OUT PVOID Buffer,
384                                   IN ULONG BufferSize,
385                                   OUT PULONG ReturnedLength OPTIONAL)
386 {
387     /* Call the newer function */
388     return LdrQueryImageFileExecutionOptionsEx(SubKey,
389                                                ValueName,
390                                                Type,
391                                                Buffer,
392                                                BufferSize,
393                                                ReturnedLength,
394                                                FALSE);
395 }
396 
397 VOID
398 NTAPI
399 LdrpEnsureLoaderLockIsHeld(VOID)
400 {
401     // Ignored atm
402 }
403 
404 PVOID
405 NTAPI
406 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
407 {
408     PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
409     ULONG DirSize;
410     PVOID Cookie = NULL;
411 
412     /* Check NT header first */
413     if (!RtlImageNtHeader(BaseAddress)) return NULL;
414 
415     /* Get the pointer to the config directory */
416     ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
417                                              TRUE,
418                                              IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
419                                              &DirSize);
420 
421     /* Check for sanity */
422     if (!ConfigDir ||
423         (DirSize != 64 && ConfigDir->Size != DirSize) ||
424         (ConfigDir->Size < 0x48))
425         return NULL;
426 
427     /* Now get the cookie */
428     Cookie = (PVOID)ConfigDir->SecurityCookie;
429 
430     /* Check this cookie */
431     if ((PCHAR)Cookie <= (PCHAR)BaseAddress ||
432         (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage)
433     {
434         Cookie = NULL;
435     }
436 
437     /* Return validated security cookie */
438     return Cookie;
439 }
440 
441 PVOID
442 NTAPI
443 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
444 {
445     PULONG_PTR Cookie;
446     LARGE_INTEGER Counter;
447     ULONG_PTR NewCookie;
448 
449     /* Fetch address of the cookie */
450     Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage);
451 
452     if (Cookie)
453     {
454         /* Check if it's a default one */
455         if ((*Cookie == DEFAULT_SECURITY_COOKIE) ||
456             (*Cookie == 0xBB40))
457         {
458             /* Make up a cookie from a bunch of values which may uniquely represent
459                current moment of time, environment, etc */
460             NtQueryPerformanceCounter(&Counter, NULL);
461 
462             NewCookie = Counter.LowPart ^ Counter.HighPart;
463             NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueProcess;
464             NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueThread;
465 
466             /* Loop like it's done in KeQueryTickCount(). We don't want to call it directly. */
467             while (SharedUserData->SystemTime.High1Time != SharedUserData->SystemTime.High2Time)
468             {
469                 YieldProcessor();
470             };
471 
472             /* Calculate the milliseconds value and xor it to the cookie */
473             NewCookie ^= Int64ShrlMod32(UInt32x32To64(SharedUserData->TickCountMultiplier, SharedUserData->TickCount.LowPart), 24) +
474                 (SharedUserData->TickCountMultiplier * (SharedUserData->TickCount.High1Time << 8));
475 
476             /* Make the cookie 16bit if necessary */
477             if (*Cookie == 0xBB40) NewCookie &= 0xFFFF;
478 
479             /* If the result is 0 or the same as we got, just subtract one from the existing value
480                and that's it */
481             if ((NewCookie == 0) || (NewCookie == *Cookie))
482             {
483                 NewCookie = *Cookie - 1;
484             }
485 
486             /* Set the new cookie value */
487             *Cookie = NewCookie;
488         }
489     }
490 
491     return Cookie;
492 }
493 
494 VOID
495 NTAPI
496 LdrpInitializeThread(IN PCONTEXT Context)
497 {
498     PPEB Peb = NtCurrentPeb();
499     PLDR_DATA_TABLE_ENTRY LdrEntry;
500     PLIST_ENTRY NextEntry, ListHead;
501     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
502     NTSTATUS Status;
503     PVOID EntryPoint;
504 
505     DPRINT("LdrpInitializeThread() called for %wZ (%p/%p)\n",
506             &LdrpImageEntry->BaseDllName,
507             NtCurrentTeb()->RealClientId.UniqueProcess,
508             NtCurrentTeb()->RealClientId.UniqueThread);
509 
510     /* Allocate an Activation Context Stack */
511     DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer);
512     Status = RtlAllocateActivationContextStack(&NtCurrentTeb()->ActivationContextStackPointer);
513     if (!NT_SUCCESS(Status))
514     {
515         DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
516     }
517 
518     /* Make sure we are not shutting down */
519     if (LdrpShutdownInProgress) return;
520 
521     /* Allocate TLS */
522     LdrpAllocateTls();
523 
524     /* Start at the beginning */
525     ListHead = &Peb->Ldr->InMemoryOrderModuleList;
526     NextEntry = ListHead->Flink;
527     while (NextEntry != ListHead)
528     {
529         /* Get the current entry */
530         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
531 
532         /* Make sure it's not ourselves */
533         if (Peb->ImageBaseAddress != LdrEntry->DllBase)
534         {
535             /* Check if we should call */
536             if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS))
537             {
538                 /* Get the entrypoint */
539                 EntryPoint = LdrEntry->EntryPoint;
540 
541                 /* Check if we are ready to call it */
542                 if ((EntryPoint) &&
543                     (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
544                     (LdrEntry->Flags & LDRP_IMAGE_DLL))
545                 {
546                     /* Set up the Act Ctx */
547                     ActCtx.Size = sizeof(ActCtx);
548                     ActCtx.Format = 1;
549                     RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
550 
551                     /* Activate the ActCtx */
552                     RtlActivateActivationContextUnsafeFast(&ActCtx,
553                                                            LdrEntry->EntryPointActivationContext);
554 
555                     _SEH2_TRY
556                     {
557                         /* Check if it has TLS */
558                         if (LdrEntry->TlsIndex)
559                         {
560                             /* Make sure we're not shutting down */
561                             if (!LdrpShutdownInProgress)
562                             {
563                                 /* Call TLS */
564                                 LdrpCallTlsInitializers(LdrEntry, DLL_THREAD_ATTACH);
565                             }
566                         }
567 
568                         /* Make sure we're not shutting down */
569                         if (!LdrpShutdownInProgress)
570                         {
571                             /* Call the Entrypoint */
572                             DPRINT("%wZ - Calling entry point at %p for thread attaching, %p/%p\n",
573                                    &LdrEntry->BaseDllName, LdrEntry->EntryPoint,
574                                    NtCurrentTeb()->RealClientId.UniqueProcess,
575                                    NtCurrentTeb()->RealClientId.UniqueThread);
576                             LdrpCallInitRoutine(LdrEntry->EntryPoint,
577                                                 LdrEntry->DllBase,
578                                                 DLL_THREAD_ATTACH,
579                                                 NULL);
580                         }
581                     }
582                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
583                     {
584                         DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_THREAD_ATTACH) for %wZ\n",
585                                 _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
586                     }
587                     _SEH2_END;
588 
589                     /* Deactivate the ActCtx */
590                     RtlDeactivateActivationContextUnsafeFast(&ActCtx);
591                 }
592             }
593         }
594 
595         /* Next entry */
596         NextEntry = NextEntry->Flink;
597     }
598 
599     /* Check for TLS */
600     if (LdrpImageHasTls && !LdrpShutdownInProgress)
601     {
602         /* Set up the Act Ctx */
603         ActCtx.Size = sizeof(ActCtx);
604         ActCtx.Format = 1;
605         RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
606 
607         /* Activate the ActCtx */
608         RtlActivateActivationContextUnsafeFast(&ActCtx,
609                                                LdrpImageEntry->EntryPointActivationContext);
610 
611         _SEH2_TRY
612         {
613             /* Do TLS callbacks */
614             LdrpCallTlsInitializers(LdrpImageEntry, DLL_THREAD_ATTACH);
615         }
616         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
617         {
618             /* Do nothing */
619         }
620         _SEH2_END;
621 
622         /* Deactivate the ActCtx */
623         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
624     }
625 
626     DPRINT("LdrpInitializeThread() done\n");
627 }
628 
629 NTSTATUS
630 NTAPI
631 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
632 {
633     PLDR_DATA_TABLE_ENTRY LocalArray[16];
634     PLIST_ENTRY ListHead;
635     PLIST_ENTRY NextEntry;
636     PLDR_DATA_TABLE_ENTRY LdrEntry, *LdrRootEntry, OldInitializer;
637     PVOID EntryPoint;
638     ULONG Count, i;
639     //ULONG BreakOnInit;
640     NTSTATUS Status = STATUS_SUCCESS;
641     PPEB Peb = NtCurrentPeb();
642     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
643     ULONG BreakOnDllLoad;
644     PTEB OldTldTeb;
645     BOOLEAN DllStatus;
646 
647     DPRINT("LdrpRunInitializeRoutines() called for %wZ (%p/%p)\n",
648         &LdrpImageEntry->BaseDllName,
649         NtCurrentTeb()->RealClientId.UniqueProcess,
650         NtCurrentTeb()->RealClientId.UniqueThread);
651 
652     /* Check the Loader Lock */
653     LdrpEnsureLoaderLockIsHeld();
654 
655      /* Get the number of entries to call */
656     if ((Count = LdrpClearLoadInProgress()))
657     {
658         /* Check if we can use our local buffer */
659         if (Count > 16)
660         {
661             /* Allocate space for all the entries */
662             LdrRootEntry = RtlAllocateHeap(RtlGetProcessHeap(),
663                                            0,
664                                            Count * sizeof(*LdrRootEntry));
665             if (!LdrRootEntry) return STATUS_NO_MEMORY;
666         }
667         else
668         {
669             /* Use our local array */
670             LdrRootEntry = LocalArray;
671         }
672     }
673     else
674     {
675         /* Don't need one */
676         LdrRootEntry = NULL;
677     }
678 
679     /* Show debug message */
680     if (ShowSnaps)
681     {
682         DPRINT1("[%p,%p] LDR: Real INIT LIST for Process %wZ\n",
683                 NtCurrentTeb()->RealClientId.UniqueThread,
684                 NtCurrentTeb()->RealClientId.UniqueProcess,
685                 &Peb->ProcessParameters->ImagePathName);
686     }
687 
688     /* Loop in order */
689     ListHead = &Peb->Ldr->InInitializationOrderModuleList;
690     NextEntry = ListHead->Flink;
691     i = 0;
692     while (NextEntry != ListHead)
693     {
694         /* Get the Data Entry */
695         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
696 
697         /* Check if we have a Root Entry */
698         if (LdrRootEntry)
699         {
700             /* Check flags */
701             if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
702             {
703                 /* Setup the Cookie for the DLL */
704                 LdrpInitSecurityCookie(LdrEntry);
705 
706                 /* Check for valid entrypoint */
707                 if (LdrEntry->EntryPoint)
708                 {
709                     /* Write in array */
710                     ASSERT(i < Count);
711                     LdrRootEntry[i] = LdrEntry;
712 
713                     /* Display debug message */
714                     if (ShowSnaps)
715                     {
716                         DPRINT1("[%p,%p] LDR: %wZ init routine %p\n",
717                                 NtCurrentTeb()->RealClientId.UniqueThread,
718                                 NtCurrentTeb()->RealClientId.UniqueProcess,
719                                 &LdrEntry->FullDllName,
720                                 LdrEntry->EntryPoint);
721                     }
722                     i++;
723                 }
724             }
725         }
726 
727         /* Set the flag */
728         LdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
729         NextEntry = NextEntry->Flink;
730     }
731 
732     /* If we got a context, then we have to call Kernel32 for TS support */
733     if (Context)
734     {
735         /* Check if we have one */
736         //if (Kernel32ProcessInitPostImportfunction)
737         //{
738             /* Call it */
739             //Kernel32ProcessInitPostImportfunction();
740         //}
741 
742         /* Clear it */
743         //Kernel32ProcessInitPostImportfunction = NULL;
744         //UNIMPLEMENTED;
745     }
746 
747     /* No root entry? return */
748     if (!LdrRootEntry) return STATUS_SUCCESS;
749 
750     /* Set the TLD TEB */
751     OldTldTeb = LdrpTopLevelDllBeingLoadedTeb;
752     LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
753 
754     /* Loop */
755     i = 0;
756     while (i < Count)
757     {
758         /* Get an entry */
759         LdrEntry = LdrRootEntry[i];
760 
761         /* FIXME: Verify NX Compat */
762 
763         /* Move to next entry */
764         i++;
765 
766         /* Get its entrypoint */
767         EntryPoint = LdrEntry->EntryPoint;
768 
769         /* Are we being debugged? */
770         BreakOnDllLoad = 0;
771         if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions)
772         {
773             /* Check if we should break on load */
774             Status = LdrQueryImageFileExecutionOptions(&LdrEntry->BaseDllName,
775                                                        L"BreakOnDllLoad",
776                                                        REG_DWORD,
777                                                        &BreakOnDllLoad,
778                                                        sizeof(ULONG),
779                                                        NULL);
780             if (!NT_SUCCESS(Status)) BreakOnDllLoad = 0;
781 
782             /* Reset status back to STATUS_SUCCESS */
783             Status = STATUS_SUCCESS;
784         }
785 
786         /* Break if aksed */
787         if (BreakOnDllLoad)
788         {
789             /* Check if we should show a message */
790             if (ShowSnaps)
791             {
792                 DPRINT1("LDR: %wZ loaded.", &LdrEntry->BaseDllName);
793                 DPRINT1(" - About to call init routine at %p\n", EntryPoint);
794             }
795 
796             /* Break in debugger */
797             DbgBreakPoint();
798         }
799 
800         /* Make sure we have an entrypoint */
801         if (EntryPoint)
802         {
803             /* Save the old Dll Initializer and write the current one */
804             OldInitializer = LdrpCurrentDllInitializer;
805             LdrpCurrentDllInitializer = LdrEntry;
806 
807             /* Set up the Act Ctx */
808             ActCtx.Size = sizeof(ActCtx);
809             ActCtx.Format = 1;
810             RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
811 
812             /* Activate the ActCtx */
813             RtlActivateActivationContextUnsafeFast(&ActCtx,
814                                                    LdrEntry->EntryPointActivationContext);
815 
816             _SEH2_TRY
817             {
818                 /* Check if it has TLS */
819                 if (LdrEntry->TlsIndex && Context)
820                 {
821                     /* Call TLS */
822                     LdrpCallTlsInitializers(LdrEntry, DLL_PROCESS_ATTACH);
823                 }
824 
825                 /* Call the Entrypoint */
826                 if (ShowSnaps)
827                 {
828                     DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
829                             &LdrEntry->BaseDllName, EntryPoint);
830                 }
831                 DllStatus = LdrpCallInitRoutine(EntryPoint,
832                                                 LdrEntry->DllBase,
833                                                 DLL_PROCESS_ATTACH,
834                                                 Context);
835             }
836             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
837             {
838                 DllStatus = FALSE;
839                 DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_PROCESS_ATTACH) for %wZ\n",
840                         _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
841             }
842             _SEH2_END;
843 
844             /* Deactivate the ActCtx */
845             RtlDeactivateActivationContextUnsafeFast(&ActCtx);
846 
847             /* Save the Current DLL Initializer */
848             LdrpCurrentDllInitializer = OldInitializer;
849 
850             /* Mark the entry as processed */
851             LdrEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED;
852 
853             /* Fail if DLL init failed */
854             if (!DllStatus)
855             {
856                 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
857                     &LdrEntry->BaseDllName, EntryPoint);
858 
859                 Status = STATUS_DLL_INIT_FAILED;
860                 goto Quickie;
861             }
862         }
863     }
864 
865     /* Loop in order */
866     ListHead = &Peb->Ldr->InInitializationOrderModuleList;
867     NextEntry = NextEntry->Flink;
868     while (NextEntry != ListHead)
869     {
870         /* Get the Data Entry */
871         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
872 
873         /* FIXME: Verify NX Compat */
874         // LdrpCheckNXCompatibility()
875 
876         /* Next entry */
877         NextEntry = NextEntry->Flink;
878     }
879 
880     /* Check for TLS */
881     if (LdrpImageHasTls && Context)
882     {
883         /* Set up the Act Ctx */
884         ActCtx.Size = sizeof(ActCtx);
885         ActCtx.Format = 1;
886         RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
887 
888         /* Activate the ActCtx */
889         RtlActivateActivationContextUnsafeFast(&ActCtx,
890                                                LdrpImageEntry->EntryPointActivationContext);
891 
892         _SEH2_TRY
893         {
894             /* Do TLS callbacks */
895             LdrpCallTlsInitializers(LdrpImageEntry, DLL_PROCESS_ATTACH);
896         }
897         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
898         {
899             /* Do nothing */
900         }
901         _SEH2_END;
902 
903         /* Deactivate the ActCtx */
904         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
905     }
906 
907 Quickie:
908     /* Restore old TEB */
909     LdrpTopLevelDllBeingLoadedTeb = OldTldTeb;
910 
911     /* Check if the array is in the heap */
912     if (LdrRootEntry != LocalArray)
913     {
914         /* Free the array */
915         RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry);
916     }
917 
918     /* Return to caller */
919     DPRINT("LdrpRunInitializeRoutines() done\n");
920     return Status;
921 }
922 
923 /*
924  * @implemented
925  */
926 NTSTATUS
927 NTAPI
928 LdrShutdownProcess(VOID)
929 {
930     PPEB Peb = NtCurrentPeb();
931     PLDR_DATA_TABLE_ENTRY LdrEntry;
932     PLIST_ENTRY NextEntry, ListHead;
933     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
934     PVOID EntryPoint;
935 
936     DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry->BaseDllName);
937     if (LdrpShutdownInProgress) return STATUS_SUCCESS;
938 
939     /* Tell the Shim Engine */
940     if (g_ShimsEnabled)
941     {
942         VOID(NTAPI *SE_ProcessDying)();
943         SE_ProcessDying = RtlDecodeSystemPointer(g_pfnSE_ProcessDying);
944         SE_ProcessDying();
945     }
946 
947     /* Tell the world */
948     if (ShowSnaps)
949     {
950         DPRINT1("\n");
951     }
952 
953     /* Set the shutdown variables */
954     LdrpShutdownThreadId = NtCurrentTeb()->RealClientId.UniqueThread;
955     LdrpShutdownInProgress = TRUE;
956 
957     /* Enter the Loader Lock */
958     RtlEnterCriticalSection(&LdrpLoaderLock);
959 
960     /* Cleanup trace logging data (Etw) */
961     if (SharedUserData->TraceLogging)
962     {
963         /* FIXME */
964         DPRINT1("We don't support Etw yet.\n");
965     }
966 
967     /* Start at the end */
968     ListHead = &Peb->Ldr->InInitializationOrderModuleList;
969     NextEntry = ListHead->Blink;
970     while (NextEntry != ListHead)
971     {
972         /* Get the current entry */
973         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
974         NextEntry = NextEntry->Blink;
975 
976         /* Make sure it's not ourselves */
977         if (Peb->ImageBaseAddress != LdrEntry->DllBase)
978         {
979             /* Get the entrypoint */
980             EntryPoint = LdrEntry->EntryPoint;
981 
982             /* Check if we are ready to call it */
983             if (EntryPoint &&
984                 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
985                 LdrEntry->Flags)
986             {
987                 /* Set up the Act Ctx */
988                 ActCtx.Size = sizeof(ActCtx);
989                 ActCtx.Format = 1;
990                 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
991 
992                 /* Activate the ActCtx */
993                 RtlActivateActivationContextUnsafeFast(&ActCtx,
994                                                        LdrEntry->EntryPointActivationContext);
995 
996                 _SEH2_TRY
997                 {
998                     /* Check if it has TLS */
999                     if (LdrEntry->TlsIndex)
1000                     {
1001                         /* Call TLS */
1002                         LdrpCallTlsInitializers(LdrEntry, DLL_PROCESS_DETACH);
1003                     }
1004 
1005                     /* Call the Entrypoint */
1006                     DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
1007                            &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
1008                     LdrpCallInitRoutine(EntryPoint,
1009                                         LdrEntry->DllBase,
1010                                         DLL_PROCESS_DETACH,
1011                                         (PVOID)1);
1012                 }
1013                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1014                 {
1015                     DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_PROCESS_DETACH) for %wZ\n",
1016                             _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
1017                 }
1018                 _SEH2_END;
1019 
1020                 /* Deactivate the ActCtx */
1021                 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1022             }
1023         }
1024     }
1025 
1026     /* Check for TLS */
1027     if (LdrpImageHasTls)
1028     {
1029         /* Set up the Act Ctx */
1030         ActCtx.Size = sizeof(ActCtx);
1031         ActCtx.Format = 1;
1032         RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1033 
1034         /* Activate the ActCtx */
1035         RtlActivateActivationContextUnsafeFast(&ActCtx,
1036                                                LdrpImageEntry->EntryPointActivationContext);
1037 
1038         _SEH2_TRY
1039         {
1040             /* Do TLS callbacks */
1041             LdrpCallTlsInitializers(LdrpImageEntry, DLL_PROCESS_DETACH);
1042         }
1043         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1044         {
1045             /* Do nothing */
1046         }
1047         _SEH2_END;
1048 
1049         /* Deactivate the ActCtx */
1050         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1051     }
1052 
1053     /* FIXME: Do Heap detection and Etw final shutdown */
1054 
1055     /* Release the lock */
1056     RtlLeaveCriticalSection(&LdrpLoaderLock);
1057     DPRINT("LdrpShutdownProcess() done\n");
1058 
1059     return STATUS_SUCCESS;
1060 }
1061 
1062 /*
1063  * @implemented
1064  */
1065 NTSTATUS
1066 NTAPI
1067 LdrShutdownThread(VOID)
1068 {
1069     PPEB Peb = NtCurrentPeb();
1070     PTEB Teb = NtCurrentTeb();
1071     PLDR_DATA_TABLE_ENTRY LdrEntry;
1072     PLIST_ENTRY NextEntry, ListHead;
1073     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
1074     PVOID EntryPoint;
1075 
1076     DPRINT("LdrShutdownThread() called for %wZ\n",
1077             &LdrpImageEntry->BaseDllName);
1078 
1079     /* Cleanup trace logging data (Etw) */
1080     if (SharedUserData->TraceLogging)
1081     {
1082         /* FIXME */
1083         DPRINT1("We don't support Etw yet.\n");
1084     }
1085 
1086     /* Get the Ldr Lock */
1087     RtlEnterCriticalSection(&LdrpLoaderLock);
1088 
1089     /* Start at the end */
1090     ListHead = &Peb->Ldr->InInitializationOrderModuleList;
1091     NextEntry = ListHead->Blink;
1092     while (NextEntry != ListHead)
1093     {
1094         /* Get the current entry */
1095         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
1096         NextEntry = NextEntry->Blink;
1097 
1098         /* Make sure it's not ourselves */
1099         if (Peb->ImageBaseAddress != LdrEntry->DllBase)
1100         {
1101             /* Check if we should call */
1102             if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
1103                 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
1104                 (LdrEntry->Flags & LDRP_IMAGE_DLL))
1105             {
1106                 /* Get the entrypoint */
1107                 EntryPoint = LdrEntry->EntryPoint;
1108 
1109                 /* Check if we are ready to call it */
1110                 if (EntryPoint)
1111                 {
1112                     /* Set up the Act Ctx */
1113                     ActCtx.Size = sizeof(ActCtx);
1114                     ActCtx.Format = 1;
1115                     RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1116 
1117                     /* Activate the ActCtx */
1118                     RtlActivateActivationContextUnsafeFast(&ActCtx,
1119                                                            LdrEntry->EntryPointActivationContext);
1120 
1121                     _SEH2_TRY
1122                     {
1123                         /* Check if it has TLS */
1124                         if (LdrEntry->TlsIndex)
1125                         {
1126                             /* Make sure we're not shutting down */
1127                             if (!LdrpShutdownInProgress)
1128                             {
1129                                 /* Call TLS */
1130                                 LdrpCallTlsInitializers(LdrEntry, DLL_THREAD_DETACH);
1131                             }
1132                         }
1133 
1134                         /* Make sure we're not shutting down */
1135                         if (!LdrpShutdownInProgress)
1136                         {
1137                             /* Call the Entrypoint */
1138                             DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
1139                                    &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
1140                             LdrpCallInitRoutine(EntryPoint,
1141                                                 LdrEntry->DllBase,
1142                                                 DLL_THREAD_DETACH,
1143                                                 NULL);
1144                         }
1145                     }
1146                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1147                     {
1148                         DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_THREAD_DETACH) for %wZ\n",
1149                                 _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
1150                     }
1151                     _SEH2_END;
1152 
1153                     /* Deactivate the ActCtx */
1154                     RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1155                 }
1156             }
1157         }
1158     }
1159 
1160     /* Check for TLS */
1161     if (LdrpImageHasTls)
1162     {
1163         /* Set up the Act Ctx */
1164         ActCtx.Size = sizeof(ActCtx);
1165         ActCtx.Format = 1;
1166         RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1167 
1168         /* Activate the ActCtx */
1169         RtlActivateActivationContextUnsafeFast(&ActCtx,
1170                                                LdrpImageEntry->EntryPointActivationContext);
1171 
1172         _SEH2_TRY
1173         {
1174             /* Do TLS callbacks */
1175             LdrpCallTlsInitializers(LdrpImageEntry, DLL_THREAD_DETACH);
1176         }
1177         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1178         {
1179             /* Do nothing */
1180         }
1181         _SEH2_END;
1182 
1183         /* Deactivate the ActCtx */
1184         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1185     }
1186 
1187     /* Free TLS */
1188     LdrpFreeTls();
1189     RtlLeaveCriticalSection(&LdrpLoaderLock);
1190 
1191     /* Check for expansion slots */
1192     if (Teb->TlsExpansionSlots)
1193     {
1194         /* Free expansion slots */
1195         RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->TlsExpansionSlots);
1196     }
1197 
1198     /* Check for FLS Data */
1199     if (Teb->FlsData)
1200     {
1201         /* FIXME */
1202         DPRINT1("We don't support FLS Data yet\n");
1203     }
1204 
1205     /* Check for Fiber data */
1206     if (Teb->HasFiberData)
1207     {
1208         /* Free Fiber data*/
1209         RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->NtTib.FiberData);
1210         Teb->NtTib.FiberData = NULL;
1211     }
1212 
1213     /* Free the activation context stack */
1214     RtlFreeThreadActivationContextStack();
1215     DPRINT("LdrShutdownThread() done\n");
1216 
1217     return STATUS_SUCCESS;
1218 }
1219 
1220 NTSTATUS
1221 NTAPI
1222 LdrpInitializeTls(VOID)
1223 {
1224     PLIST_ENTRY NextEntry, ListHead;
1225     PLDR_DATA_TABLE_ENTRY LdrEntry;
1226     PIMAGE_TLS_DIRECTORY TlsDirectory;
1227     PLDRP_TLS_DATA TlsData;
1228     ULONG Size;
1229 
1230     /* Initialize the TLS List */
1231     InitializeListHead(&LdrpTlsList);
1232 
1233     /* Loop all the modules */
1234     ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1235     NextEntry = ListHead->Flink;
1236     while (ListHead != NextEntry)
1237     {
1238         /* Get the entry */
1239         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1240         NextEntry = NextEntry->Flink;
1241 
1242         /* Get the TLS directory */
1243         TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
1244                                                     TRUE,
1245                                                     IMAGE_DIRECTORY_ENTRY_TLS,
1246                                                     &Size);
1247 
1248         /* Check if we have a directory */
1249         if (!TlsDirectory) continue;
1250 
1251         /* Check if the image has TLS */
1252         if (!LdrpImageHasTls) LdrpImageHasTls = TRUE;
1253 
1254         /* Show debug message */
1255         if (ShowSnaps)
1256         {
1257             DPRINT1("LDR: Tls Found in %wZ at %p\n",
1258                     &LdrEntry->BaseDllName,
1259                     TlsDirectory);
1260         }
1261 
1262         /* Allocate an entry */
1263         TlsData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA));
1264         if (!TlsData) return STATUS_NO_MEMORY;
1265 
1266         /* Lock the DLL and mark it for TLS Usage */
1267         LdrEntry->LoadCount = -1;
1268         LdrEntry->TlsIndex = -1;
1269 
1270         /* Save the cached TLS data */
1271         TlsData->TlsDirectory = *TlsDirectory;
1272         InsertTailList(&LdrpTlsList, &TlsData->TlsLinks);
1273 
1274         /* Update the index */
1275         *(PLONG)TlsData->TlsDirectory.AddressOfIndex = LdrpNumberOfTlsEntries;
1276         TlsData->TlsDirectory.Characteristics = LdrpNumberOfTlsEntries++;
1277     }
1278 
1279     /* Done setting up TLS, allocate entries */
1280     return LdrpAllocateTls();
1281 }
1282 
1283 NTSTATUS
1284 NTAPI
1285 LdrpAllocateTls(VOID)
1286 {
1287     PTEB Teb = NtCurrentTeb();
1288     PLIST_ENTRY NextEntry, ListHead;
1289     PLDRP_TLS_DATA TlsData;
1290     SIZE_T TlsDataSize;
1291     PVOID *TlsVector;
1292 
1293     /* Check if we have any entries */
1294     if (!LdrpNumberOfTlsEntries)
1295         return STATUS_SUCCESS;
1296 
1297     /* Allocate the vector array */
1298     TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
1299                                     0,
1300                                     LdrpNumberOfTlsEntries * sizeof(PVOID));
1301     if (!TlsVector) return STATUS_NO_MEMORY;
1302     Teb->ThreadLocalStoragePointer = TlsVector;
1303 
1304     /* Loop the TLS Array */
1305     ListHead = &LdrpTlsList;
1306     NextEntry = ListHead->Flink;
1307     while (NextEntry != ListHead)
1308     {
1309         /* Get the entry */
1310         TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1311         NextEntry = NextEntry->Flink;
1312 
1313         /* Allocate this vector */
1314         TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
1315                       TlsData->TlsDirectory.StartAddressOfRawData;
1316         TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
1317                                                                            0,
1318                                                                            TlsDataSize);
1319         if (!TlsVector[TlsData->TlsDirectory.Characteristics])
1320         {
1321             /* Out of memory */
1322             return STATUS_NO_MEMORY;
1323         }
1324 
1325         /* Show debug message */
1326         if (ShowSnaps)
1327         {
1328             DPRINT1("LDR: TlsVector %p Index %lu = %p copied from %x to %p\n",
1329                     TlsVector,
1330                     TlsData->TlsDirectory.Characteristics,
1331                     &TlsVector[TlsData->TlsDirectory.Characteristics],
1332                     TlsData->TlsDirectory.StartAddressOfRawData,
1333                     TlsVector[TlsData->TlsDirectory.Characteristics]);
1334         }
1335 
1336         /* Copy the data */
1337         RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
1338                       (PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
1339                       TlsDataSize);
1340     }
1341 
1342     /* Done */
1343     return STATUS_SUCCESS;
1344 }
1345 
1346 VOID
1347 NTAPI
1348 LdrpFreeTls(VOID)
1349 {
1350     PLIST_ENTRY ListHead, NextEntry;
1351     PLDRP_TLS_DATA TlsData;
1352     PVOID *TlsVector;
1353     PTEB Teb = NtCurrentTeb();
1354 
1355     /* Get a pointer to the vector array */
1356     TlsVector = Teb->ThreadLocalStoragePointer;
1357     if (!TlsVector) return;
1358 
1359     /* Loop through it */
1360     ListHead = &LdrpTlsList;
1361     NextEntry = ListHead->Flink;
1362     while (NextEntry != ListHead)
1363     {
1364         TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1365         NextEntry = NextEntry->Flink;
1366 
1367         /* Free each entry */
1368         if (TlsVector[TlsData->TlsDirectory.Characteristics])
1369         {
1370             RtlFreeHeap(RtlGetProcessHeap(),
1371                         0,
1372                         TlsVector[TlsData->TlsDirectory.Characteristics]);
1373         }
1374     }
1375 
1376     /* Free the array itself */
1377     RtlFreeHeap(RtlGetProcessHeap(),
1378                 0,
1379                 TlsVector);
1380 }
1381 
1382 NTSTATUS
1383 NTAPI
1384 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE OptionsKey)
1385 {
1386     NTSTATUS Status;
1387     HANDLE KeyHandle;
1388     ULONG ExecuteOptions, MinimumStackCommit = 0, GlobalFlag;
1389 
1390     /* Return error if we were not provided a pointer where to save the options key handle */
1391     if (!OptionsKey) return STATUS_INVALID_HANDLE;
1392 
1393     /* Zero initialize the options key pointer */
1394     *OptionsKey = NULL;
1395 
1396     /* Open the options key */
1397     Status = LdrOpenImageFileOptionsKey(ImagePathName, 0, &KeyHandle);
1398 
1399     /* Save it if it was opened successfully */
1400     if (NT_SUCCESS(Status))
1401         *OptionsKey = KeyHandle;
1402 
1403     if (KeyHandle)
1404     {
1405         /* There are image specific options, read them starting with NXCOMPAT */
1406         Status = LdrQueryImageFileKeyOption(KeyHandle,
1407                                             L"ExecuteOptions",
1408                                             4,
1409                                             &ExecuteOptions,
1410                                             sizeof(ExecuteOptions),
1411                                             0);
1412 
1413         if (NT_SUCCESS(Status))
1414         {
1415             /* TODO: Set execution options for the process */
1416             /*
1417             if (ExecuteOptions == 0)
1418                 ExecuteOptions = 1;
1419             else
1420                 ExecuteOptions = 2;
1421             ZwSetInformationProcess(NtCurrentProcess(),
1422                                     ProcessExecuteFlags,
1423                                     &ExecuteOptions,
1424                                     sizeof(ULONG));*/
1425 
1426         }
1427 
1428         /* Check if this image uses large pages */
1429         if (Peb->ImageUsesLargePages)
1430         {
1431             /* TODO: If it does, open large page key */
1432             UNIMPLEMENTED;
1433         }
1434 
1435         /* Get various option values */
1436         LdrQueryImageFileKeyOption(KeyHandle,
1437                                    L"DisableHeapLookaside",
1438                                    REG_DWORD,
1439                                    &RtlpDisableHeapLookaside,
1440                                    sizeof(RtlpDisableHeapLookaside),
1441                                    NULL);
1442 
1443         LdrQueryImageFileKeyOption(KeyHandle,
1444                                    L"ShutdownFlags",
1445                                    REG_DWORD,
1446                                    &RtlpShutdownProcessFlags,
1447                                    sizeof(RtlpShutdownProcessFlags),
1448                                    NULL);
1449 
1450         LdrQueryImageFileKeyOption(KeyHandle,
1451                                    L"MinimumStackCommitInBytes",
1452                                    REG_DWORD,
1453                                    &MinimumStackCommit,
1454                                    sizeof(MinimumStackCommit),
1455                                    NULL);
1456 
1457         /* Update PEB's minimum stack commit if it's lower */
1458         if (Peb->MinimumStackCommit < MinimumStackCommit)
1459             Peb->MinimumStackCommit = MinimumStackCommit;
1460 
1461         /* Set the global flag */
1462         Status = LdrQueryImageFileKeyOption(KeyHandle,
1463                                             L"GlobalFlag",
1464                                             REG_DWORD,
1465                                             &GlobalFlag,
1466                                             sizeof(GlobalFlag),
1467                                             NULL);
1468 
1469         if (NT_SUCCESS(Status))
1470             Peb->NtGlobalFlag = GlobalFlag;
1471         else
1472             GlobalFlag = 0;
1473 
1474         /* Call AVRF if necessary */
1475         if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
1476         {
1477             Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
1478             if (!NT_SUCCESS(Status))
1479             {
1480                 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1481             }
1482         }
1483     }
1484     else
1485     {
1486         /* There are no image-specific options, so perform global initialization */
1487         if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
1488         {
1489             /* Initialize app verifier package */
1490             Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
1491             if (!NT_SUCCESS(Status))
1492             {
1493                 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1494             }
1495         }
1496     }
1497 
1498     return STATUS_SUCCESS;
1499 }
1500 
1501 VOID
1502 NTAPI
1503 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)
1504 {
1505     UNIMPLEMENTED;
1506 }
1507 
1508 VOID
1509 NTAPI
1510 LdrpInitializeProcessCompat(PVOID* pOldShimData)
1511 {
1512     static const GUID* GuidOrder[] = { &COMPAT_GUID_WIN10, &COMPAT_GUID_WIN81, &COMPAT_GUID_WIN8,
1513                                        &COMPAT_GUID_WIN7, &COMPAT_GUID_VISTA };
1514     static const DWORD GuidVersions[] = { WINVER_WIN10, WINVER_WIN81, WINVER_WIN8, WINVER_WIN7, WINVER_VISTA };
1515 
1516     ULONG Buffer[(sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * 10 + sizeof(ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION)) / sizeof(ULONG)];
1517     ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION* ContextCompatInfo;
1518     SIZE_T SizeRequired;
1519     NTSTATUS Status;
1520     DWORD n, cur;
1521     ReactOS_ShimData* pShimData = *pOldShimData;
1522 
1523     C_ASSERT(RTL_NUMBER_OF(GuidOrder) == RTL_NUMBER_OF(GuidVersions));
1524 
1525     if (pShimData)
1526     {
1527         if (pShimData->dwMagic != REACTOS_SHIMDATA_MAGIC ||
1528             pShimData->dwSize != sizeof(ReactOS_ShimData))
1529         {
1530             DPRINT1("LdrpInitializeProcessCompat: Corrupt pShimData (0x%x, %u)\n", pShimData->dwMagic, pShimData->dwSize);
1531             return;
1532         }
1533         if (pShimData->dwRosProcessCompatVersion)
1534         {
1535             DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion already set to 0x%x\n", pShimData->dwRosProcessCompatVersion);
1536             return;
1537         }
1538     }
1539 
1540     SizeRequired = sizeof(Buffer);
1541     Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF,
1542                                                   NULL,
1543                                                   NULL,
1544                                                   CompatibilityInformationInActivationContext,
1545                                                   Buffer,
1546                                                   sizeof(Buffer),
1547                                                   &SizeRequired);
1548 
1549     if (!NT_SUCCESS(Status))
1550     {
1551         DPRINT1("LdrpInitializeProcessCompat: Unable to query process actctx with status %x\n", Status);
1552         return;
1553     }
1554 
1555     ContextCompatInfo = (ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*)Buffer;
1556     /* No Compatibility elements present, bail out */
1557     if (ContextCompatInfo->ElementCount == 0)
1558         return;
1559 
1560     /* Search for known GUID's, starting from newest to oldest. */
1561     for (cur = 0; cur < RTL_NUMBER_OF(GuidOrder); ++cur)
1562     {
1563         for (n = 0; n < ContextCompatInfo->ElementCount; ++n)
1564         {
1565             if (ContextCompatInfo->Elements[n].Type == ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS &&
1566                 RtlCompareMemory(&ContextCompatInfo->Elements[n].Id, GuidOrder[cur], sizeof(GUID)) == sizeof(GUID))
1567             {
1568                 /* If this process did not need shim data before, allocate and store it */
1569                 if (pShimData == NULL)
1570                 {
1571                     PPEB Peb = NtCurrentPeb();
1572 
1573                     ASSERT(Peb->pShimData == NULL);
1574                     pShimData = RtlAllocateHeap(Peb->ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*pShimData));
1575 
1576                     if (!pShimData)
1577                     {
1578                         DPRINT1("LdrpInitializeProcessCompat: Unable to allocated %u bytes\n", sizeof(*pShimData));
1579                         return;
1580                     }
1581 
1582                     pShimData->dwSize = sizeof(*pShimData);
1583                     pShimData->dwMagic = REACTOS_SHIMDATA_MAGIC;
1584 
1585                     Peb->pShimData = pShimData;
1586                     *pOldShimData = pShimData;
1587                 }
1588 
1589                 /* Store the highest found version, and bail out. */
1590                 pShimData->dwRosProcessCompatVersion = GuidVersions[cur];
1591                 DPRINT1("LdrpInitializeProcessCompat: Found guid for winver 0x%x\n", GuidVersions[cur]);
1592                 return;
1593             }
1594         }
1595     }
1596 }
1597 
1598 
1599 NTSTATUS
1600 NTAPI
1601 LdrpInitializeProcess(IN PCONTEXT Context,
1602                       IN PVOID SystemArgument1)
1603 {
1604     RTL_HEAP_PARAMETERS HeapParameters;
1605     ULONG ComSectionSize;
1606     //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1607     PVOID OldShimData;
1608     OBJECT_ATTRIBUTES ObjectAttributes;
1609     //UNICODE_STRING LocalFileName, FullImageName;
1610     HANDLE SymLinkHandle;
1611     //ULONG DebugHeapOnly;
1612     UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
1613     PPEB Peb = NtCurrentPeb();
1614     BOOLEAN IsDotNetImage = FALSE;
1615     BOOLEAN FreeCurDir = FALSE;
1616     //HANDLE CompatKey;
1617     PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
1618     //LPWSTR ImagePathBuffer;
1619     ULONG ConfigSize;
1620     UNICODE_STRING CurrentDirectory;
1621     HANDLE OptionsKey;
1622     ULONG HeapFlags;
1623     PIMAGE_NT_HEADERS NtHeader;
1624     LPWSTR NtDllName = NULL;
1625     NTSTATUS Status, ImportStatus;
1626     NLSTABLEINFO NlsTable;
1627     PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
1628     PTEB Teb = NtCurrentTeb();
1629     PLIST_ENTRY ListHead;
1630     PLIST_ENTRY NextEntry;
1631     ULONG i;
1632     PWSTR ImagePath;
1633     ULONG DebugProcessHeapOnly = 0;
1634     PLDR_DATA_TABLE_ENTRY NtLdrEntry;
1635     PWCHAR Current;
1636     ULONG ExecuteOptions = 0;
1637     PVOID ViewBase;
1638 
1639     /* Set a NULL SEH Filter */
1640     RtlSetUnhandledExceptionFilter(NULL);
1641 
1642     /* Get the image path */
1643     ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
1644 
1645     /* Check if it's not normalized */
1646     if (!(Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED))
1647     {
1648         /* Normalize it*/
1649         ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
1650     }
1651 
1652     /* Create a unicode string for the Image Path */
1653     ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
1654     ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
1655     ImagePathName.Buffer = ImagePath;
1656 
1657     /* Get the NT Headers */
1658     NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
1659 
1660     /* Get the execution options */
1661     Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &OptionsKey);
1662 
1663     /* Check if this is a .NET executable */
1664     if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1665                                      TRUE,
1666                                      IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
1667                                      &ComSectionSize))
1668     {
1669         /* Remember this for later */
1670         IsDotNetImage = TRUE;
1671     }
1672 
1673     /* Save the NTDLL Base address */
1674     NtDllBase = SystemArgument1;
1675 
1676     /* If this is a Native Image */
1677     if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
1678     {
1679         /* Then do DLL Validation */
1680         LdrpDllValidation = TRUE;
1681     }
1682 
1683     /* Save the old Shim Data */
1684     OldShimData = Peb->pShimData;
1685 
1686     /* ReactOS specific: do not clear it. (Windows starts doing the same in later versions) */
1687     //Peb->pShimData = NULL;
1688 
1689     /* Save the number of processors and CS Timeout */
1690     LdrpNumberOfProcessors = Peb->NumberOfProcessors;
1691     RtlpTimeout = Peb->CriticalSectionTimeout;
1692 
1693     /* Normalize the parameters */
1694     ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
1695     if (ProcessParameters)
1696     {
1697         /* Save the Image and Command Line Names */
1698         ImageFileName = ProcessParameters->ImagePathName;
1699         CommandLine = ProcessParameters->CommandLine;
1700     }
1701     else
1702     {
1703         /* It failed, initialize empty strings */
1704         RtlInitUnicodeString(&ImageFileName, NULL);
1705         RtlInitUnicodeString(&CommandLine, NULL);
1706     }
1707 
1708     /* Initialize NLS data */
1709     RtlInitNlsTables(Peb->AnsiCodePageData,
1710                      Peb->OemCodePageData,
1711                      Peb->UnicodeCaseTableData,
1712                      &NlsTable);
1713 
1714     /* Reset NLS Translations */
1715     RtlResetRtlTranslations(&NlsTable);
1716 
1717     /* Get the Image Config Directory */
1718     LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1719                                               TRUE,
1720                                               IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
1721                                               &ConfigSize);
1722 
1723     /* Setup the Heap Parameters */
1724     RtlZeroMemory(&HeapParameters, sizeof(RTL_HEAP_PARAMETERS));
1725     HeapFlags = HEAP_GROWABLE;
1726     HeapParameters.Length = sizeof(RTL_HEAP_PARAMETERS);
1727 
1728     /* Check if we have Configuration Data */
1729     if ((LoadConfig) && (ConfigSize == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY)))
1730     {
1731         /* FIXME: Custom heap settings and misc. */
1732         DPRINT1("We don't support LOAD_CONFIG data yet\n");
1733     }
1734 
1735     /* Check for custom affinity mask */
1736     if (Peb->ImageProcessAffinityMask)
1737     {
1738         /* Set it */
1739         Status = NtSetInformationProcess(NtCurrentProcess(),
1740                                          ProcessAffinityMask,
1741                                          &Peb->ImageProcessAffinityMask,
1742                                          sizeof(Peb->ImageProcessAffinityMask));
1743     }
1744 
1745     /* Check if verbose debugging (ShowSnaps) was requested */
1746     ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1747 
1748     /* Start verbose debugging messages right now if they were requested */
1749     if (ShowSnaps)
1750     {
1751         DPRINT1("LDR: PID: 0x%p started - '%wZ'\n",
1752                 Teb->ClientId.UniqueProcess,
1753                 &CommandLine);
1754     }
1755 
1756     /* If the timeout is too long */
1757     if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
1758     {
1759         /* Then disable CS Timeout */
1760         RtlpTimeoutDisable = TRUE;
1761     }
1762 
1763     /* Initialize Critical Section Data */
1764     RtlpInitDeferedCriticalSection();
1765 
1766     /* Initialize VEH Call lists */
1767     RtlpInitializeVectoredExceptionHandling();
1768 
1769     /* Set TLS/FLS Bitmap data */
1770     Peb->FlsBitmap = &FlsBitMap;
1771     Peb->TlsBitmap = &TlsBitMap;
1772     Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
1773 
1774     /* Initialize FLS Bitmap */
1775     RtlInitializeBitMap(&FlsBitMap,
1776                         Peb->FlsBitmapBits,
1777                         FLS_MAXIMUM_AVAILABLE);
1778     RtlSetBit(&FlsBitMap, 0);
1779 
1780     /* Initialize TLS Bitmap */
1781     RtlInitializeBitMap(&TlsBitMap,
1782                         Peb->TlsBitmapBits,
1783                         TLS_MINIMUM_AVAILABLE);
1784     RtlSetBit(&TlsBitMap, 0);
1785     RtlInitializeBitMap(&TlsExpansionBitMap,
1786                         Peb->TlsExpansionBitmapBits,
1787                         TLS_EXPANSION_SLOTS);
1788     RtlSetBit(&TlsExpansionBitMap, 0);
1789 
1790     /* Initialize the Hash Table */
1791     for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
1792     {
1793         InitializeListHead(&LdrpHashTable[i]);
1794     }
1795 
1796     /* Initialize the Loader Lock */
1797     // FIXME: What's the point of initing it manually, if two lines lower
1798     //        a call to RtlInitializeCriticalSection() is being made anyway?
1799     //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1800     //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1801     RtlInitializeCriticalSection(&LdrpLoaderLock);
1802     LdrpLoaderLockInit = TRUE;
1803 
1804     /* Check if User Stack Trace Database support was requested */
1805     if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
1806     {
1807         DPRINT1("We don't support user stack trace databases yet\n");
1808     }
1809 
1810     /* Setup Fast PEB Lock */
1811     RtlInitializeCriticalSection(&FastPebLock);
1812     Peb->FastPebLock = &FastPebLock;
1813     //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1814     //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1815 
1816     /* Setup Callout Lock and Notification list */
1817     //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1818     InitializeListHead(&LdrpDllNotificationList);
1819 
1820     /* For old executables, use 16-byte aligned heap */
1821     if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
1822         (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
1823     {
1824         HeapFlags |= HEAP_CREATE_ALIGN_16;
1825     }
1826 
1827     /* Setup the Heap */
1828     RtlInitializeHeapManager();
1829     Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
1830                                      NULL,
1831                                      NtHeader->OptionalHeader.SizeOfHeapReserve,
1832                                      NtHeader->OptionalHeader.SizeOfHeapCommit,
1833                                      NULL,
1834                                      &HeapParameters);
1835 
1836     if (!Peb->ProcessHeap)
1837     {
1838         DPRINT1("Failed to create process heap\n");
1839         return STATUS_NO_MEMORY;
1840     }
1841 
1842     /* Allocate an Activation Context Stack */
1843     Status = RtlAllocateActivationContextStack(&Teb->ActivationContextStackPointer);
1844     if (!NT_SUCCESS(Status)) return Status;
1845 
1846     // FIXME: Loader private heap is missing
1847     //DPRINT1("Loader private heap is missing\n");
1848 
1849     /* Check for Debug Heap */
1850     if (OptionsKey)
1851     {
1852         /* Query the setting */
1853         Status = LdrQueryImageFileKeyOption(OptionsKey,
1854                                             L"DebugProcessHeapOnly",
1855                                             REG_DWORD,
1856                                             &DebugProcessHeapOnly,
1857                                             sizeof(ULONG),
1858                                             NULL);
1859 
1860         if (NT_SUCCESS(Status))
1861         {
1862             /* Reset DPH if requested */
1863             if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
1864             {
1865                 RtlpDphGlobalFlags &= ~DPH_FLAG_DLL_NOTIFY;
1866                 RtlpPageHeapEnabled = FALSE;
1867             }
1868         }
1869     }
1870 
1871     /* Build the NTDLL Path */
1872     FullPath.Buffer = StringBuffer;
1873     FullPath.Length = 0;
1874     FullPath.MaximumLength = sizeof(StringBuffer);
1875     RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
1876     RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
1877     RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
1878 
1879     /* Open the Known DLLs directory */
1880     RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
1881     InitializeObjectAttributes(&ObjectAttributes,
1882                                &KnownDllString,
1883                                OBJ_CASE_INSENSITIVE,
1884                                NULL,
1885                                NULL);
1886     Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
1887                                    DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
1888                                    &ObjectAttributes);
1889 
1890     /* Check if it exists */
1891     if (NT_SUCCESS(Status))
1892     {
1893         /* Open the Known DLLs Path */
1894         RtlInitUnicodeString(&KnownDllString, L"KnownDllPath");
1895         InitializeObjectAttributes(&ObjectAttributes,
1896                                    &KnownDllString,
1897                                    OBJ_CASE_INSENSITIVE,
1898                                    LdrpKnownDllObjectDirectory,
1899                                    NULL);
1900         Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
1901                                           SYMBOLIC_LINK_QUERY,
1902                                           &ObjectAttributes);
1903         if (NT_SUCCESS(Status))
1904         {
1905             /* Query the path */
1906             LdrpKnownDllPath.Length = 0;
1907             LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
1908             LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
1909             Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
1910             NtClose(SymLinkHandle);
1911             if (!NT_SUCCESS(Status))
1912             {
1913                 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
1914                 return Status;
1915             }
1916         }
1917     }
1918 
1919     /* Check if we failed */
1920     if (!NT_SUCCESS(Status))
1921     {
1922         /* Assume System32 */
1923         LdrpKnownDllObjectDirectory = NULL;
1924         RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer);
1925         LdrpKnownDllPath.Length -= sizeof(WCHAR);
1926     }
1927 
1928     /* If we have process parameters, get the default path and current path */
1929     if (ProcessParameters)
1930     {
1931         /* Check if we have a Dll Path */
1932         if (ProcessParameters->DllPath.Length)
1933         {
1934             /* Get the path */
1935             LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
1936         }
1937         else
1938         {
1939             /* We need a valid path */
1940             DPRINT1("No valid DllPath was given!\n");
1941             LdrpInitFailure(STATUS_INVALID_PARAMETER);
1942         }
1943 
1944         /* Set the current directory */
1945         CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
1946 
1947         /* Check if it's empty or invalid */
1948         if ((!CurrentDirectory.Buffer) ||
1949             (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
1950             (!CurrentDirectory.Length))
1951         {
1952             /* Allocate space for the buffer */
1953             CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
1954                                                       0,
1955                                                       3 * sizeof(WCHAR) +
1956                                                       sizeof(UNICODE_NULL));
1957             if (!CurrentDirectory.Buffer)
1958             {
1959                 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
1960                 // FIXME: And what?
1961             }
1962 
1963             /* Copy the drive of the system root */
1964             RtlMoveMemory(CurrentDirectory.Buffer,
1965                           SharedUserData->NtSystemRoot,
1966                           3 * sizeof(WCHAR));
1967             CurrentDirectory.Buffer[3] = UNICODE_NULL;
1968             CurrentDirectory.Length = 3 * sizeof(WCHAR);
1969             CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
1970 
1971             FreeCurDir = TRUE;
1972             DPRINT("Using dynamically allocd curdir\n");
1973         }
1974         else
1975         {
1976             /* Use the local buffer */
1977             DPRINT("Using local system root\n");
1978         }
1979     }
1980 
1981     /* Setup Loader Data */
1982     Peb->Ldr = &PebLdr;
1983     InitializeListHead(&PebLdr.InLoadOrderModuleList);
1984     InitializeListHead(&PebLdr.InMemoryOrderModuleList);
1985     InitializeListHead(&PebLdr.InInitializationOrderModuleList);
1986     PebLdr.Length = sizeof(PEB_LDR_DATA);
1987     PebLdr.Initialized = TRUE;
1988 
1989     /* Allocate a data entry for the Image */
1990     LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
1991 
1992     /* Set it up */
1993     LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrpImageEntry->DllBase);
1994     LdrpImageEntry->LoadCount = -1;
1995     LdrpImageEntry->EntryPointActivationContext = 0;
1996     LdrpImageEntry->FullDllName = ImageFileName;
1997 
1998     if (IsDotNetImage)
1999         LdrpImageEntry->Flags = LDRP_COR_IMAGE;
2000     else
2001         LdrpImageEntry->Flags = 0;
2002 
2003     /* Check if the name is empty */
2004     if (!ImageFileName.Buffer[0])
2005     {
2006         /* Use the same Base name */
2007         LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2008     }
2009     else
2010     {
2011         /* Find the last slash */
2012         Current = ImageFileName.Buffer;
2013         while (*Current)
2014         {
2015             if (*Current++ == '\\')
2016             {
2017                 /* Set this path */
2018                 NtDllName = Current;
2019             }
2020         }
2021 
2022         /* Did we find anything? */
2023         if (!NtDllName)
2024         {
2025             /* Use the same Base name */
2026             LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2027         }
2028         else
2029         {
2030             /* Setup the name */
2031             LdrpImageEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
2032             LdrpImageEntry->BaseDllName.MaximumLength = LdrpImageEntry->BaseDllName.Length + sizeof(WCHAR);
2033             LdrpImageEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
2034                                                      (ImageFileName.Length - LdrpImageEntry->BaseDllName.Length));
2035         }
2036     }
2037 
2038     /* Processing done, insert it */
2039     LdrpInsertMemoryTableEntry(LdrpImageEntry);
2040     LdrpImageEntry->Flags |= LDRP_ENTRY_PROCESSED;
2041 
2042     /* Now add an entry for NTDLL */
2043     NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
2044     NtLdrEntry->Flags = LDRP_IMAGE_DLL;
2045     NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
2046     NtLdrEntry->LoadCount = -1;
2047     NtLdrEntry->EntryPointActivationContext = 0;
2048 
2049     NtLdrEntry->FullDllName.Length = FullPath.Length;
2050     NtLdrEntry->FullDllName.MaximumLength = FullPath.MaximumLength;
2051     NtLdrEntry->FullDllName.Buffer = StringBuffer;
2052     RtlAppendUnicodeStringToString(&NtLdrEntry->FullDllName, &NtDllString);
2053 
2054     NtLdrEntry->BaseDllName.Length = NtDllString.Length;
2055     NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength;
2056     NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer;
2057 
2058     /* Processing done, insert it */
2059     LdrpNtDllDataTableEntry = NtLdrEntry;
2060     LdrpInsertMemoryTableEntry(NtLdrEntry);
2061 
2062     /* Let the world know */
2063     if (ShowSnaps)
2064     {
2065         DPRINT1("LDR: NEW PROCESS\n");
2066         DPRINT1("     Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
2067         DPRINT1("     Current Directory: %wZ\n", &CurrentDirectory);
2068         DPRINT1("     Search Path: %wZ\n", &LdrpDefaultPath);
2069     }
2070 
2071     /* Link the Init Order List */
2072     InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
2073                    &LdrpNtDllDataTableEntry->InInitializationOrderLinks);
2074 
2075     /* Initialize Wine's active context implementation for the current process */
2076     actctx_init();
2077 
2078     /* ReactOS specific */
2079     LdrpInitializeProcessCompat(&OldShimData);
2080 
2081     /* Set the current directory */
2082     Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
2083     if (!NT_SUCCESS(Status))
2084     {
2085         /* We failed, check if we should free it */
2086         if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2087 
2088         /* Set it to the NT Root */
2089         CurrentDirectory = NtSystemRoot;
2090         RtlSetCurrentDirectory_U(&CurrentDirectory);
2091     }
2092     else
2093     {
2094         /* We're done with it, free it */
2095         if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2096     }
2097 
2098     /* Check if we should look for a .local file */
2099     if (ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH)
2100     {
2101         /* FIXME */
2102         DPRINT1("We don't support .local overrides yet\n");
2103     }
2104 
2105     /* Check if the Application Verifier was enabled */
2106     if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
2107     {
2108         Status = AVrfInitializeVerifier();
2109         if (!NT_SUCCESS(Status))
2110         {
2111             DPRINT1("LDR: AVrfInitializeVerifier failed (ntstatus 0x%x)\n", Status);
2112             return Status;
2113         }
2114 
2115     }
2116 
2117     if (IsDotNetImage)
2118     {
2119         /* FIXME */
2120         DPRINT1("We don't support .NET applications yet\n");
2121     }
2122 
2123     /* FIXME: Load support for Terminal Services */
2124     if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
2125     {
2126         /* Load kernel32 and call BasePostImportInit... */
2127         DPRINT("Unimplemented codepath!\n");
2128     }
2129 
2130     /* Walk the IAT and load all the DLLs */
2131     ImportStatus = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
2132 
2133     /* Check if relocation is needed */
2134     if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
2135     {
2136         DPRINT1("LDR: Performing EXE relocation\n");
2137 
2138         /* Change the protection to prepare for relocation */
2139         ViewBase = Peb->ImageBaseAddress;
2140         Status = LdrpSetProtection(ViewBase, FALSE);
2141         if (!NT_SUCCESS(Status)) return Status;
2142 
2143         /* Do the relocation */
2144         Status = LdrRelocateImageWithBias(ViewBase,
2145                                           0LL,
2146                                           NULL,
2147                                           STATUS_SUCCESS,
2148                                           STATUS_CONFLICTING_ADDRESSES,
2149                                           STATUS_INVALID_IMAGE_FORMAT);
2150         if (!NT_SUCCESS(Status))
2151         {
2152             DPRINT1("LdrRelocateImageWithBias() failed\n");
2153             return Status;
2154         }
2155 
2156         /* Check if a start context was provided */
2157         if (Context)
2158         {
2159             DPRINT1("WARNING: Relocated EXE Context");
2160             UNIMPLEMENTED; // We should support this
2161             return STATUS_INVALID_IMAGE_FORMAT;
2162         }
2163 
2164         /* Restore the protection */
2165         Status = LdrpSetProtection(ViewBase, TRUE);
2166         if (!NT_SUCCESS(Status)) return Status;
2167     }
2168 
2169     /* Lock the DLLs */
2170     ListHead = &Peb->Ldr->InLoadOrderModuleList;
2171     NextEntry = ListHead->Flink;
2172     while (ListHead != NextEntry)
2173     {
2174         NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2175         NtLdrEntry->LoadCount = -1;
2176         NextEntry = NextEntry->Flink;
2177     }
2178 
2179     /* Phase 0 is done */
2180     LdrpLdrDatabaseIsSetup = TRUE;
2181 
2182     /* Check whether all static imports were properly loaded and return here */
2183     if (!NT_SUCCESS(ImportStatus)) return ImportStatus;
2184 
2185     /* Initialize TLS */
2186     Status = LdrpInitializeTls();
2187     if (!NT_SUCCESS(Status))
2188     {
2189         DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2190                 Status);
2191         return Status;
2192     }
2193 
2194     /* FIXME Mark the DLL Ranges for Stack Traces later */
2195 
2196     /* Notify the debugger now */
2197     if (Peb->BeingDebugged)
2198     {
2199         /* Break */
2200         DbgBreakPoint();
2201 
2202         /* Update show snaps again */
2203         ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
2204     }
2205 
2206     /* Validate the Image for MP Usage */
2207     if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
2208 
2209     /* Check NX Options */
2210     if (SharedUserData->NXSupportPolicy == 1)
2211     {
2212         ExecuteOptions = 0xD;
2213     }
2214     else if (!SharedUserData->NXSupportPolicy)
2215     {
2216         ExecuteOptions = 0xA;
2217     }
2218 
2219     /* Let Mm know */
2220     ZwSetInformationProcess(NtCurrentProcess(),
2221                             ProcessExecuteFlags,
2222                             &ExecuteOptions,
2223                             sizeof(ULONG));
2224 
2225     // FIXME: Should be done by Application Compatibility features,
2226     // by reading the registry, etc...
2227     // For now, this is the old code from ntdll!RtlGetVersion().
2228     RtlInitEmptyUnicodeString(&Peb->CSDVersion, NULL, 0);
2229     if (((Peb->OSCSDVersion >> 8) & 0xFF) != 0)
2230     {
2231         WCHAR szCSDVersion[128];
2232         LONG i;
2233         ULONG Length = ARRAYSIZE(szCSDVersion) - 1;
2234         i = _snwprintf(szCSDVersion, Length,
2235                        L"Service Pack %d",
2236                        ((Peb->OSCSDVersion >> 8) & 0xFF));
2237         if (i < 0)
2238         {
2239             /* Null-terminate if it was overflowed */
2240             szCSDVersion[Length] = UNICODE_NULL;
2241         }
2242 
2243         Length *= sizeof(WCHAR);
2244         Peb->CSDVersion.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
2245                                                  0,
2246                                                  Length + sizeof(UNICODE_NULL));
2247         if (Peb->CSDVersion.Buffer)
2248         {
2249             Peb->CSDVersion.Length = Length;
2250             Peb->CSDVersion.MaximumLength = Length + sizeof(UNICODE_NULL);
2251 
2252             RtlCopyMemory(Peb->CSDVersion.Buffer,
2253                           szCSDVersion,
2254                           Peb->CSDVersion.MaximumLength);
2255             Peb->CSDVersion.Buffer[Peb->CSDVersion.Length / sizeof(WCHAR)] = UNICODE_NULL;
2256         }
2257     }
2258 
2259     /* Check if we had Shim Data */
2260     if (OldShimData)
2261     {
2262         /* Load the Shim Engine */
2263         Peb->AppCompatInfo = NULL;
2264         LdrpLoadShimEngine(OldShimData, &ImagePathName, OldShimData);
2265     }
2266     else
2267     {
2268         /* Check for Application Compatibility Goo */
2269         //LdrQueryApplicationCompatibilityGoo(hKey);
2270         DPRINT("Querying app compat hacks is missing!\n");
2271     }
2272 
2273     /*
2274      * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2275      * incompatible images.
2276      */
2277 
2278     /* Now call the Init Routines */
2279     Status = LdrpRunInitializeRoutines(Context);
2280     if (!NT_SUCCESS(Status))
2281     {
2282         DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2283                 Status);
2284         return Status;
2285     }
2286 
2287     /* Notify Shim Engine */
2288     if (g_ShimsEnabled)
2289     {
2290         VOID(NTAPI *SE_InstallAfterInit)(PUNICODE_STRING, PVOID);
2291         SE_InstallAfterInit = RtlDecodeSystemPointer(g_pfnSE_InstallAfterInit);
2292         SE_InstallAfterInit(&ImagePathName, OldShimData);
2293     }
2294 
2295     /* Check if we have a user-defined Post Process Routine */
2296     if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
2297     {
2298         /* Call it */
2299         Peb->PostProcessInitRoutine();
2300     }
2301 
2302     /* Close the key if we have one opened */
2303     if (OptionsKey) NtClose(OptionsKey);
2304 
2305     /* Return status */
2306     return Status;
2307 }
2308 
2309 VOID
2310 NTAPI
2311 LdrpInitFailure(NTSTATUS Status)
2312 {
2313     ULONG Response;
2314     PPEB Peb = NtCurrentPeb();
2315 
2316     /* Print a debug message */
2317     DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2318             &Peb->ProcessParameters->ImagePathName, Status);
2319 
2320     /* Raise a hard error */
2321     if (!LdrpFatalHardErrorCount)
2322     {
2323         ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response);
2324     }
2325 }
2326 
2327 VOID
2328 NTAPI
2329 LdrpInit(PCONTEXT Context,
2330          PVOID SystemArgument1,
2331          PVOID SystemArgument2)
2332 {
2333     LARGE_INTEGER Timeout;
2334     PTEB Teb = NtCurrentTeb();
2335     NTSTATUS Status, LoaderStatus = STATUS_SUCCESS;
2336     MEMORY_BASIC_INFORMATION MemoryBasicInfo;
2337     PPEB Peb = NtCurrentPeb();
2338 
2339     DPRINT("LdrpInit() %p/%p\n",
2340         NtCurrentTeb()->RealClientId.UniqueProcess,
2341         NtCurrentTeb()->RealClientId.UniqueThread);
2342 
2343 #ifdef _WIN64
2344     /* Set the SList header usage */
2345     RtlpUse16ByteSLists = SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128];
2346 #endif /* _WIN64 */
2347 
2348     /* Check if we have a deallocation stack */
2349     if (!Teb->DeallocationStack)
2350     {
2351         /* We don't, set one */
2352         Status = NtQueryVirtualMemory(NtCurrentProcess(),
2353                                       Teb->NtTib.StackLimit,
2354                                       MemoryBasicInformation,
2355                                       &MemoryBasicInfo,
2356                                       sizeof(MEMORY_BASIC_INFORMATION),
2357                                       NULL);
2358         if (!NT_SUCCESS(Status))
2359         {
2360             /* Fail */
2361             LdrpInitFailure(Status);
2362             RtlRaiseStatus(Status);
2363             return;
2364         }
2365 
2366         /* Set the stack */
2367         Teb->DeallocationStack = MemoryBasicInfo.AllocationBase;
2368     }
2369 
2370     /* Now check if the process is already being initialized */
2371     while (_InterlockedCompareExchange(&LdrpProcessInitialized,
2372                                       1,
2373                                       0) == 1)
2374     {
2375         /* Set the timeout to 30 milliseconds */
2376         Timeout.QuadPart = Int32x32To64(30, -10000);
2377 
2378         /* Make sure the status hasn't changed */
2379         while (LdrpProcessInitialized == 1)
2380         {
2381             /* Do the wait */
2382             ZwDelayExecution(FALSE, &Timeout);
2383         }
2384     }
2385 
2386     /* Check if we have already setup LDR data */
2387     if (!Peb->Ldr)
2388     {
2389         /* Setup the Loader Lock */
2390         Peb->LoaderLock = &LdrpLoaderLock;
2391 
2392         /* Let other code know we're initializing */
2393         LdrpInLdrInit = TRUE;
2394 
2395         /* Protect with SEH */
2396         _SEH2_TRY
2397         {
2398             /* Initialize the Process */
2399             LoaderStatus = LdrpInitializeProcess(Context,
2400                                                  SystemArgument1);
2401 
2402             /* Check for success and if MinimumStackCommit was requested */
2403             if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit)
2404             {
2405                 /* Enforce the limit */
2406                 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2407                 UNIMPLEMENTED;
2408             }
2409         }
2410         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2411         {
2412             /* Fail with the SEH error */
2413             LoaderStatus = _SEH2_GetExceptionCode();
2414         }
2415         _SEH2_END;
2416 
2417         /* We're not initializing anymore */
2418         LdrpInLdrInit = FALSE;
2419 
2420         /* Check if init worked */
2421         if (NT_SUCCESS(LoaderStatus))
2422         {
2423             /* Set the process as Initialized */
2424             _InterlockedIncrement(&LdrpProcessInitialized);
2425         }
2426     }
2427     else
2428     {
2429         /* Loader data is there... is this a fork() ? */
2430         if(Peb->InheritedAddressSpace)
2431         {
2432             /* Handle the fork() */
2433             //LoaderStatus = LdrpForkProcess();
2434             LoaderStatus = STATUS_NOT_IMPLEMENTED;
2435             UNIMPLEMENTED;
2436         }
2437         else
2438         {
2439             /* This is a new thread initializing */
2440             LdrpInitializeThread(Context);
2441         }
2442     }
2443 
2444     /* All done, test alert the thread */
2445     NtTestAlert();
2446 
2447     /* Return */
2448     if (!NT_SUCCESS(LoaderStatus))
2449     {
2450         /* Fail */
2451         LdrpInitFailure(LoaderStatus);
2452         RtlRaiseStatus(LoaderStatus);
2453     }
2454 }
2455 
2456 /* EOF */
2457