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