[LDR] Introduce a private heap for the loader.
[reactos.git] / dll / ntdll / ldr / ldrinit.c
index 2c7094d..bc72c95 100644 (file)
@@ -10,9 +10,8 @@
 /* INCLUDES *****************************************************************/
 
 #include <ntdll.h>
-
-#include <wingdi.h>
-#include <callback.h>
+#include <compat_undoc.h>
+#include <compatguid_undoc.h>
 
 #define NDEBUG
 #include <debug.h>
@@ -25,6 +24,7 @@ HANDLE Wow64ExecOptionsKey;
 UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
 UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
 UNICODE_STRING NtDllString = RTL_CONSTANT_STRING(L"ntdll.dll");
+UNICODE_STRING Kernel32String = RTL_CONSTANT_STRING(L"kernel32.dll");
 
 BOOLEAN LdrpInLdrInit;
 LONG LdrpProcessInitialized;
@@ -42,6 +42,9 @@ extern PTEB LdrpTopLevelDllBeingLoadedTeb; // defined in rtlsupp.c!
 PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer;
 PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry;
 
+static NTSTATUS (WINAPI *Kernel32ProcessInitPostImportFunction)(VOID);
+static BOOL (WINAPI *Kernel32BaseQueryModuleData)(IN LPSTR ModuleName, IN LPSTR Unk1, IN PVOID Unk2, IN PVOID Unk3, IN PVOID Unk4);
+
 RTL_BITMAP TlsBitMap;
 RTL_BITMAP TlsExpansionBitMap;
 RTL_BITMAP FlsBitMap;
@@ -52,6 +55,7 @@ ULONG LdrpNumberOfProcessors;
 PVOID NtDllBase;
 extern LARGE_INTEGER RtlpTimeout;
 BOOLEAN RtlpTimeoutDisable;
+PVOID LdrpHeap;
 LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
 LIST_ENTRY LdrpDllNotificationList;
 HANDLE LdrpKnownDllObjectDirectory;
@@ -80,16 +84,16 @@ ULONG LdrpActiveUnloadCount;
 
 //extern LIST_ENTRY RtlCriticalSectionList;
 
-VOID RtlpInitializeVectoredExceptionHandling(VOID);
+VOID NTAPI RtlpInitializeVectoredExceptionHandling(VOID);
 VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
 VOID NTAPI RtlInitializeHeapManager(VOID);
-extern BOOLEAN RtlpPageHeapEnabled;
 
 ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c
 ULONG RtlpShutdownProcessFlags; // TODO: Use it
 
 NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase);
 void actctx_init(void);
+extern BOOLEAN RtlpUse16ByteSLists;
 
 #ifdef _WIN64
 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
@@ -137,7 +141,7 @@ LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey,
     if (NT_SUCCESS(Status))
     {
         /* Write the key handle */
-        if (_InterlockedCompareExchange((LONG*)RootKeyLocation, (LONG)RootKey, 0) != 0)
+        if (InterlockedCompareExchangePointer(RootKeyLocation, RootKey, NULL) != NULL)
         {
             /* Someone already opened it, use it instead */
             NtClose(RootKey);
@@ -397,7 +401,7 @@ LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
 
 VOID
 NTAPI
-LdrpEnsureLoaderLockIsHeld()
+LdrpEnsureLoaderLockIsHeld(VOID)
 {
     // Ignored atm
 }
@@ -461,8 +465,8 @@ LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
             NtQueryPerformanceCounter(&Counter, NULL);
 
             NewCookie = Counter.LowPart ^ Counter.HighPart;
-            NewCookie ^= (ULONG)NtCurrentTeb()->ClientId.UniqueProcess;
-            NewCookie ^= (ULONG)NtCurrentTeb()->ClientId.UniqueThread;
+            NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueProcess;
+            NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueThread;
 
             /* Loop like it's done in KeQueryTickCount(). We don't want to call it directly. */
             while (SharedUserData->SystemTime.High1Time != SharedUserData->SystemTime.High2Time)
@@ -528,7 +532,7 @@ LdrpInitializeThread(IN PCONTEXT Context)
     while (NextEntry != ListHead)
     {
         /* Get the current entry */
-        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList);
+        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
 
         /* Make sure it's not ourselves */
         if (Peb->ImageBaseAddress != LdrEntry->DllBase)
@@ -553,30 +557,39 @@ LdrpInitializeThread(IN PCONTEXT Context)
                     RtlActivateActivationContextUnsafeFast(&ActCtx,
                                                            LdrEntry->EntryPointActivationContext);
 
-                    /* Check if it has TLS */
-                    if (LdrEntry->TlsIndex)
+                    _SEH2_TRY
                     {
+                        /* Check if it has TLS */
+                        if (LdrEntry->TlsIndex)
+                        {
+                            /* Make sure we're not shutting down */
+                            if (!LdrpShutdownInProgress)
+                            {
+                                /* Call TLS */
+                                LdrpCallTlsInitializers(LdrEntry, DLL_THREAD_ATTACH);
+                            }
+                        }
+
                         /* Make sure we're not shutting down */
                         if (!LdrpShutdownInProgress)
                         {
-                            /* Call TLS */
-                            LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_ATTACH);
+                            /* Call the Entrypoint */
+                            DPRINT("%wZ - Calling entry point at %p for thread attaching, %p/%p\n",
+                                   &LdrEntry->BaseDllName, LdrEntry->EntryPoint,
+                                   NtCurrentTeb()->RealClientId.UniqueProcess,
+                                   NtCurrentTeb()->RealClientId.UniqueThread);
+                            LdrpCallInitRoutine(LdrEntry->EntryPoint,
+                                                LdrEntry->DllBase,
+                                                DLL_THREAD_ATTACH,
+                                                NULL);
                         }
                     }
-
-                    /* Make sure we're not shutting down */
-                    if (!LdrpShutdownInProgress)
+                    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                     {
-                        /* Call the Entrypoint */
-                        DPRINT("%wZ - Calling entry point at %p for thread attaching, %p/%p\n",
-                                &LdrEntry->BaseDllName, LdrEntry->EntryPoint,
-                                NtCurrentTeb()->RealClientId.UniqueProcess,
-                                NtCurrentTeb()->RealClientId.UniqueThread);
-                        LdrpCallInitRoutine(LdrEntry->EntryPoint,
-                                         LdrEntry->DllBase,
-                                         DLL_THREAD_ATTACH,
-                                         NULL);
+                        DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_THREAD_ATTACH) for %wZ\n",
+                                _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
                     }
