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