xref: /reactos/dll/ntdll/ldr/ldrinit.c (revision 1b3eed58)
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 extern 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 RtlpInitDeferredCriticalSection(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 BOOLEAN
1541 NTAPI
1542 LdrpDisableProcessCompatGuidDetection(VOID)
1543 {
1544     UNICODE_STRING PolicyKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\Software\\Policies\\Microsoft\\Windows\\AppCompat");
1545     UNICODE_STRING DisableDetection = RTL_CONSTANT_STRING(L"DisableCompatGuidDetection");
1546     OBJECT_ATTRIBUTES PolicyKeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&PolicyKey, OBJ_CASE_INSENSITIVE);
1547     KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
1548     ULONG ResultLength;
1549     NTSTATUS Status;
1550     HANDLE KeyHandle;
1551 
1552     Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &PolicyKeyAttributes);
1553     if (NT_SUCCESS(Status))
1554     {
1555         Status = NtQueryValueKey(KeyHandle,
1556                                  &DisableDetection,
1557                                  KeyValuePartialInformation,
1558                                  &KeyInfo,
1559                                  sizeof(KeyInfo),
1560                                  &ResultLength);
1561         NtClose(KeyHandle);
1562         if ((NT_SUCCESS(Status)) &&
1563             (KeyInfo.Type == REG_DWORD) &&
1564             (KeyInfo.DataLength == sizeof(ULONG)) &&
1565             (KeyInfo.Data[0] == TRUE))
1566         {
1567             return TRUE;
1568         }
1569     }
1570     return FALSE;
1571 }
1572 
1573 
1574 VOID
1575 NTAPI
1576 LdrpInitializeProcessCompat(PVOID pProcessActctx, PVOID* pOldShimData)
1577 {
1578     static const struct
1579     {
1580         const GUID* Guid;
1581         const DWORD Version;
1582     } KnownCompatGuids[] = {
1583         { &COMPAT_GUID_WIN10, _WIN32_WINNT_WIN10 },
1584         { &COMPAT_GUID_WIN81, _WIN32_WINNT_WINBLUE },
1585         { &COMPAT_GUID_WIN8, _WIN32_WINNT_WIN8 },
1586         { &COMPAT_GUID_WIN7, _WIN32_WINNT_WIN7 },
1587         { &COMPAT_GUID_VISTA, _WIN32_WINNT_VISTA },
1588     };
1589 
1590     ULONG Buffer[(sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * 10 + sizeof(ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION)) / sizeof(ULONG)];
1591     ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION* ContextCompatInfo;
1592     SIZE_T SizeRequired;
1593     NTSTATUS Status;
1594     DWORD n, cur;
1595     ReactOS_ShimData* pShimData = *pOldShimData;
1596 
1597     if (pShimData)
1598     {
1599         if (pShimData->dwMagic != REACTOS_SHIMDATA_MAGIC ||
1600             pShimData->dwSize != sizeof(ReactOS_ShimData))
1601         {
1602             DPRINT1("LdrpInitializeProcessCompat: Corrupt pShimData (0x%x, %u)\n", pShimData->dwMagic, pShimData->dwSize);
1603             return;
1604         }
1605         if (pShimData->dwRosProcessCompatVersion)
1606         {
1607             if (pShimData->dwRosProcessCompatVersion == REACTOS_COMPATVERSION_IGNOREMANIFEST)
1608             {
1609                 DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion set to ignore manifest\n");
1610             }
1611             else
1612             {
1613                 DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion already set to 0x%x\n", pShimData->dwRosProcessCompatVersion);
1614             }
1615             return;
1616         }
1617     }
1618 
1619     SizeRequired = sizeof(Buffer);
1620     Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF,
1621                                                   pProcessActctx,
1622                                                   NULL,
1623                                                   CompatibilityInformationInActivationContext,
1624                                                   Buffer,
1625                                                   sizeof(Buffer),
1626                                                   &SizeRequired);
1627 
1628     if (!NT_SUCCESS(Status))
1629     {
1630         DPRINT1("LdrpInitializeProcessCompat: Unable to query process actctx with status %x\n", Status);
1631         return;
1632     }
1633 
1634     ContextCompatInfo = (ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*)Buffer;
1635     /* No Compatibility elements present, bail out */
1636     if (ContextCompatInfo->ElementCount == 0)
1637         return;
1638 
1639     /* Search for known GUIDs, starting from oldest to newest.
1640        Note that on Windows it is somewhat reversed, starting from the latest known
1641        version, going down. But we are not Windows, trying to allow a lower version,
1642        we are ReactOS trying to fake a higher version. So we interpret what Windows
1643        does as "try the closest version to the actual version", so we start with the
1644        lowest version, which is closest to Windows 2003, which we mostly are. */
1645     for (cur = RTL_NUMBER_OF(KnownCompatGuids) - 1; cur != -1; --cur)
1646     {
1647         for (n = 0; n < ContextCompatInfo->ElementCount; ++n)
1648         {
1649             if (ContextCompatInfo->Elements[n].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS &&
1650                 RtlCompareMemory(&ContextCompatInfo->Elements[n].Id, KnownCompatGuids[cur].Guid, sizeof(GUID)) == sizeof(GUID))
1651             {
1652                 if (LdrpDisableProcessCompatGuidDetection())
1653                 {
1654                     DPRINT1("LdrpInitializeProcessCompat: Not applying automatic fix for winver 0x%x due to policy\n", KnownCompatGuids[cur].Version);
1655                     return;
1656                 }
1657 
1658                 /* If this process did not need shim data before, allocate and store it */
1659                 if (pShimData == NULL)
1660                 {
1661                     PPEB Peb = NtCurrentPeb();
1662 
1663                     ASSERT(Peb->pShimData == NULL);
1664                     pShimData = RtlAllocateHeap(Peb->ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*pShimData));
1665 
1666                     if (!pShimData)
1667                     {
1668                         DPRINT1("LdrpInitializeProcessCompat: Unable to allocated %u bytes\n", sizeof(*pShimData));
1669                         return;
1670                     }
1671 
1672                     pShimData->dwSize = sizeof(*pShimData);
1673                     pShimData->dwMagic = REACTOS_SHIMDATA_MAGIC;
1674 
1675                     Peb->pShimData = pShimData;
1676                     *pOldShimData = pShimData;
1677                 }
1678 
1679                 /* Store the lowest found version, and bail out. */
1680                 pShimData->dwRosProcessCompatVersion = KnownCompatGuids[cur].Version;
1681                 DPRINT1("LdrpInitializeProcessCompat: Found guid for winver 0x%x in manifest from %wZ\n",
1682                         KnownCompatGuids[cur].Version,
1683                         &(NtCurrentPeb()->ProcessParameters->ImagePathName));
1684                 return;
1685             }
1686         }
1687     }
1688 }
1689 
1690 VOID
1691 NTAPI
1692 LdrpInitializeDotLocalSupport(PRTL_USER_PROCESS_PARAMETERS ProcessParameters)
1693 {
1694     UNICODE_STRING ImagePathName = ProcessParameters->ImagePathName;
1695     WCHAR LocalBuffer[MAX_PATH];
1696     UNICODE_STRING DotLocal;
1697     NTSTATUS Status;
1698     ULONG RequiredSize;
1699 
1700     RequiredSize = ImagePathName.Length + LdrpDotLocal.Length + sizeof(UNICODE_NULL);
1701     if (RequiredSize <= sizeof(LocalBuffer))
1702     {
1703         RtlInitEmptyUnicodeString(&DotLocal, LocalBuffer, sizeof(LocalBuffer));
1704     }
1705     else if (RequiredSize <= UNICODE_STRING_MAX_BYTES)
1706     {
1707         DotLocal.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, RequiredSize);
1708         DotLocal.Length = 0;
1709         DotLocal.MaximumLength = RequiredSize;
1710         if (!DotLocal.Buffer)
1711             DPRINT1("LDR: Failed to allocate memory for .local check\n");
1712     }
1713     else
1714     {
1715         DotLocal.Buffer = NULL;
1716         DotLocal.Length = 0;
1717         DotLocal.MaximumLength = 0;
1718         DPRINT1("LDR: String too big for .local check\n");
1719     }
1720 
1721     if (DotLocal.Buffer)
1722     {
1723         Status = RtlAppendUnicodeStringToString(&DotLocal, &ImagePathName);
1724         ASSERT(NT_SUCCESS(Status));
1725         if (NT_SUCCESS(Status))
1726         {
1727             Status = RtlAppendUnicodeStringToString(&DotLocal, &LdrpDotLocal);
1728             ASSERT(NT_SUCCESS(Status));
1729         }
1730 
1731         if (NT_SUCCESS(Status))
1732         {
1733             if (RtlDoesFileExists_UStr(&DotLocal))
1734             {
1735                 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_PRIVATE_DLL_PATH;
1736             }
1737         }
1738         else
1739         {
1740             DPRINT1("LDR: Failed to append: 0x%lx\n", Status);
1741         }
1742 
1743         if (DotLocal.Buffer != LocalBuffer)
1744         {
1745             RtlFreeHeap(RtlGetProcessHeap(), 0, DotLocal.Buffer);
1746         }
1747     }
1748 }
1749 
1750 
1751 NTSTATUS
1752 NTAPI
1753 LdrpInitializeProcess(IN PCONTEXT Context,
1754                       IN PVOID SystemArgument1)
1755 {
1756     RTL_HEAP_PARAMETERS HeapParameters;
1757     ULONG ComSectionSize;
1758     ANSI_STRING BaseProcessInitPostImportName = RTL_CONSTANT_STRING("BaseProcessInitPostImport");
1759     ANSI_STRING BaseQueryModuleDataName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1760     PVOID OldShimData;
1761     OBJECT_ATTRIBUTES ObjectAttributes;
1762     //UNICODE_STRING LocalFileName, FullImageName;
1763     HANDLE SymLinkHandle;
1764     //ULONG DebugHeapOnly;
1765     UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
1766     PPEB Peb = NtCurrentPeb();
1767     BOOLEAN IsDotNetImage = FALSE;
1768     BOOLEAN FreeCurDir = FALSE;
1769     //HANDLE CompatKey;
1770     PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
1771     //LPWSTR ImagePathBuffer;
1772     ULONG ConfigSize;
1773     UNICODE_STRING CurrentDirectory;
1774     HANDLE OptionsKey;
1775     ULONG HeapFlags;
1776     PIMAGE_NT_HEADERS NtHeader;
1777     LPWSTR NtDllName = NULL;
1778     NTSTATUS Status, ImportStatus;
1779     NLSTABLEINFO NlsTable;
1780     PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
1781     PTEB Teb = NtCurrentTeb();
1782     PLIST_ENTRY ListHead;
1783     PLIST_ENTRY NextEntry;
1784     ULONG i;
1785     PWSTR ImagePath;
1786     ULONG DebugProcessHeapOnly = 0;
1787     PLDR_DATA_TABLE_ENTRY NtLdrEntry;
1788     PWCHAR Current;
1789     ULONG ExecuteOptions = 0;
1790     PVOID ViewBase;
1791 
1792     /* Set a NULL SEH Filter */
1793     RtlSetUnhandledExceptionFilter(NULL);
1794 
1795     /* Get the image path */
1796     ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
1797 
1798     /* Check if it's not normalized */
1799     if (!(Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED))
1800     {
1801         /* Normalize it*/
1802         ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
1803     }
1804 
1805     /* Create a unicode string for the Image Path */
1806     ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
1807     ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
1808     ImagePathName.Buffer = ImagePath;
1809 
1810     /* Get the NT Headers */
1811     NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
1812 
1813     /* Get the execution options */
1814     Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &OptionsKey);
1815 
1816     /* Check if this is a .NET executable */
1817     if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1818                                      TRUE,
1819                                      IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
1820                                      &ComSectionSize))
1821     {
1822         /* Remember this for later */
1823         IsDotNetImage = TRUE;
1824     }
1825 
1826     /* Save the NTDLL Base address */
1827     NtDllBase = SystemArgument1;
1828 
1829     /* If this is a Native Image */
1830     if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
1831     {
1832         /* Then do DLL Validation */
1833         LdrpDllValidation = TRUE;
1834     }
1835 
1836     /* Save the old Shim Data */
1837     OldShimData = Peb->pShimData;
1838 
1839     /* ReactOS specific: do not clear it. (Windows starts doing the same in later versions) */
1840     //Peb->pShimData = NULL;
1841 
1842     /* Save the number of processors and CS timeout */
1843     LdrpNumberOfProcessors = Peb->NumberOfProcessors;
1844     RtlpTimeout = Peb->CriticalSectionTimeout;
1845 
1846     /* Normalize the parameters */
1847     ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
1848     if (ProcessParameters)
1849     {
1850         /* Save the Image and Command Line Names */
1851         ImageFileName = ProcessParameters->ImagePathName;
1852         CommandLine = ProcessParameters->CommandLine;
1853     }
1854     else
1855     {
1856         /* It failed, initialize empty strings */
1857         RtlInitUnicodeString(&ImageFileName, NULL);
1858         RtlInitUnicodeString(&CommandLine, NULL);
1859     }
1860 
1861     /* Initialize NLS data */
1862     RtlInitNlsTables(Peb->AnsiCodePageData,
1863                      Peb->OemCodePageData,
1864                      Peb->UnicodeCaseTableData,
1865                      &NlsTable);
1866 
1867     /* Reset NLS Translations */
1868     RtlResetRtlTranslations(&NlsTable);
1869 
1870     /* Get the Image Config Directory */
1871     LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1872                                               TRUE,
1873                                               IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
1874                                               &ConfigSize);
1875 
1876     /* Setup the Heap Parameters */
1877     RtlZeroMemory(&HeapParameters, sizeof(HeapParameters));
1878     HeapFlags = HEAP_GROWABLE;
1879     HeapParameters.Length = sizeof(HeapParameters);
1880 
1881     /* Check if we have Configuration Data */
1882 #define VALID_CONFIG_FIELD(Name) (ConfigSize >= (FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, Name) + sizeof(LoadConfig->Name)))
1883     /* The 'original' load config ends after SecurityCookie */
1884     if ((LoadConfig) && ConfigSize && (VALID_CONFIG_FIELD(SecurityCookie) || ConfigSize == LoadConfig->Size))
1885     {
1886         if (ConfigSize != sizeof(IMAGE_LOAD_CONFIG_DIRECTORY))
1887             DPRINT1("WARN: Accepting different LOAD_CONFIG size!\n");
1888         else
1889             DPRINT1("Applying LOAD_CONFIG\n");
1890 
1891         if (VALID_CONFIG_FIELD(GlobalFlagsSet) && LoadConfig->GlobalFlagsSet)
1892             Peb->NtGlobalFlag |= LoadConfig->GlobalFlagsSet;
1893 
1894         if (VALID_CONFIG_FIELD(GlobalFlagsClear) && LoadConfig->GlobalFlagsClear)
1895             Peb->NtGlobalFlag &= ~LoadConfig->GlobalFlagsClear;
1896 
1897         /* Convert the default CS timeout from milliseconds to 100ns units */
1898         if (VALID_CONFIG_FIELD(CriticalSectionDefaultTimeout) && LoadConfig->CriticalSectionDefaultTimeout)
1899             RtlpTimeout.QuadPart = Int32x32To64(LoadConfig->CriticalSectionDefaultTimeout, -10000);
1900 
1901         if (VALID_CONFIG_FIELD(DeCommitFreeBlockThreshold) && LoadConfig->DeCommitFreeBlockThreshold)
1902             HeapParameters.DeCommitFreeBlockThreshold = LoadConfig->DeCommitFreeBlockThreshold;
1903 
1904         if (VALID_CONFIG_FIELD(DeCommitTotalFreeThreshold) && LoadConfig->DeCommitTotalFreeThreshold)
1905             HeapParameters.DeCommitTotalFreeThreshold = LoadConfig->DeCommitTotalFreeThreshold;
1906 
1907         if (VALID_CONFIG_FIELD(MaximumAllocationSize) && LoadConfig->MaximumAllocationSize)
1908             HeapParameters.MaximumAllocationSize = LoadConfig->MaximumAllocationSize;
1909 
1910         if (VALID_CONFIG_FIELD(VirtualMemoryThreshold) && LoadConfig->VirtualMemoryThreshold)
1911             HeapParameters.VirtualMemoryThreshold = LoadConfig->VirtualMemoryThreshold;
1912 
1913         if (VALID_CONFIG_FIELD(ProcessHeapFlags) && LoadConfig->ProcessHeapFlags)
1914             HeapFlags = LoadConfig->ProcessHeapFlags;
1915     }
1916 #undef VALID_CONFIG_FIELD
1917 
1918     /* Check for custom affinity mask */
1919     if (Peb->ImageProcessAffinityMask)
1920     {
1921         /* Set it */
1922         Status = NtSetInformationProcess(NtCurrentProcess(),
1923                                          ProcessAffinityMask,
1924                                          &Peb->ImageProcessAffinityMask,
1925                                          sizeof(Peb->ImageProcessAffinityMask));
1926     }
1927 
1928     /* Check if verbose debugging (ShowSnaps) was requested */
1929     ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1930 
1931     /* Start verbose debugging messages right now if they were requested */
1932     if (ShowSnaps)
1933     {
1934         DPRINT1("LDR: PID: 0x%p started - '%wZ'\n",
1935                 Teb->ClientId.UniqueProcess,
1936                 &CommandLine);
1937     }
1938 
1939     /* If the CS timeout is longer than 1 hour, disable it */
1940     if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
1941         RtlpTimeoutDisable = TRUE;
1942 
1943     /* Initialize Critical Section Data */
1944     RtlpInitDeferredCriticalSection();
1945 
1946     /* Initialize VEH Call lists */
1947     RtlpInitializeVectoredExceptionHandling();
1948 
1949     /* Set TLS/FLS Bitmap data */
1950     Peb->FlsBitmap = &FlsBitMap;
1951     Peb->TlsBitmap = &TlsBitMap;
1952     Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
1953 
1954     /* Initialize FLS Bitmap */
1955     RtlInitializeBitMap(&FlsBitMap,
1956                         Peb->FlsBitmapBits,
1957                         FLS_MAXIMUM_AVAILABLE);
1958     RtlSetBit(&FlsBitMap, 0);
1959     InitializeListHead(&Peb->FlsListHead);
1960 
1961     /* Initialize TLS Bitmap */
1962     RtlInitializeBitMap(&TlsBitMap,
1963                         Peb->TlsBitmapBits,
1964                         TLS_MINIMUM_AVAILABLE);
1965     RtlSetBit(&TlsBitMap, 0);
1966     RtlInitializeBitMap(&TlsExpansionBitMap,
1967                         Peb->TlsExpansionBitmapBits,
1968                         TLS_EXPANSION_SLOTS);
1969     RtlSetBit(&TlsExpansionBitMap, 0);
1970 
1971     /* Initialize the Hash Table */
1972     for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
1973     {
1974         InitializeListHead(&LdrpHashTable[i]);
1975     }
1976 
1977     /* Initialize the Loader Lock */
1978     // FIXME: What's the point of initing it manually, if two lines lower
1979     //        a call to RtlInitializeCriticalSection() is being made anyway?
1980     //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1981     //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1982     RtlInitializeCriticalSection(&LdrpLoaderLock);
1983     LdrpLoaderLockInit = TRUE;
1984 
1985     /* Check if User Stack Trace Database support was requested */
1986     if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
1987     {
1988         DPRINT1("We don't support user stack trace databases yet\n");
1989     }
1990 
1991     /* Setup Fast PEB Lock */
1992     RtlInitializeCriticalSection(&FastPebLock);
1993     Peb->FastPebLock = &FastPebLock;
1994     //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1995     //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1996 
1997     /* Setup Callout Lock and Notification list */
1998     //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1999     InitializeListHead(&LdrpDllNotificationList);
2000 
2001     /* For old executables, use 16-byte aligned heap */
2002     if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
2003         (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
2004     {
2005         HeapFlags |= HEAP_CREATE_ALIGN_16;
2006     }
2007 
2008     /* Setup the Heap */
2009     RtlInitializeHeapManager();
2010     Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
2011                                      NULL,
2012                                      NtHeader->OptionalHeader.SizeOfHeapReserve,
2013                                      NtHeader->OptionalHeader.SizeOfHeapCommit,
2014                                      NULL,
2015                                      &HeapParameters);
2016 
2017     if (!Peb->ProcessHeap)
2018     {
2019         DPRINT1("Failed to create process heap\n");
2020         return STATUS_NO_MEMORY;
2021     }
2022 
2023     /* Allocate an Activation Context Stack */
2024     Status = RtlAllocateActivationContextStack(&Teb->ActivationContextStackPointer);
2025     if (!NT_SUCCESS(Status)) return Status;
2026 
2027     RtlZeroMemory(&HeapParameters, sizeof(HeapParameters));
2028     HeapFlags = HEAP_GROWABLE | HEAP_CLASS_1;
2029     HeapParameters.Length = sizeof(HeapParameters);
2030     LdrpHeap = RtlCreateHeap(HeapFlags, 0, 0x10000, 0x6000, 0, &HeapParameters);
2031     if (!LdrpHeap)
2032     {
2033         DPRINT1("Failed to create loader private heap\n");
2034         return STATUS_NO_MEMORY;
2035     }
2036 
2037     /* Check for Debug Heap */
2038     if (OptionsKey)
2039     {
2040         /* Query the setting */
2041         Status = LdrQueryImageFileKeyOption(OptionsKey,
2042                                             L"DebugProcessHeapOnly",
2043                                             REG_DWORD,
2044                                             &DebugProcessHeapOnly,
2045                                             sizeof(ULONG),
2046                                             NULL);
2047 
2048         if (NT_SUCCESS(Status))
2049         {
2050             /* Reset DPH if requested */
2051             if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
2052             {
2053                 RtlpDphGlobalFlags &= ~DPH_FLAG_DLL_NOTIFY;
2054                 RtlpPageHeapEnabled = FALSE;
2055             }
2056         }
2057     }
2058 
2059     /* Build the NTDLL Path */
2060     FullPath.Buffer = StringBuffer;
2061     FullPath.Length = 0;
2062     FullPath.MaximumLength = sizeof(StringBuffer);
2063     RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
2064     RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
2065     RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
2066 
2067     /* Open the Known DLLs directory */
2068     RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
2069     InitializeObjectAttributes(&ObjectAttributes,
2070                                &KnownDllString,
2071                                OBJ_CASE_INSENSITIVE,
2072                                NULL,
2073                                NULL);
2074     Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
2075                                    DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
2076                                    &ObjectAttributes);
2077 
2078     /* Check if it exists */
2079     if (NT_SUCCESS(Status))
2080     {
2081         /* Open the Known DLLs Path */
2082         RtlInitUnicodeString(&KnownDllString, L"KnownDllPath");
2083         InitializeObjectAttributes(&ObjectAttributes,
2084                                    &KnownDllString,
2085                                    OBJ_CASE_INSENSITIVE,
2086                                    LdrpKnownDllObjectDirectory,
2087                                    NULL);
2088         Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
2089                                           SYMBOLIC_LINK_QUERY,
2090                                           &ObjectAttributes);
2091         if (NT_SUCCESS(Status))
2092         {
2093             /* Query the path */
2094             LdrpKnownDllPath.Length = 0;
2095             LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
2096             LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
2097             Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
2098             NtClose(SymLinkHandle);
2099             if (!NT_SUCCESS(Status))
2100             {
2101                 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
2102                 return Status;
2103             }
2104         }
2105     }
2106 
2107     /* Check if we failed */
2108     if (!NT_SUCCESS(Status))
2109     {
2110         /* Assume System32 */
2111         LdrpKnownDllObjectDirectory = NULL;
2112         RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer);
2113         LdrpKnownDllPath.Length -= sizeof(WCHAR);
2114     }
2115 
2116     /* If we have process parameters, get the default path and current path */
2117     if (ProcessParameters)
2118     {
2119         /* Check if we have a Dll Path */
2120         if (ProcessParameters->DllPath.Length)
2121         {
2122             /* Get the path */
2123             LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
2124         }
2125         else
2126         {
2127             /* We need a valid path */
2128             DPRINT1("No valid DllPath was given!\n");
2129             LdrpInitFailure(STATUS_INVALID_PARAMETER);
2130         }
2131 
2132         /* Set the current directory */
2133         CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
2134 
2135         /* Check if it's empty or invalid */
2136         if ((!CurrentDirectory.Buffer) ||
2137             (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
2138             (!CurrentDirectory.Length))
2139         {
2140             /* Allocate space for the buffer */
2141             CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
2142                                                       0,
2143                                                       3 * sizeof(WCHAR) +
2144                                                       sizeof(UNICODE_NULL));
2145             if (!CurrentDirectory.Buffer)
2146             {
2147                 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
2148                 // FIXME: And what?
2149             }
2150 
2151             /* Copy the drive of the system root */
2152             RtlMoveMemory(CurrentDirectory.Buffer,
2153                           SharedUserData->NtSystemRoot,
2154                           3 * sizeof(WCHAR));
2155             CurrentDirectory.Buffer[3] = UNICODE_NULL;
2156             CurrentDirectory.Length = 3 * sizeof(WCHAR);
2157             CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
2158 
2159             FreeCurDir = TRUE;
2160             DPRINT("Using dynamically allocd curdir\n");
2161         }
2162         else
2163         {
2164             /* Use the local buffer */
2165             DPRINT("Using local system root\n");
2166         }
2167     }
2168 
2169     /* Setup Loader Data */
2170     Peb->Ldr = &PebLdr;
2171     InitializeListHead(&PebLdr.InLoadOrderModuleList);
2172     InitializeListHead(&PebLdr.InMemoryOrderModuleList);
2173     InitializeListHead(&PebLdr.InInitializationOrderModuleList);
2174     PebLdr.Length = sizeof(PEB_LDR_DATA);
2175     PebLdr.Initialized = TRUE;
2176 
2177     /* Allocate a data entry for the Image */
2178     LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
2179 
2180     /* Set it up */
2181     LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrpImageEntry->DllBase);
2182     LdrpImageEntry->LoadCount = -1;
2183     LdrpImageEntry->EntryPointActivationContext = 0;
2184     LdrpImageEntry->FullDllName = ImageFileName;
2185 
2186     if (IsDotNetImage)
2187         LdrpImageEntry->Flags = LDRP_COR_IMAGE;
2188     else
2189         LdrpImageEntry->Flags = 0;
2190 
2191     /* Check if the name is empty */
2192     if (!ImageFileName.Buffer[0])
2193     {
2194         /* Use the same Base name */
2195         LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2196     }
2197     else
2198     {
2199         /* Find the last slash */
2200         Current = ImageFileName.Buffer;
2201         while (*Current)
2202         {
2203             if (*Current++ == '\\')
2204             {
2205                 /* Set this path */
2206                 NtDllName = Current;
2207             }
2208         }
2209 
2210         /* Did we find anything? */
2211         if (!NtDllName)
2212         {
2213             /* Use the same Base name */
2214             LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2215         }
2216         else
2217         {
2218             /* Setup the name */
2219             LdrpImageEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
2220             LdrpImageEntry->BaseDllName.MaximumLength = LdrpImageEntry->BaseDllName.Length + sizeof(WCHAR);
2221             LdrpImageEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
2222                                                      (ImageFileName.Length - LdrpImageEntry->BaseDllName.Length));
2223         }
2224     }
2225 
2226     /* Processing done, insert it */
2227     LdrpInsertMemoryTableEntry(LdrpImageEntry);
2228     LdrpImageEntry->Flags |= LDRP_ENTRY_PROCESSED;
2229 
2230     /* Now add an entry for NTDLL */
2231     NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
2232     NtLdrEntry->Flags = LDRP_IMAGE_DLL;
2233     NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
2234     NtLdrEntry->LoadCount = -1;
2235     NtLdrEntry->EntryPointActivationContext = 0;
2236 
2237     NtLdrEntry->FullDllName.Length = FullPath.Length;
2238     NtLdrEntry->FullDllName.MaximumLength = FullPath.MaximumLength;
2239     NtLdrEntry->FullDllName.Buffer = StringBuffer;
2240     RtlAppendUnicodeStringToString(&NtLdrEntry->FullDllName, &NtDllString);
2241 
2242     NtLdrEntry->BaseDllName.Length = NtDllString.Length;
2243     NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength;
2244     NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer;
2245 
2246     /* Processing done, insert it */
2247     LdrpNtDllDataTableEntry = NtLdrEntry;
2248     LdrpInsertMemoryTableEntry(NtLdrEntry);
2249 
2250     /* Let the world know */
2251     if (ShowSnaps)
2252     {
2253         DPRINT1("LDR: NEW PROCESS\n");
2254         DPRINT1("     Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
2255         DPRINT1("     Current Directory: %wZ\n", &CurrentDirectory);
2256         DPRINT1("     Search Path: %wZ\n", &LdrpDefaultPath);
2257     }
2258 
2259     /* Link the Init Order List */
2260     InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
2261                    &LdrpNtDllDataTableEntry->InInitializationOrderLinks);
2262 
2263     /* Initialize Wine's active context implementation for the current process */
2264     actctx_init(&OldShimData);
2265 
2266     /* Set the current directory */
2267     Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
2268     if (!NT_SUCCESS(Status))
2269     {
2270         /* We failed, check if we should free it */
2271         if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2272 
2273         /* Set it to the NT Root */
2274         CurrentDirectory = NtSystemRoot;
2275         RtlSetCurrentDirectory_U(&CurrentDirectory);
2276     }
2277     else
2278     {
2279         /* We're done with it, free it */
2280         if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2281     }
2282 
2283     /* Check if we should look for a .local file */
2284     if (ProcessParameters && !(ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH))
2285     {
2286         LdrpInitializeDotLocalSupport(ProcessParameters);
2287     }
2288 
2289     /* Check if the Application Verifier was enabled */
2290     if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
2291     {
2292         Status = AVrfInitializeVerifier();
2293         if (!NT_SUCCESS(Status))
2294         {
2295             DPRINT1("LDR: AVrfInitializeVerifier failed (ntstatus 0x%x)\n", Status);
2296             return Status;
2297         }
2298 
2299     }
2300 
2301     if (IsDotNetImage)
2302     {
2303         /* FIXME */
2304         DPRINT1("We don't support .NET applications yet\n");
2305     }
2306 
2307     if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ||
2308         NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
2309     {
2310         PVOID Kernel32BaseAddress;
2311         PVOID FunctionAddress;
2312 
2313         Status = LdrLoadDll(NULL, NULL, &Kernel32String, &Kernel32BaseAddress);
2314 
2315         if (!NT_SUCCESS(Status))
2316         {
2317             if (ShowSnaps)
2318                 DPRINT1("LDR: Unable to load %wZ, Status=0x%08lx\n", &Kernel32String, Status);
2319             return Status;
2320         }
2321 
2322         Status = LdrGetProcedureAddress(Kernel32BaseAddress,
2323                                         &BaseProcessInitPostImportName,
2324                                         0,
2325                                         &FunctionAddress);
2326 
2327         if (!NT_SUCCESS(Status))
2328         {
2329             if (ShowSnaps)
2330                 DPRINT1("LDR: Unable to find post-import process init function, Status=0x%08lx\n", &Kernel32String, Status);
2331             return Status;
2332         }
2333         Kernel32ProcessInitPostImportFunction = FunctionAddress;
2334 
2335         Status = LdrGetProcedureAddress(Kernel32BaseAddress,
2336                                         &BaseQueryModuleDataName,
2337                                         0,
2338                                         &FunctionAddress);
2339 
2340         if (!NT_SUCCESS(Status))
2341         {
2342             if (ShowSnaps)
2343                 DPRINT1("LDR: Unable to find BaseQueryModuleData, Status=0x%08lx\n", &Kernel32String, Status);
2344             return Status;
2345         }
2346         Kernel32BaseQueryModuleData = FunctionAddress;
2347     }
2348 
2349     /* Walk the IAT and load all the DLLs */
2350     ImportStatus = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
2351 
2352     /* Check if relocation is needed */
2353     if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
2354     {
2355         DPRINT1("LDR: Performing EXE relocation\n");
2356 
2357         /* Change the protection to prepare for relocation */
2358         ViewBase = Peb->ImageBaseAddress;
2359         Status = LdrpSetProtection(ViewBase, FALSE);
2360         if (!NT_SUCCESS(Status)) return Status;
2361 
2362         /* Do the relocation */
2363         Status = LdrRelocateImageWithBias(ViewBase,
2364                                           0LL,
2365                                           NULL,
2366                                           STATUS_SUCCESS,
2367                                           STATUS_CONFLICTING_ADDRESSES,
2368                                           STATUS_INVALID_IMAGE_FORMAT);
2369         if (!NT_SUCCESS(Status))
2370         {
2371             DPRINT1("LdrRelocateImageWithBias() failed\n");
2372             return Status;
2373         }
2374 
2375         /* Check if a start context was provided */
2376         if (Context)
2377         {
2378             DPRINT1("WARNING: Relocated EXE Context");
2379             UNIMPLEMENTED; // We should support this
2380             return STATUS_INVALID_IMAGE_FORMAT;
2381         }
2382 
2383         /* Restore the protection */
2384         Status = LdrpSetProtection(ViewBase, TRUE);
2385         if (!NT_SUCCESS(Status)) return Status;
2386     }
2387 
2388     /* Lock the DLLs */
2389     ListHead = &Peb->Ldr->InLoadOrderModuleList;
2390     NextEntry = ListHead->Flink;
2391     while (ListHead != NextEntry)
2392     {
2393         NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2394         NtLdrEntry->LoadCount = -1;
2395         NextEntry = NextEntry->Flink;
2396     }
2397 
2398     /* Phase 0 is done */
2399     LdrpLdrDatabaseIsSetup = TRUE;
2400 
2401     /* Check whether all static imports were properly loaded and return here */
2402     if (!NT_SUCCESS(ImportStatus)) return ImportStatus;
2403 
2404     /* Initialize TLS */
2405     Status = LdrpInitializeTls();
2406     if (!NT_SUCCESS(Status))
2407     {
2408         DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2409                 Status);
2410         return Status;
2411     }
2412 
2413     /* FIXME Mark the DLL Ranges for Stack Traces later */
2414 
2415     /* Notify the debugger now */
2416     if (Peb->BeingDebugged)
2417     {
2418         /* Break */
2419         DbgBreakPoint();
2420 
2421         /* Update show snaps again */
2422         ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
2423     }
2424 
2425     /* Validate the Image for MP Usage */
2426     if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
2427 
2428     /* Check NX options and set them */
2429     if (SharedUserData->NXSupportPolicy == NX_SUPPORT_POLICY_ALWAYSON)
2430     {
2431         ExecuteOptions = MEM_EXECUTE_OPTION_DISABLE |
2432                          MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION |
2433                          MEM_EXECUTE_OPTION_PERMANENT;
2434     }
2435     else if (SharedUserData->NXSupportPolicy == NX_SUPPORT_POLICY_ALWAYSOFF)
2436     {
2437         ExecuteOptions = MEM_EXECUTE_OPTION_ENABLE | MEM_EXECUTE_OPTION_PERMANENT;
2438     }
2439     Status = NtSetInformationProcess(NtCurrentProcess(),
2440                                      ProcessExecuteFlags,
2441                                      &ExecuteOptions,
2442                                      sizeof(ExecuteOptions));
2443     if (!NT_SUCCESS(Status))
2444     {
2445         DPRINT1("LDR: Could not set process execute flags 0x%x; status %x\n",
2446                 ExecuteOptions, Status);
2447     }
2448 
2449     // FIXME: Should be done by Application Compatibility features,
2450     // by reading the registry, etc...
2451     // For now, this is the old code from ntdll!RtlGetVersion().
2452     RtlInitEmptyUnicodeString(&Peb->CSDVersion, NULL, 0);
2453     if (((Peb->OSCSDVersion >> 8) & 0xFF) != 0)
2454     {
2455         WCHAR szCSDVersion[128];
2456         LONG i;
2457         USHORT Length = (USHORT)ARRAYSIZE(szCSDVersion) - 1;
2458         i = _snwprintf(szCSDVersion, Length,
2459                        L"Service Pack %d",
2460                        ((Peb->OSCSDVersion >> 8) & 0xFF));
2461         if (i < 0)
2462         {
2463             /* Null-terminate if it was overflowed */
2464             szCSDVersion[Length] = UNICODE_NULL;
2465         }
2466 
2467         Length *= sizeof(WCHAR);
2468         Peb->CSDVersion.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
2469                                                  0,
2470                                                  Length + sizeof(UNICODE_NULL));
2471         if (Peb->CSDVersion.Buffer)
2472         {
2473             Peb->CSDVersion.Length = Length;
2474             Peb->CSDVersion.MaximumLength = Length + sizeof(UNICODE_NULL);
2475 
2476             RtlCopyMemory(Peb->CSDVersion.Buffer,
2477                           szCSDVersion,
2478                           Peb->CSDVersion.MaximumLength);
2479             Peb->CSDVersion.Buffer[Peb->CSDVersion.Length / sizeof(WCHAR)] = UNICODE_NULL;
2480         }
2481     }
2482 
2483     /* Check if we had Shim Data */
2484     if (OldShimData)
2485     {
2486         /* Load the Shim Engine */
2487         Peb->AppCompatInfo = NULL;
2488         LdrpLoadShimEngine(OldShimData, &ImagePathName, OldShimData);
2489     }
2490     else
2491     {
2492         /* Check for Application Compatibility Goo */
2493         //LdrQueryApplicationCompatibilityGoo(hKey);
2494         DPRINT("Querying app compat hacks is missing!\n");
2495     }
2496 
2497     /*
2498      * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2499      * incompatible images.
2500      */
2501 
2502     /* Now call the Init Routines */
2503     Status = LdrpRunInitializeRoutines(Context);
2504     if (!NT_SUCCESS(Status))
2505     {
2506         DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2507                 Status);
2508         return Status;
2509     }
2510 
2511     /* Notify Shim Engine */
2512     if (g_ShimsEnabled)
2513     {
2514         VOID(NTAPI *SE_InstallAfterInit)(PUNICODE_STRING, PVOID);
2515         SE_InstallAfterInit = RtlDecodeSystemPointer(g_pfnSE_InstallAfterInit);
2516         SE_InstallAfterInit(&ImagePathName, OldShimData);
2517     }
2518 
2519     /* Check if we have a user-defined Post Process Routine */
2520     if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
2521     {
2522         /* Call it */
2523         Peb->PostProcessInitRoutine();
2524     }
2525 
2526     /* Close the key if we have one opened */
2527     if (OptionsKey) NtClose(OptionsKey);
2528 
2529     /* Return status */
2530     return Status;
2531 }
2532 
2533 VOID
2534 NTAPI
2535 LdrpInitFailure(NTSTATUS Status)
2536 {
2537     ULONG Response;
2538     PPEB Peb = NtCurrentPeb();
2539 
2540     /* Print a debug message */
2541     DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2542             &Peb->ProcessParameters->ImagePathName, Status);
2543 
2544     /* Raise a hard error */
2545     if (!LdrpFatalHardErrorCount)
2546     {
2547         ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response);
2548     }
2549 }
2550 
2551 VOID
2552 NTAPI
2553 LdrpInit(PCONTEXT Context,
2554          PVOID SystemArgument1,
2555          PVOID SystemArgument2)
2556 {
2557     LARGE_INTEGER Timeout;
2558     PTEB Teb = NtCurrentTeb();
2559     NTSTATUS Status, LoaderStatus = STATUS_SUCCESS;
2560     MEMORY_BASIC_INFORMATION MemoryBasicInfo;
2561     PPEB Peb = NtCurrentPeb();
2562 
2563     DPRINT("LdrpInit() %p/%p\n",
2564         NtCurrentTeb()->RealClientId.UniqueProcess,
2565         NtCurrentTeb()->RealClientId.UniqueThread);
2566 
2567 #ifdef _WIN64
2568     /* Set the SList header usage */
2569     RtlpUse16ByteSLists = SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128];
2570 #endif /* _WIN64 */
2571 
2572     /* Check if we have a deallocation stack */
2573     if (!Teb->DeallocationStack)
2574     {
2575         /* We don't, set one */
2576         Status = NtQueryVirtualMemory(NtCurrentProcess(),
2577                                       Teb->NtTib.StackLimit,
2578                                       MemoryBasicInformation,
2579                                       &MemoryBasicInfo,
2580                                       sizeof(MEMORY_BASIC_INFORMATION),
2581                                       NULL);
2582         if (!NT_SUCCESS(Status))
2583         {
2584             /* Fail */
2585             LdrpInitFailure(Status);
2586             RtlRaiseStatus(Status);
2587             return;
2588         }
2589 
2590         /* Set the stack */
2591         Teb->DeallocationStack = MemoryBasicInfo.AllocationBase;
2592     }
2593 
2594     /* Now check if the process is already being initialized */
2595     while (_InterlockedCompareExchange(&LdrpProcessInitialized,
2596                                       1,
2597                                       0) == 1)
2598     {
2599         /* Set the timeout to 30 milliseconds */
2600         Timeout.QuadPart = Int32x32To64(30, -10000);
2601 
2602         /* Make sure the status hasn't changed */
2603         while (LdrpProcessInitialized == 1)
2604         {
2605             /* Do the wait */
2606             ZwDelayExecution(FALSE, &Timeout);
2607         }
2608     }
2609 
2610     /* Check if we have already setup LDR data */
2611     if (!Peb->Ldr)
2612     {
2613         /* Setup the Loader Lock */
2614         Peb->LoaderLock = &LdrpLoaderLock;
2615 
2616         /* Let other code know we're initializing */
2617         LdrpInLdrInit = TRUE;
2618 
2619         /* Protect with SEH */
2620         _SEH2_TRY
2621         {
2622             /* Initialize the Process */
2623             LoaderStatus = LdrpInitializeProcess(Context,
2624                                                  SystemArgument1);
2625 
2626             /* Check for success and if MinimumStackCommit was requested */
2627             if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit)
2628             {
2629                 /* Enforce the limit */
2630                 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2631                 UNIMPLEMENTED;
2632             }
2633         }
2634         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2635         {
2636             /* Fail with the SEH error */
2637             LoaderStatus = _SEH2_GetExceptionCode();
2638         }
2639         _SEH2_END;
2640 
2641         /* We're not initializing anymore */
2642         LdrpInLdrInit = FALSE;
2643 
2644         /* Check if init worked */
2645         if (NT_SUCCESS(LoaderStatus))
2646         {
2647             /* Set the process as Initialized */
2648             _InterlockedIncrement(&LdrpProcessInitialized);
2649         }
2650     }
2651     else
2652     {
2653         /* Loader data is there... is this a fork() ? */
2654         if(Peb->InheritedAddressSpace)
2655         {
2656             /* Handle the fork() */
2657             //LoaderStatus = LdrpForkProcess();
2658             LoaderStatus = STATUS_NOT_IMPLEMENTED;
2659             UNIMPLEMENTED;
2660         }
2661         else
2662         {
2663             /* This is a new thread initializing */
2664             LdrpInitializeThread(Context);
2665         }
2666     }
2667 
2668     /* All done, test alert the thread */
2669     NtTestAlert();
2670 
2671     /* Return */
2672     if (!NT_SUCCESS(LoaderStatus))
2673     {
2674         /* Fail */
2675         LdrpInitFailure(LoaderStatus);
2676         RtlRaiseStatus(LoaderStatus);
2677     }
2678 }
2679 
2680 /* EOF */
2681