+                    _SEH2_END;
 
                     /* Deactivate the ActCtx */
                     RtlDeactivateActivationContextUnsafeFast(&ActCtx);
@@ -600,8 +613,16 @@ LdrpInitializeThread(IN PCONTEXT Context)
         RtlActivateActivationContextUnsafeFast(&ActCtx,
                                                LdrpImageEntry->EntryPointActivationContext);
 
-        /* Do TLS callbacks */
-        LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_ATTACH);
+        _SEH2_TRY
+        {
+            /* Do TLS callbacks */
+            LdrpCallTlsInitializers(LdrpImageEntry, DLL_THREAD_ATTACH);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Do nothing */
+        }
+        _SEH2_END;
 
         /* Deactivate the ActCtx */
         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
@@ -643,7 +664,7 @@ LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
         if (Count > 16)
         {
             /* Allocate space for all the entries */
-            LdrRootEntry = RtlAllocateHeap(RtlGetProcessHeap(),
+            LdrRootEntry = RtlAllocateHeap(LdrpHeap,
                                            0,
                                            Count * sizeof(*LdrRootEntry));
             if (!LdrRootEntry) return STATUS_NO_MEMORY;
@@ -676,7 +697,7 @@ LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
     while (NextEntry != ListHead)
     {
         /* Get the Data Entry */
-        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
+        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
 
         /* Check if we have a Root Entry */
         if (LdrRootEntry)
@@ -713,23 +734,28 @@ LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
         NextEntry = NextEntry->Flink;
     }
 
+    Status = STATUS_SUCCESS;
+
     /* If we got a context, then we have to call Kernel32 for TS support */
     if (Context)
     {
         /* Check if we have one */
-        //if (Kernel32ProcessInitPostImportfunction)
-        //{
+        if (Kernel32ProcessInitPostImportFunction)
+        {
             /* Call it */
-            //Kernel32ProcessInitPostImportfunction();
-        //}
-
+            Status = Kernel32ProcessInitPostImportFunction();
+            if (!NT_SUCCESS(Status))
+            {
+                DPRINT1("LDR: LdrpRunInitializeRoutines - Failed running kernel32 post-import function, Status=0x%08lx\n", Status);
+            }
+        }
         /* Clear it */
-        //Kernel32ProcessInitPostImportfunction = NULL;
-        //UNIMPLEMENTED;
+        Kernel32ProcessInitPostImportFunction = NULL;
     }
 
     /* No root entry? return */
-    if (!LdrRootEntry) return STATUS_SUCCESS;
+    if (!LdrRootEntry)
+        return Status;
 
     /* Set the TLD TEB */
     OldTldTeb = LdrpTopLevelDllBeingLoadedTeb;
@@ -797,23 +823,33 @@ LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
             RtlActivateActivationContextUnsafeFast(&ActCtx,
                                                    LdrEntry->EntryPointActivationContext);
 
-            /* Check if it has TLS */
-            if (LdrEntry->TlsIndex && Context)
+            _SEH2_TRY
             {
-                /* Call TLS */
-                LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_ATTACH);
-            }
+                /* Check if it has TLS */
+                if (LdrEntry->TlsIndex && Context)
+                {
+                    /* Call TLS */
+                    LdrpCallTlsInitializers(LdrEntry, DLL_PROCESS_ATTACH);
+                }
 
-            /* Call the Entrypoint */
-            if (ShowSnaps)
+                /* Call the Entrypoint */
+                if (ShowSnaps)
+                {
+                    DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
+                            &LdrEntry->BaseDllName, EntryPoint);
+                }
+                DllStatus = LdrpCallInitRoutine(EntryPoint,
+                                                LdrEntry->DllBase,
+                                                DLL_PROCESS_ATTACH,
+                                                Context);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
-                DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
-                        &LdrEntry->BaseDllName, EntryPoint);
+                DllStatus = FALSE;
+                DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_PROCESS_ATTACH) for %wZ\n",
+                        _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
             }
