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