-            DllStatus = LdrpCallInitRoutine(EntryPoint,
-                                         LdrEntry->DllBase,
-                                         DLL_PROCESS_ATTACH,
-                                         Context);
+            _SEH2_END;
 
             /* Deactivate the ActCtx */
             RtlDeactivateActivationContextUnsafeFast(&ActCtx);
@@ -841,8 +877,8 @@ LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
     NextEntry = NextEntry->Flink;
     while (NextEntry != ListHead)
     {
-        /* Get the Data Entrry */
-        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
+        /* Get the Data Entry */
+        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
 
         /* FIXME: Verify NX Compat */
         // LdrpCheckNXCompatibility()
@@ -863,8 +899,16 @@ LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
         RtlActivateActivationContextUnsafeFast(&ActCtx,
                                                LdrpImageEntry->EntryPointActivationContext);
 
-        /* Do TLS callbacks */
-        LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_ATTACH);
+        _SEH2_TRY
+        {
+            /* Do TLS callbacks */
+            LdrpCallTlsInitializers(LdrpImageEntry, DLL_PROCESS_ATTACH);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Do nothing */
+        }
+        _SEH2_END;
 
         /* Deactivate the ActCtx */
         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
@@ -878,7 +922,7 @@ Quickie:
     if (LdrRootEntry != LocalArray)
     {
         /* Free the array */
-        RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry);
+        RtlFreeHeap(LdrpHeap, 0, LdrRootEntry);
     }
 
     /* Return to caller */
@@ -903,10 +947,12 @@ LdrShutdownProcess(VOID)
     if (LdrpShutdownInProgress) return STATUS_SUCCESS;
 
     /* Tell the Shim Engine */
-    //if (ShimsEnabled)
-    //{
-        /* FIXME */
-    //}
+    if (g_ShimsEnabled)
+    {
+        VOID(NTAPI *SE_ProcessDying)();
+        SE_ProcessDying = RtlDecodeSystemPointer(g_pfnSE_ProcessDying);
+        SE_ProcessDying();
+    }
 
     /* Tell the world */
     if (ShowSnaps)
@@ -934,7 +980,7 @@ LdrShutdownProcess(VOID)
     while (NextEntry != ListHead)
     {
         /* Get the current entry */
-        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
+        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
         NextEntry = NextEntry->Blink;
 
         /* Make sure it's not ourselves */
@@ -957,20 +1003,29 @@ LdrShutdownProcess(VOID)
                 RtlActivateActivationContextUnsafeFast(&ActCtx,
                                                        LdrEntry->EntryPointActivationContext);
 
-                /* Check if it has TLS */
-                if (LdrEntry->TlsIndex)
+                _SEH2_TRY
                 {
-                    /* Call TLS */
-                    LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_DETACH);
-                }
+                    /* Check if it has TLS */
+                    if (LdrEntry->TlsIndex)
+                    {
+                        /* Call TLS */
+                        LdrpCallTlsInitializers(LdrEntry, DLL_PROCESS_DETACH);
+                    }
 
-                /* Call the Entrypoint */
-                DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
-                        &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
-                LdrpCallInitRoutine(EntryPoint,
-                                 LdrEntry->DllBase,
-                                 DLL_PROCESS_DETACH,
-                                 (PVOID)1);
+                    /* Call the Entrypoint */
+                    DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
+                           &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
+                    LdrpCallInitRoutine(EntryPoint,
+                                        LdrEntry->DllBase,
+                                        DLL_PROCESS_DETACH,
+                                        (PVOID)1);
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_PROCESS_DETACH) for %wZ\n",
+                            _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
+                }
+                _SEH2_END;
 
                 /* Deactivate the ActCtx */
                 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
@@ -990,8 +1045,16 @@ LdrShutdownProcess(VOID)
         RtlActivateActivationContextUnsafeFast(&ActCtx,
                                                LdrpImageEntry->EntryPointActivationContext);
 
-        /* Do TLS callbacks */
-        LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_DETACH);
+        _SEH2_TRY
+        {
+            /* Do TLS callbacks */
+            LdrpCallTlsInitializers(LdrpImageEntry, DLL_PROCESS_DETACH);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Do nothing */
+        }
+        _SEH2_END;
 
         /* Deactivate the ActCtx */
         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
@@ -1039,7 +1102,7 @@ LdrShutdownThread(VOID)
     while (NextEntry != ListHead)
     {
         /* Get the current entry */
-        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
+        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
         NextEntry = NextEntry->Blink;
 
         /* Make sure it's not ourselves */
@@ -1065,28 +1128,37 @@ LdrShutdownThread(VOID)
                     RtlActivateActivationContextUnsafeFast(&ActCtx,
                                                            LdrEntry->EntryPointActivationContext);
 
-                    /* Check if it has TLS */
-                    if (LdrEntry->TlsIndex)
+                    _SEH2_TRY
                     {
+                        /* Check if it has TLS */
+                        if (LdrEntry->TlsIndex)
+                        {
+                            /* Make sure we're not shutting down */
+                            if (!LdrpShutdownInProgress)
+                            {
+                                /* Call TLS */
+                                LdrpCallTlsInitializers(LdrEntry, DLL_THREAD_DETACH);
+                            }
+                        }
+
                         /* Make sure we're not shutting down */
                         if (!LdrpShutdownInProgress)
                         {
-                            /* Call TLS */
-                            LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_DETACH);
+                            /* Call the Entrypoint */
+                            DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
+                                   &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
+                            LdrpCallInitRoutine(EntryPoint,
+                                                LdrEntry->DllBase,
+                                                DLL_THREAD_DETACH,
+                                                NULL);
                         }
                     }
-
-                    /* Make sure we're not shutting down */
-                    if (!LdrpShutdownInProgress)
+                    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                     {
-                        /* Call the Entrypoint */
-                        DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
-                                &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
-                        LdrpCallInitRoutine(EntryPoint,
-                                         LdrEntry->DllBase,
-                                         DLL_THREAD_DETACH,
-                                         NULL);
+                        DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_THREAD_DETACH) for %wZ\n",
+                                _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
                     }
+                    _SEH2_END;
 
                     /* Deactivate the ActCtx */
                     RtlDeactivateActivationContextUnsafeFast(&ActCtx);
@@ -1107,8 +1179,16 @@ LdrShutdownThread(VOID)
         RtlActivateActivationContextUnsafeFast(&ActCtx,
                                                LdrpImageEntry->EntryPointActivationContext);
 
-        /* Do TLS callbacks */
-        LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_DETACH);
+        _SEH2_TRY
+        {
+            /* Do TLS callbacks */
+            LdrpCallTlsInitializers(LdrpImageEntry, DLL_THREAD_DETACH);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Do nothing */
+        }
+        _SEH2_END;
 
         /* Deactivate the ActCtx */
         RtlDeactivateActivationContextUnsafeFast(&ActCtx);
@@ -1128,8 +1208,29 @@ LdrShutdownThread(VOID)
     /* Check for FLS Data */
     if (Teb->FlsData)
     {
-        /* FIXME */
-        DPRINT1("We don't support FLS Data yet\n");
+        /* Mimic BaseRundownFls */
+        ULONG n, FlsHighIndex;
+        PRTL_FLS_DATA pFlsData;
+        PFLS_CALLBACK_FUNCTION lpCallback;
+
+        pFlsData = Teb->FlsData;
+
+        RtlAcquirePebLock();
+        FlsHighIndex = NtCurrentPeb()->FlsHighIndex;
+        RemoveEntryList(&pFlsData->ListEntry);
+        RtlReleasePebLock();
+
+        for (n = 1; n <= FlsHighIndex; ++n)
+        {
+            lpCallback = NtCurrentPeb()->FlsCallback[n];
+            if (lpCallback && pFlsData->Data[n])
+            {
+                lpCallback(pFlsData->Data[n]);
+            }
+        }
+
+        RtlFreeHeap(RtlGetProcessHeap(), 0, pFlsData);
+        Teb->FlsData = NULL;
     }
 
     /* Check for Fiber data */
@@ -1309,26 +1410,6 @@ LdrpFreeTls(VOID)
                 TlsVector);
 }
 
-NTSTATUS
-NTAPI
-LdrpInitializeApplicationVerifierPackage(PUNICODE_STRING ImagePathName, PPEB Peb, BOOLEAN SystemWide, BOOLEAN ReadAdvancedOptions)
-{
-    /* If global flags request DPH, perform some additional actions */
-    if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
-    {
-        // TODO: Read advanced DPH flags from the registry if requested
-        if (ReadAdvancedOptions)
-        {
-            UNIMPLEMENTED;
-        }
-
-        /* Enable page heap */
-        RtlpPageHeapEnabled = TRUE;
-    }
-
-    return STATUS_SUCCESS;
-}
-
 NTSTATUS
 NTAPI
 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE OptionsKey)
@@ -1340,7 +1421,7 @@ LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE
     /* Return error if we were not provided a pointer where to save the options key handle */
     if (!OptionsKey) return STATUS_INVALID_HANDLE;
 
-    /* Zero initialize the optinos key pointer */
+    /* Zero initialize the options key pointer */
     *OptionsKey = NULL;
 
     /* Open the options key */
@@ -1422,9 +1503,9 @@ LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE
             GlobalFlag = 0;
 
         /* Call AVRF if necessary */
-        if (Peb->NtGlobalFlag & (FLG_POOL_ENABLE_TAIL_CHECK | FLG_HEAP_PAGE_ALLOCS))
+        if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
         {
-            Status = LdrpInitializeApplicationVerifierPackage(ImagePathName, Peb, TRUE, FALSE);
+            Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
             if (!NT_SUCCESS(Status))
             {
                 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
@@ -1434,10 +1515,10 @@ LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE
     else
     {
         /* There are no image-specific options, so perform global initialization */
-        if (Peb->NtGlobalFlag & (FLG_POOL_ENABLE_TAIL_CHECK | FLG_HEAP_PAGE_ALLOCS))
+        if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
         {
             /* Initialize app verifier package */
-            Status = LdrpInitializeApplicationVerifierPackage(ImagePathName, Peb, TRUE, FALSE);
+            Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
             if (!NT_SUCCESS(Status))
             {
                 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
@@ -1455,6 +1536,97 @@ LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)
     UNIMPLEMENTED;
 }
 
+VOID
+NTAPI
+LdrpInitializeProcessCompat(PVOID* pOldShimData)
+{
+    static const GUID* GuidOrder[] = { &COMPAT_GUID_WIN10, &COMPAT_GUID_WIN81, &COMPAT_GUID_WIN8,
+                                       &COMPAT_GUID_WIN7, &COMPAT_GUID_VISTA };
+    static const DWORD GuidVersions[] = { WINVER_WIN10, WINVER_WIN81, WINVER_WIN8, WINVER_WIN7, WINVER_VISTA };
+
+    ULONG Buffer[(sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * 10 + sizeof(ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION)) / sizeof(ULONG)];
+    ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION* ContextCompatInfo;
+    SIZE_T SizeRequired;
+    NTSTATUS Status;
+    DWORD n, cur;
+    ReactOS_ShimData* pShimData = *pOldShimData;
+
+    C_ASSERT(RTL_NUMBER_OF(GuidOrder) == RTL_NUMBER_OF(GuidVersions));
+
+    if (pShimData)
+    {
+        if (pShimData->dwMagic != REACTOS_SHIMDATA_MAGIC ||
+            pShimData->dwSize != sizeof(ReactOS_ShimData))
+        {
+            DPRINT1("LdrpInitializeProcessCompat: Corrupt pShimData (0x%x, %u)\n", pShimData->dwMagic, pShimData->dwSize);
+            return;
+        }
+        if (pShimData->dwRosProcessCompatVersion)
+        {
+            DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion already set to 0x%x\n", pShimData->dwRosProcessCompatVersion);
+            return;
+        }
+    }
+
+    SizeRequired = sizeof(Buffer);
+    Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF,
+                                                  NULL,
+                                                  NULL,
+                                                  CompatibilityInformationInActivationContext,
+                                                  Buffer,
+                                                  sizeof(Buffer),
+                                                  &SizeRequired);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("LdrpInitializeProcessCompat: Unable to query process actctx with status %x\n", Status);
+        return;
+    }
+
+    ContextCompatInfo = (ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*)Buffer;
+    /* No Compatibility elements present, bail out */
+    if (ContextCompatInfo->ElementCount == 0)
+        return;
+
+    /* Search for known GUID's, starting from newest to oldest. */
+    for (cur = 0; cur < RTL_NUMBER_OF(GuidOrder); ++cur)
+    {
+        for (n = 0; n < ContextCompatInfo->ElementCount; ++n)
+        {
+            if (ContextCompatInfo->Elements[n].Type == ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS &&
+                RtlCompareMemory(&ContextCompatInfo->Elements[n].Id, GuidOrder[cur], sizeof(GUID)) == sizeof(GUID))
+            {
+                /* If this process did not need shim data before, allocate and store it */
+                if (pShimData == NULL)
+                {
+                    PPEB Peb = NtCurrentPeb();
+
+                    ASSERT(Peb->pShimData == NULL);
+                    pShimData = RtlAllocateHeap(Peb->ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*pShimData));
+
+                    if (!pShimData)
+                    {
+                        DPRINT1("LdrpInitializeProcessCompat: Unable to allocated %u bytes\n", sizeof(*pShimData));
+                        return;
+                    }
+
+                    pShimData->dwSize = sizeof(*pShimData);
+                    pShimData->dwMagic = REACTOS_SHIMDATA_MAGIC;
+
+                    Peb->pShimData = pShimData;
+                    *pOldShimData = pShimData;
+                }
+
+                /* Store the highest found version, and bail out. */
+                pShimData->dwRosProcessCompatVersion = GuidVersions[cur];
+                DPRINT1("LdrpInitializeProcessCompat: Found guid for winver 0x%x\n", GuidVersions[cur]);
+                return;
+            }
+        }
+    }
+}
+
+
 NTSTATUS
 NTAPI
 LdrpInitializeProcess(IN PCONTEXT Context,
@@ -1462,7 +1634,8 @@ LdrpInitializeProcess(IN PCONTEXT Context,
 {
     RTL_HEAP_PARAMETERS HeapParameters;
     ULONG ComSectionSize;
-    //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
+    ANSI_STRING BaseProcessInitPostImportName = RTL_CONSTANT_STRING("BaseProcessInitPostImport");
+    ANSI_STRING BaseQueryModuleDataName = RTL_CONSTANT_STRING("BaseQueryModuleData");
     PVOID OldShimData;
     OBJECT_ATTRIBUTES ObjectAttributes;
     //UNICODE_STRING LocalFileName, FullImageName;
@@ -1525,7 +1698,7 @@ LdrpInitializeProcess(IN PCONTEXT Context,
                                      IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
                                      &ComSectionSize))
     {
-        /* Remeber this for later */
+        /* Remember this for later */
         IsDotNetImage = TRUE;
     }
 
@@ -1542,8 +1715,8 @@ LdrpInitializeProcess(IN PCONTEXT Context,
     /* Save the old Shim Data */
     OldShimData = Peb->pShimData;
 
-    /* Clear it */
-    Peb->pShimData = NULL;
+    /* ReactOS specific: do not clear it. (Windows starts doing the same in later versions) */
+    //Peb->pShimData = NULL;
 
     /* Save the number of processors and CS Timeout */
     LdrpNumberOfProcessors = Peb->NumberOfProcessors;
@@ -1580,9 +1753,9 @@ LdrpInitializeProcess(IN PCONTEXT Context,
                                               &ConfigSize);
 
     /* Setup the Heap Parameters */
-    RtlZeroMemory(&HeapParameters, sizeof(RTL_HEAP_PARAMETERS));
+    RtlZeroMemory(&HeapParameters, sizeof(HeapParameters));
     HeapFlags = HEAP_GROWABLE;
-    HeapParameters.Length = sizeof(RTL_HEAP_PARAMETERS);
+    HeapParameters.Length = sizeof(HeapParameters);
 
     /* Check if we have Configuration Data */
     if ((LoadConfig) && (ConfigSize == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY)))
@@ -1635,6 +1808,7 @@ LdrpInitializeProcess(IN PCONTEXT Context,
                         Peb->FlsBitmapBits,
                         FLS_MAXIMUM_AVAILABLE);
     RtlSetBit(&FlsBitMap, 0);
+    InitializeListHead(&Peb->FlsListHead);
 
     /* Initialize TLS Bitmap */
     RtlInitializeBitMap(&TlsBitMap,
@@ -1702,8 +1876,15 @@ LdrpInitializeProcess(IN PCONTEXT Context,
     Status = RtlAllocateActivationContextStack(&Teb->ActivationContextStackPointer);
     if (!NT_SUCCESS(Status)) return Status;
 
-    // FIXME: Loader private heap is missing
-    //DPRINT1("Loader private heap is missing\n");
+    RtlZeroMemory(&HeapParameters, sizeof(HeapParameters));
+    HeapFlags = HEAP_GROWABLE | HEAP_CLASS_1;
+    HeapParameters.Length = sizeof(HeapParameters);
+    LdrpHeap = RtlCreateHeap(HeapFlags, 0, 0x10000, 0x6000, 0, &HeapParameters);
+    if (!LdrpHeap)
+    {
+        DPRINT1("Failed to create loader private heap\n");
+        return STATUS_NO_MEMORY;
+    }
 
     /* Check for Debug Heap */
     if (OptionsKey)
@@ -1778,7 +1959,7 @@ LdrpInitializeProcess(IN PCONTEXT Context,
     /* Check if we failed */
     if (!NT_SUCCESS(Status))
     {
-        /* Aassume System32 */
+        /* Assume System32 */
         LdrpKnownDllObjectDirectory = NULL;
         RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer);
         LdrpKnownDllPath.Length -= sizeof(WCHAR);
@@ -1846,24 +2027,24 @@ LdrpInitializeProcess(IN PCONTEXT Context,
     PebLdr.Initialized = TRUE;
 
     /* Allocate a data entry for the Image */
-    LdrpImageEntry = NtLdrEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
+    LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
 
     /* Set it up */
-    NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
-    NtLdrEntry->LoadCount = -1;
-    NtLdrEntry->EntryPointActivationContext = 0;
-    NtLdrEntry->FullDllName = ImageFileName;
+    LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrpImageEntry->DllBase);
+    LdrpImageEntry->LoadCount = -1;
+    LdrpImageEntry->EntryPointActivationContext = 0;
+    LdrpImageEntry->FullDllName = ImageFileName;
 
     if (IsDotNetImage)
-        NtLdrEntry->Flags = LDRP_COR_IMAGE;
+        LdrpImageEntry->Flags = LDRP_COR_IMAGE;
     else
-        NtLdrEntry->Flags = 0;
+        LdrpImageEntry->Flags = 0;
 
     /* Check if the name is empty */
     if (!ImageFileName.Buffer[0])
     {
         /* Use the same Base name */
-        NtLdrEntry->BaseDllName = NtLdrEntry->FullDllName;
+        LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
     }
     else
     {
@@ -1882,21 +2063,21 @@ LdrpInitializeProcess(IN PCONTEXT Context,
         if (!NtDllName)
         {
             /* Use the same Base name */
-            NtLdrEntry->BaseDllName = NtLdrEntry->FullDllName;
+            LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
         }
         else
         {
             /* Setup the name */
-            NtLdrEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
-            NtLdrEntry->BaseDllName.MaximumLength = NtLdrEntry->BaseDllName.Length + sizeof(WCHAR);
-            NtLdrEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
-                                                     (ImageFileName.Length - NtLdrEntry->BaseDllName.Length));
+            LdrpImageEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
+            LdrpImageEntry->BaseDllName.MaximumLength = LdrpImageEntry->BaseDllName.Length + sizeof(WCHAR);
+            LdrpImageEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
+                                                     (ImageFileName.Length - LdrpImageEntry->BaseDllName.Length));
         }
     }
 
     /* Processing done, insert it */
-    LdrpInsertMemoryTableEntry(NtLdrEntry);
-    NtLdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
+    LdrpInsertMemoryTableEntry(LdrpImageEntry);
+    LdrpImageEntry->Flags |= LDRP_ENTRY_PROCESSED;
 
     /* Now add an entry for NTDLL */
     NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
@@ -1929,11 +2110,14 @@ LdrpInitializeProcess(IN PCONTEXT Context,
 
     /* Link the Init Order List */
     InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
-                   &LdrpNtDllDataTableEntry->InInitializationOrderModuleList);
+                   &LdrpNtDllDataTableEntry->InInitializationOrderLinks);
 
     /* Initialize Wine's active context implementation for the current process */
     actctx_init();
 
+    /* ReactOS specific */
+    LdrpInitializeProcessCompat(&OldShimData);
+
     /* Set the current directory */
     Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
     if (!NT_SUCCESS(Status))
@@ -1959,10 +2143,15 @@ LdrpInitializeProcess(IN PCONTEXT Context,
     }
 
     /* Check if the Application Verifier was enabled */
-    if (Peb->NtGlobalFlag & FLG_POOL_ENABLE_TAIL_CHECK)
+    if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
     {
-        /* FIXME */
-        DPRINT1("We don't support Application Verifier yet\n");
+        Status = AVrfInitializeVerifier();
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("LDR: AVrfInitializeVerifier failed (ntstatus 0x%x)\n", Status);
+            return Status;
+        }
+
     }
 
     if (IsDotNetImage)
@@ -1971,11 +2160,46 @@ LdrpInitializeProcess(IN PCONTEXT Context,
         DPRINT1("We don't support .NET applications yet\n");
     }
 
-    /* FIXME: Load support for Terminal Services */
-    if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
+    if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ||
+        NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
     {
-        /* Load kernel32 and call BasePostImportInit... */
-        DPRINT("Unimplemented codepath!\n");
+        PVOID Kernel32BaseAddress;
+        PVOID FunctionAddress;
+
+        Status = LdrLoadDll(NULL, NULL, &Kernel32String, &Kernel32BaseAddress);
+
+        if (!NT_SUCCESS(Status))
+        {
+            if (ShowSnaps)
+                DPRINT1("LDR: Unable to load %wZ, Status=0x%08lx\n", &Kernel32String, Status);
+            return Status;
+        }
+
+        Status = LdrGetProcedureAddress(Kernel32BaseAddress,
+                                        &BaseProcessInitPostImportName,
+                                        0,
+                                        &FunctionAddress);
+
+        if (!NT_SUCCESS(Status))
+        {
+            if (ShowSnaps)
+                DPRINT1("LDR: Unable to find post-import process init function, Status=0x%08lx\n", &Kernel32String, Status);
+            return Status;
+        }
+        Kernel32ProcessInitPostImportFunction = FunctionAddress;
+
+        Status = LdrGetProcedureAddress(Kernel32BaseAddress,
+                                        &BaseQueryModuleDataName,
+                                        0,
+                                        &FunctionAddress);
+
+        if (!NT_SUCCESS(Status))
+        {
+            if (ShowSnaps)
+                DPRINT1("LDR: Unable to find BaseQueryModuleData, Status=0x%08lx\n", &Kernel32String, Status);
+            return Status;
+        }
+        Kernel32BaseQueryModuleData = FunctionAddress;
     }
 
     /* Walk the IAT and load all the DLLs */
@@ -2073,13 +2297,46 @@ LdrpInitializeProcess(IN PCONTEXT Context,
                             &ExecuteOptions,
                             sizeof(ULONG));
 
+    // FIXME: Should be done by Application Compatibility features,
+    // by reading the registry, etc...
+    // For now, this is the old code from ntdll!RtlGetVersion().
+    RtlInitEmptyUnicodeString(&Peb->CSDVersion, NULL, 0);
+    if (((Peb->OSCSDVersion >> 8) & 0xFF) != 0)
+    {
+        WCHAR szCSDVersion[128];
+        LONG i;
+        ULONG Length = ARRAYSIZE(szCSDVersion) - 1;
+        i = _snwprintf(szCSDVersion, Length,
+                       L"Service Pack %d",
+                       ((Peb->OSCSDVersion >> 8) & 0xFF));
+        if (i < 0)
+        {
+            /* Null-terminate if it was overflowed */
+            szCSDVersion[Length] = UNICODE_NULL;
+        }
+
+        Length *= sizeof(WCHAR);
+        Peb->CSDVersion.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                                                 0,
+                                                 Length + sizeof(UNICODE_NULL));
+        if (Peb->CSDVersion.Buffer)
+        {
+            Peb->CSDVersion.Length = Length;
+            Peb->CSDVersion.MaximumLength = Length + sizeof(UNICODE_NULL);
+
+            RtlCopyMemory(Peb->CSDVersion.Buffer,
+                          szCSDVersion,
+                          Peb->CSDVersion.MaximumLength);
+            Peb->CSDVersion.Buffer[Peb->CSDVersion.Length / sizeof(WCHAR)] = UNICODE_NULL;
+        }
+    }
+
     /* Check if we had Shim Data */
     if (OldShimData)
     {
         /* Load the Shim Engine */
         Peb->AppCompatInfo = NULL;
-        //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData);
-        DPRINT1("We do not support shims yet\n");
+        LdrpLoadShimEngine(OldShimData, &ImagePathName, OldShimData);
     }
     else
     {
@@ -2102,7 +2359,13 @@ LdrpInitializeProcess(IN PCONTEXT Context,
         return Status;
     }
 
-    /* FIXME: Unload the Shim Engine if it was loaded */
+    /* Notify Shim Engine */
+    if (g_ShimsEnabled)
+    {
+        VOID(NTAPI *SE_InstallAfterInit)(PUNICODE_STRING, PVOID);
+        SE_InstallAfterInit = RtlDecodeSystemPointer(g_pfnSE_InstallAfterInit);
+        SE_InstallAfterInit(&ImagePathName, OldShimData);
+    }
 
     /* Check if we have a user-defined Post Process Routine */
     if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
@@ -2152,6 +2415,11 @@ LdrpInit(PCONTEXT Context,
         NtCurrentTeb()->RealClientId.UniqueProcess,
         NtCurrentTeb()->RealClientId.UniqueThread);
 
+#ifdef _WIN64
+    /* Set the SList header usage */
+    RtlpUse16ByteSLists = SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128];
+#endif /* _WIN64 */
+
     /* Check if we have a deallocation stack */
     if (!Teb->DeallocationStack)
     {
@@ -2179,11 +2447,11 @@ LdrpInit(PCONTEXT Context,
                                       1,
                                       0) == 1)
     {
-        /* Set the timeout to 30 seconds */
+        /* Set the timeout to 30 milliseconds */
         Timeout.QuadPart = Int32x32To64(30, -10000);
 
         /* Make sure the status hasn't changed */
-        while (!LdrpProcessInitialized)
+        while (LdrpProcessInitialized == 1)
         {
             /* Do the wait */
             ZwDelayExecution(FALSE, &Timeout);