[KERNEL32]
[reactos.git] / reactos / dll / win32 / kernel32 / client / proc.c
index f063304..6c44e99 100644 (file)
@@ -1,10 +1,9 @@
-/* $Id$
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/kernel32/proc/proc.c
  * PURPOSE:         Process functions
- * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
+ * PROGRAMMERS:     Ariadne (ariadne@xs4all.nl)
  * UPDATE HISTORY:
  *                  Created 01/11/98
  */
 #define NDEBUG
 #include <debug.h>
 
-
-typedef INT (WINAPI *MessageBoxW_Proc) (HWND, LPCWSTR, LPCWSTR, UINT);
-
 /* GLOBALS *******************************************************************/
 
-static UNICODE_STRING CommandLineStringW;
-static ANSI_STRING CommandLineStringA;
-
-static BOOL bCommandLineInitialized = FALSE;
-
-WaitForInputIdleType  lpfnGlobalRegisterWaitForInputIdle;
+WaitForInputIdleType UserWaitForInputIdleRoutine;
+UNICODE_STRING BaseUnicodeCommandLine;
+ANSI_STRING BaseAnsiCommandLine;
+UNICODE_STRING BasePathVariableName = RTL_CONSTANT_STRING(L"PATH");
+LPSTARTUPINFOA BaseAnsiStartupInfo = NULL;
+PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry;
+BOOLEAN g_AppCertInitialized;
+BOOLEAN g_HaveAppCerts;
+LIST_ENTRY BasepAppCertDllsList;
+RTL_CRITICAL_SECTION gcsAppCert;
+PBASEP_APPCERT_EMBEDDED_FUNC fEmbeddedCertFunc;
+NTSTATUS g_AppCertStatus;
+RTL_QUERY_REGISTRY_TABLE BasepAppCertTable[2] =
+{
+    {
+        BasepConfigureAppCertDlls,
+        1,
+        L"AppCertDlls",
+        &BasepAppCertDllsList,
+        0,
+        NULL,
+        0
+    }
+};
 
-LPSTARTUPINFOA lpLocalStartupInfo = NULL;
+PSAFER_REPLACE_PROCESS_THREAD_TOKENS g_SaferReplaceProcessThreadTokens;
+HMODULE gSaferHandle = (HMODULE)-1;
 
 VOID WINAPI
 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle);
 
-UNICODE_STRING BasePathVariableName = RTL_CONSTANT_STRING(L"PATH");
-PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry;
-
 #define CMD_STRING L"cmd /c "
 
-extern __declspec(noreturn)
-VOID
-CALLBACK
-ConsoleControlDispatcher(DWORD CodeAndFlag);
-
 /* FUNCTIONS ****************************************************************/
 
-static
-LONG BaseExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo)
+VOID
+WINAPI
+StuffStdHandle(IN HANDLE ProcessHandle,
+               IN HANDLE StandardHandle,
+               IN PHANDLE Address)
 {
-    LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
+    NTSTATUS Status;
+    HANDLE DuplicatedHandle;
+    SIZE_T NumberOfBytesWritten;
 
-    if (GlobalTopLevelExceptionFilter != NULL)
-    {
-        _SEH2_TRY
-        {
-            ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo);
-        }
-        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-        {
-        }
-        _SEH2_END;
-    }
-    if ((ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH || ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER) &&
-        GlobalTopLevelExceptionFilter != UnhandledExceptionFilter)
-    {
-       ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
-    }
+    /* If there is no handle to duplicate, return immediately */
+    if (!StandardHandle) return;
 
-    return ExceptionDisposition;
+    /* Duplicate the handle */
+    Status = NtDuplicateObject(NtCurrentProcess(),
+                               StandardHandle,
+                               ProcessHandle,
+                               &DuplicatedHandle,
+                               0,
+                               0,
+                               DUPLICATE_SAME_ACCESS |
+                               DUPLICATE_SAME_ATTRIBUTES);
+    if (!NT_SUCCESS(Status)) return;
+
+    /* Write it */
+    NtWriteVirtualMemory(ProcessHandle,
+                         Address,
+                         &DuplicatedHandle,
+                         sizeof(HANDLE),
+                         &NumberOfBytesWritten);
 }
 
-VOID
+BOOLEAN
 WINAPI
-BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress)
+BuildSubSysCommandLine(IN LPCWSTR SubsystemName,
+                       IN LPCWSTR ApplicationName,
+                       IN LPCWSTR CommandLine,
+                       OUT PUNICODE_STRING SubsysCommandLine)
 {
-    UINT uExitCode = 0;
-
-    DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
-
-    _SEH2_TRY
-    {
-        /* Set our Start Address */
-        NtSetInformationThread(NtCurrentThread(),
-                               ThreadQuerySetWin32StartAddress,
-                               &lpStartAddress,
-                               sizeof(PPROCESS_START_ROUTINE));
-
-        /* Call the Start Routine */
-        uExitCode = (lpStartAddress)();
-    }
-    _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
-    {
-        /* Get the SEH Error */
-        uExitCode = _SEH2_GetExceptionCode();
+    UNICODE_STRING CommandLineString, ApplicationNameString;
+    PWCHAR Buffer;
+    ULONG Length;
+
+    /* Convert to unicode strings */
+    RtlInitUnicodeString(&CommandLineString, ApplicationName);
+    RtlInitUnicodeString(&ApplicationNameString, CommandLine);
+
+    /* Allocate buffer for the output string */
+    Length = CommandLineString.MaximumLength + ApplicationNameString.MaximumLength + 32;
+    Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
+    RtlInitEmptyUnicodeString(SubsysCommandLine, Buffer, (USHORT)Length);
+    if (!Buffer)
+    {
+        /* Fail, no memory */
+        BaseSetLastNTError(STATUS_NO_MEMORY);
+        return FALSE;
     }
-    _SEH2_END;
 
-    /* Exit the Process with our error */
-    ExitProcess(uExitCode);
+    /* Build the final subsystem command line */
+    RtlAppendUnicodeToString(SubsysCommandLine, SubsystemName);
+    RtlAppendUnicodeStringToString(SubsysCommandLine, &CommandLineString);
+    RtlAppendUnicodeToString(SubsysCommandLine, L" /C ");
+    RtlAppendUnicodeStringToString(SubsysCommandLine, &ApplicationNameString);
+    return TRUE;
+}
+
+BOOLEAN
+WINAPI
+BasepIsImageVersionOk(IN ULONG ImageMajorVersion,
+                      IN ULONG ImageMinorVersion)
+{
+    /* Accept images for NT 3.1 or higher, as long as they're not newer than us */
+    return ((ImageMajorVersion >= 3) &&
+            ((ImageMajorVersion != 3) ||
+             (ImageMinorVersion >= 10)) &&
+            (ImageMajorVersion <= SharedUserData->NtMajorVersion) &&
+            ((ImageMajorVersion != SharedUserData->NtMajorVersion) ||
+             (ImageMinorVersion <= SharedUserData->NtMinorVersion)));
 }
 
-/*
- * Tells CSR that a new process was created
- */
 NTSTATUS
 WINAPI
-BasepNotifyCsrOfCreation(ULONG dwCreationFlags,
-                         IN HANDLE ProcessId,
-                         IN BOOL InheritHandles)
+BasepCheckWebBladeHashes(IN HANDLE FileHandle)
 {
-    ULONG Request = CREATE_PROCESS;
-    CSR_API_MESSAGE CsrRequest;
     NTSTATUS Status;
+    CHAR Hash[16];
 
-    DPRINT("BasepNotifyCsrOfCreation: Process: %lx, Flags %lx\n",
-            ProcessId, dwCreationFlags);
-
-    /* Fill out the request */
-    CsrRequest.Data.CreateProcessRequest.NewProcessId = ProcessId;
-    CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
-    CsrRequest.Data.CreateProcessRequest.bInheritHandles = InheritHandles;
+    /* Get all the MD5 hashes */
+    Status = RtlComputeImportTableHash(FileHandle, Hash, 1);
+    if (!NT_SUCCESS(Status)) return Status;
 
-    /* Call CSR */
-    Status = CsrClientCallServer(&CsrRequest,
-                                 NULL,
-                                 MAKE_CSR_API(Request, CSR_NATIVE),
-                                 sizeof(CSR_API_MESSAGE));
-    if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
+    /* Depending on which suite this is, run a bsearch and block the appropriate ones */
+    if (SharedUserData->SuiteMask & VER_SUITE_COMPUTE_SERVER)
     {
-        DPRINT1("Failed to tell csrss about new process\n");
-        return CsrRequest.Status;
+        DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't.");
+    }
+    else if (SharedUserData->SuiteMask & VER_SUITE_STORAGE_SERVER)
+    {
+        DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't.");
+    }
+    else if (SharedUserData->SuiteMask & VER_SUITE_BLADE)
+    {
+        DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't.");
     }
 
-    /* Return Success */
+    /* Actually, fuck it, don't block anything, we're open source */
     return STATUS_SUCCESS;
 }
 
 NTSTATUS
-WINAPI
-BasepNotifyCsrOfThread(IN HANDLE ThreadHandle,
-                       IN PCLIENT_ID ClientId)
+NTAPI
+BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List,
+                              IN PWCHAR ComponentName,
+                              IN PWCHAR DllName)
 {
-    ULONG Request = CREATE_THREAD;
-    CSR_API_MESSAGE CsrRequest;
-    NTSTATUS Status;
-
-    DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n",
-            ClientId->UniqueThread, ThreadHandle);
-
-    /* Fill out the request */
-    CsrRequest.Data.CreateThreadRequest.ClientId = *ClientId;
-    CsrRequest.Data.CreateThreadRequest.ThreadHandle = ThreadHandle;
-
-    /* Call CSR */
-    Status = CsrClientCallServer(&CsrRequest,
-                                 NULL,
-                                 MAKE_CSR_API(Request, CSR_NATIVE),
-                                 sizeof(CSR_API_MESSAGE));
-    if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
-    {
-        DPRINT1("Failed to tell csrss about new thread\n");
-        return CsrRequest.Status;
-    }
+    /* Pretty much the only thing this key is used for, is malware */
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
 
-    /* Return Success */
-    return STATUS_SUCCESS;
+NTSTATUS
+NTAPI
+BasepConfigureAppCertDlls(IN PWSTR ValueName,
+                          IN ULONG ValueType,
+                          IN PVOID ValueData,
+                          IN ULONG ValueLength,
+                          IN PVOID Context,
+                          IN PVOID EntryContext)
+{
+    /* Add this to the certification list */
+    return BasepSaveAppCertRegistryValue(Context, ValueName, ValueData);
 }
 
-/*
- * Creates the first Thread in a Proces
- */
-HANDLE
+NTSTATUS
 WINAPI
-BasepCreateFirstThread(HANDLE ProcessHandle,
-                       LPSECURITY_ATTRIBUTES lpThreadAttributes,
-                       PSECTION_IMAGE_INFORMATION SectionImageInfo,
-                       PCLIENT_ID ClientId)
+BasepIsProcessAllowed(IN LPWSTR ApplicationName)
 {
-    OBJECT_ATTRIBUTES LocalObjectAttributes;
-    POBJECT_ATTRIBUTES ObjectAttributes;
-    CONTEXT Context;
-    INITIAL_TEB InitialTeb;
-    NTSTATUS Status;
-    HANDLE hThread;
+    NTSTATUS Status, Status1;
+    PWCHAR Buffer;
+    UINT Length;
+    HMODULE TrustLibrary;
+    PBASEP_APPCERT_ENTRY Entry;
+    ULONG CertFlag;
+    PLIST_ENTRY NextEntry;
+    HANDLE KeyHandle;
+    UNICODE_STRING CertKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
+    OBJECT_ATTRIBUTES KeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey, OBJ_CASE_INSENSITIVE);
+
+    /* Try to initialize the certification subsystem */
+    while (!g_AppCertInitialized)
+    {
+        /* Defaults */
+        Status = STATUS_SUCCESS;
+        Buffer = NULL;
+
+        /* Acquire the lock while initializing and see if we lost a race */
+        RtlEnterCriticalSection(&gcsAppCert);
+        if (g_AppCertInitialized) break;
+
+        /* On embedded, there is a special DLL */
+        if (SharedUserData->SuiteMask & VER_SUITE_EMBEDDEDNT)
+        {
+            /* Allocate a buffer for the name */
+            Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                                     0,
+                                     MAX_PATH * sizeof(WCHAR) +
+                                     sizeof(UNICODE_NULL));
+            if (!Buffer)
+            {
+                /* Fail if no memory */
+                Status = STATUS_NO_MEMORY;
+            }
+            else
+            {
+                /* Now get the system32 directory in our buffer, make sure it fits */
+                Length = GetSystemDirectoryW(Buffer, MAX_PATH - sizeof("EmbdTrst.DLL"));
+                if ((Length) && (Length <= MAX_PATH - sizeof("EmbdTrst.DLL")))
+                {
+                    /* Add a slash if needed, and add the embedded cert DLL name */
+                    if (Buffer[Length - 1] != '\\') Buffer[Length++] = '\\';
+                    RtlCopyMemory(&Buffer[Length],
+                                  L"EmbdTrst.DLL",
+                                  sizeof(L"EmbdTrst.DLL"));
+
+                    /* Try to load it */
+                    TrustLibrary = LoadLibraryW(Buffer);
+                    if (TrustLibrary)
+                    {
+                        /* And extract the special function out of it */
+                        fEmbeddedCertFunc = (PVOID)GetProcAddress(TrustLibrary,
+                                                                  "ImageOkToRunOnEmbeddedNT");
+                    }
+                }
+
+                /* If we didn't get this far, set a failure code */
+                if (!fEmbeddedCertFunc) Status = STATUS_UNSUCCESSFUL;
+            }
+        }
+        else
+        {
+            /* Other systems have a registry entry for this */
+            Status1 = NtOpenKey(&KeyHandle, KEY_READ, &KeyAttributes);
+            if (NT_SUCCESS(Status1))
+            {
+                /* Close it, we'll query it through Rtl */
+                NtClose(KeyHandle);
+
+                /* Do the query, which will call a special callback */
+                Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                                L"Session Manager",
+                                                BasepAppCertTable,
+                                                NULL,
+                                                NULL);
+                if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+                {
+                    Status = STATUS_SUCCESS;
+                }
+            }
+        }
 
-    DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle);
+        /* Free any buffer if we had one */
+        if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
 
-    /* Create the Thread's Stack */
-    BasepCreateStack(ProcessHandle,
-                     SectionImageInfo->MaximumStackSize,
-                     SectionImageInfo->CommittedStackSize,
-                     &InitialTeb);
+        /* Check for errors, or a missing embedded/custom certification DLL */
+        if (!NT_SUCCESS(Status) ||
+            (!(fEmbeddedCertFunc) && (IsListEmpty(&BasepAppCertDllsList))))
+        {
+            /* The subsystem is not active on this machine, so give up */
+            g_HaveAppCerts = FALSE;
+            g_AppCertStatus = Status;
+        }
+        else
+        {
+            /* We have certification DLLs active, remember this */
+            g_HaveAppCerts = TRUE;
+        }
 
-    /* Create the Thread's Context */
-    BaseInitializeContext(&Context,
-                           NtCurrentPeb(),
-                           SectionImageInfo->TransferAddress,
-                           InitialTeb.StackBase,
-                           0);
+        /* We are done the initialization phase, release the lock */
+        g_AppCertInitialized = TRUE;
+        RtlLeaveCriticalSection(&gcsAppCert);
+    }
 
-    /* Convert the thread attributes */
-    ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
-                                                    lpThreadAttributes,
-                                                    NULL);
+    /* If there's no certification DLLs present, return the failure code */
+    if (!g_HaveAppCerts) return g_AppCertStatus;
 
-    /* Create the Kernel Thread Object */
-    Status = NtCreateThread(&hThread,
-                            THREAD_ALL_ACCESS,
-                            ObjectAttributes,
-                            ProcessHandle,
-                            ClientId,
-                            &Context,
-                            &InitialTeb,
-                            TRUE);
-    if (!NT_SUCCESS(Status))
+    /* Otherwise, assume success and make sure we have *something* */
+    ASSERT(fEmbeddedCertFunc || !IsListEmpty(&BasepAppCertDllsList));
+    Status = STATUS_SUCCESS;
+
+    /* If the something is an embedded certification DLL, call it and return */
+    if (fEmbeddedCertFunc) return fEmbeddedCertFunc(ApplicationName);
+
+    /* Otherwise we have custom certification DLLs, parse them */
+    NextEntry = BasepAppCertDllsList.Flink;
+    CertFlag = 2;
+    while (NextEntry != &BasepAppCertDllsList)
     {
-        return NULL;
+        /* Make sure the entry has a callback */
+        Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry);
+        ASSERT(Entry->fPluginCertFunc != NULL);
+
+        /* Call it and check if it failed */
+        Status = Entry->fPluginCertFunc(ApplicationName, 1);
+        if (!NT_SUCCESS(Status)) CertFlag = 3;
+
+        /* Move on */
+        NextEntry = NextEntry->Flink;
     }
-    
-    Status = BasepNotifyCsrOfThread(hThread, ClientId);
-    if (!NT_SUCCESS(Status))
+
+    /* Now loop them again */
+    NextEntry = BasepAppCertDllsList.Flink;
+    while (NextEntry != &BasepAppCertDllsList)
     {
-        ASSERT(FALSE);
+        /* Make sure the entry has a callback */
+        Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry);
+        ASSERT(Entry->fPluginCertFunc != NULL);
+
+        /* Call it, this time with the flag from the loop above */
+        Status = Entry->fPluginCertFunc(ApplicationName, CertFlag);
     }
-    
-    /* Success */
-    return hThread;
+
+    /* All done, return the status */
+    return Status;
 }
 
-/*
- * Converts ANSI to Unicode Environment
- */
-PVOID
+NTSTATUS
 WINAPI
-BasepConvertUnicodeEnvironment(OUT SIZE_T* EnvSize,
-                               IN PVOID lpEnvironment)
+BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle,
+                                IN HANDLE ProcessHandle,
+                                IN HANDLE ThreadHandle)
 {
-    PCHAR pcScan;
-    ANSI_STRING AnsiEnv;
-    UNICODE_STRING UnicodeEnv;
     NTSTATUS Status;
+    ANSI_STRING SaferiReplaceProcessThreadTokens = RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
 
-    DPRINT("BasepConvertUnicodeEnvironment\n");
-
-    /* Scan the environment to calculate its Unicode size */
-    AnsiEnv.Buffer = pcScan = (PCHAR)lpEnvironment;
-    while (*pcScan)
-    {
-        pcScan += strlen(pcScan) + 1;
-    }
+    /* Enter the application certification lock */
+    RtlEnterCriticalSection(&gcsAppCert);
 
-    /* Create our ANSI String */
-    if (pcScan == (PCHAR)lpEnvironment)
+    /* Check if we already know the function */
+    if (g_SaferReplaceProcessThreadTokens)
     {
-        AnsiEnv.Length = 2 * sizeof(CHAR);
+        /* Call it */
+        Status = g_SaferReplaceProcessThreadTokens(TokenHandle,
+                                                   ProcessHandle,
+                                                   ThreadHandle) ?
+                                                   STATUS_SUCCESS :
+                                                   STATUS_UNSUCCESSFUL;
     }
     else
     {
-
-        AnsiEnv.Length = (USHORT)((ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + sizeof(CHAR));
-    }
-    AnsiEnv.MaximumLength = AnsiEnv.Length + 1;
-
-    /* Allocate memory for the Unicode Environment */
-    UnicodeEnv.Buffer = NULL;
-    *EnvSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
-    Status = NtAllocateVirtualMemory(NtCurrentProcess(),
-                                     (PVOID)&UnicodeEnv.Buffer,
-                                     0,
-                                     EnvSize,
-                                     MEM_COMMIT,
-                                     PAGE_READWRITE);
-    /* Failure */
-    if (!NT_SUCCESS(Status))
-    {
-        SetLastError(Status);
-        *EnvSize = 0;
-        return NULL;
+        /* Check if the app certification DLL isn't loaded */
+        if (!(gSaferHandle) ||
+            (gSaferHandle == (HMODULE)-1) ||
+            (gSaferHandle == (HMODULE)-2))
+        {
+            /* Then we can't call the function */
+            Status = STATUS_ENTRYPOINT_NOT_FOUND;
+        }
+        else
+        {
+            /* We have the DLL, find the address of the Safer function */
+            Status = LdrGetProcedureAddress(gSaferHandle,
+                                            &SaferiReplaceProcessThreadTokens,
+                                            0,
+                                            (PVOID*)&g_SaferReplaceProcessThreadTokens);
+            if (NT_SUCCESS(Status))
+            {
+                /* Found it, now call it */
+                Status = g_SaferReplaceProcessThreadTokens(TokenHandle,
+                                                           ProcessHandle,
+                                                           ThreadHandle) ?
+                                                           STATUS_SUCCESS :
+                                                           STATUS_UNSUCCESSFUL;
+            }
+            else
+            {
+                /* We couldn't find it, so this must be an unsupported DLL */
+                LdrUnloadDll(gSaferHandle);
+                gSaferHandle = NULL;
+                Status = STATUS_ENTRYPOINT_NOT_FOUND;
+            }
+        }
     }
 
-    /* Use the allocated size */
-    UnicodeEnv.MaximumLength = (USHORT)*EnvSize;
-
-    /* Convert */
-    RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
-    return UnicodeEnv.Buffer;
+    /* Release the lock and return the result */
+    RtlLeaveCriticalSection(&gcsAppCert);
+    return Status;
 }
 
-/*
- * Converts a Win32 Priority Class to NT
- */
-ULONG
+VOID
 WINAPI
-BasepConvertPriorityClass(IN ULONG dwCreationFlags)
+BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles)
 {
-    ULONG ReturnClass;
+    NTSTATUS Status;
 
-    if(dwCreationFlags & IDLE_PRIORITY_CLASS)
-    {
-        ReturnClass = PROCESS_PRIORITY_CLASS_IDLE;
-    }
-    else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
-    {
-        ReturnClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
-    }
-    else if(dwCreationFlags & NORMAL_PRIORITY_CLASS)
+    /* Sanity checks */
+    ASSERT(Handles != NULL);
+    ASSERT(Handles->Process == NULL || Handles->Process == NtCurrentProcess());
+
+    /* Close the file handle */
+    if (Handles->File)
     {
-        ReturnClass = PROCESS_PRIORITY_CLASS_NORMAL;
+        Status = NtClose(Handles->File);
+        ASSERT(NT_SUCCESS(Status));
     }
-    else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
+
+    /* Close the section handle */
+    if (Handles->Section)
     {
-        ReturnClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
+        Status = NtClose(Handles->Section);
+        ASSERT(NT_SUCCESS(Status));
     }
-    else if(dwCreationFlags & HIGH_PRIORITY_CLASS)
+
+    /* Unmap the section view */
+    if (Handles->ViewBase.QuadPart)
     {
-        ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
+        Status = NtUnmapViewOfSection(NtCurrentProcess(),
+                                      (PVOID)Handles->ViewBase.LowPart);
+        ASSERT(NT_SUCCESS(Status));
     }
-    else if(dwCreationFlags & REALTIME_PRIORITY_CLASS)
+}
+
+static
+LONG BaseExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo)
+{
+    LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
+    LPTOP_LEVEL_EXCEPTION_FILTER RealFilter;
+    RealFilter = RtlDecodePointer(GlobalTopLevelExceptionFilter);
+
+    if (RealFilter != NULL)
     {
-        /* Check for Privilege First */
-        if (BasepIsRealtimeAllowed(TRUE))
+        _SEH2_TRY
         {
-            ReturnClass = PROCESS_PRIORITY_CLASS_REALTIME;
+            ExceptionDisposition = RealFilter(ExceptionInfo);
         }
-        else
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
         }
+        _SEH2_END;
     }
-    else
+    if ((ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH || ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER) &&
+        RealFilter != UnhandledExceptionFilter)
     {
-        ReturnClass = PROCESS_PRIORITY_CLASS_INVALID;
+       ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
     }
 
-    return ReturnClass;
+    return ExceptionDisposition;
 }
 
-/*
- * Duplicates a standard handle and writes it where requested.
- */
 VOID
 WINAPI
-BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle,
-                             IN HANDLE StandardHandle,
-                             IN PHANDLE Address)
+BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress)
 {
-    NTSTATUS Status;
-    HANDLE DuplicatedHandle;
-    SIZE_T Dummy;
-
-    DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
-           "Address: %p\n", ProcessHandle, StandardHandle, Address);
+    DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
 
-    /* Don't touch Console Handles */
-    if (IsConsoleHandle(StandardHandle)) return;
+    _SEH2_TRY
+    {
+        /* Set our Start Address */
+        NtSetInformationThread(NtCurrentThread(),
+                               ThreadQuerySetWin32StartAddress,
+                               &lpStartAddress,
+                               sizeof(PPROCESS_START_ROUTINE));
 
-    /* Duplicate the handle */
-    Status = NtDuplicateObject(NtCurrentProcess(),
-                               StandardHandle,
-                               ProcessHandle,
-                               &DuplicatedHandle,
-                               DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES,
-                               0,
-                               0);
-    if (NT_SUCCESS(Status))
+        /* Call the Start Routine */
+        ExitThread(lpStartAddress());
+    }
+    _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
     {
-        /* Write it */
-        NtWriteVirtualMemory(ProcessHandle,
-                             Address,
-                             &DuplicatedHandle,
-                             sizeof(HANDLE),
-                             &Dummy);
+        /* Get the Exit code from the SEH Handler */
+        if (!BaseRunningInServerProcess)
+        {
+            /* Kill the whole process, usually */
+            ExitProcess(_SEH2_GetExceptionCode());
+        }
+        else
+        {
+            /* If running inside CSRSS, kill just this thread */
+            ExitThread(_SEH2_GetExceptionCode());
+        }
     }
+    _SEH2_END;
 }
 
-LPWSTR
+NTSTATUS
 WINAPI
-BasepGetProcessPath(DWORD Reserved,
-                    LPWSTR FullPath,
-                    PVOID Environment)
+BasepNotifyCsrOfThread(IN HANDLE ThreadHandle,
+                       IN PCLIENT_ID ClientId)
 {
     NTSTATUS Status;
-    LPWSTR AllocatedPath = NULL, ch;
-    ULONG DefaultLength = BaseDefaultPath.Length;
-    ULONG AppLength = 0;
-    UNICODE_STRING EnvPath;
-    LPWSTR NamePtr;
-    LPWSTR PathBuffer;
-    BOOLEAN SecondAttempt = FALSE;
-    PPEB Peb = NtCurrentPeb();
+    BASE_API_MESSAGE ApiMessage;
+    PBASE_CREATE_THREAD CreateThreadRequest = &ApiMessage.Data.CreateThreadRequest;
 
-    if (!Environment) RtlAcquirePebLock();
+    DPRINT("BasepNotifyCsrOfThread: Thread: %p, Handle %p\n",
+            ClientId->UniqueThread, ThreadHandle);
 
-    /* Query PATH env var into append path */
-    Status = RtlQueryEnvironmentVariable_U(Environment,
-                                           &BasePathVariableName,
-                                           &BaseDefaultPathAppend);
-    if (NT_SUCCESS(Status))
-    {
-        /* Add up PATH environment length */
-        DefaultLength += BaseDefaultPathAppend.Length;
-    }
-    else if (Status == STATUS_BUFFER_TOO_SMALL)
-    {
-        /* We have to allocate path dynamically */
-        AllocatedPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, BaseDefaultPathAppend.Length + sizeof(UNICODE_NULL));
+    /* Fill out the request */
+    CreateThreadRequest->ClientId = *ClientId;
+    CreateThreadRequest->ThreadHandle = ThreadHandle;
 
-        if (AllocatedPath)
-        {
-            /* Set up EnvPath */
-            EnvPath.Buffer = AllocatedPath;
-            EnvPath.Length = BaseDefaultPathAppend.Length + sizeof(UNICODE_NULL);
-            EnvPath.MaximumLength = EnvPath.Length;
-
-            /* Query PATH env var into newly allocated path */
-            Status = RtlQueryEnvironmentVariable_U(Environment,
-                                                   &BasePathVariableName,
-                                                   &EnvPath);
-
-            if (NT_SUCCESS(Status))
-            {
-                DefaultLength += EnvPath.Length;
-            }
-            else
-            {
-                /* Free newly allocated path, it didn't work */
-                RtlFreeHeap(RtlGetProcessHeap(), 0, AllocatedPath);
-                AllocatedPath = NULL;
-                Status = STATUS_NO_MEMORY;
-            }
-        }
-    }
-
-secondattempt:
-    if (!FullPath)
-    {
-        /* Initialize BasepExeLdrEntry if necessary */
-        if (!BasepExeLdrEntry)
-            LdrEnumerateLoadedModules(0, BasepLocateExeLdrEntry, Peb->ImageBaseAddress);
-
-        DPRINT("Found BasepExeLdrEntry %wZ\n", &BasepExeLdrEntry->FullDllName);
-
-        /* Set name pointer to the full dll path */
-        NamePtr = BasepExeLdrEntry->FullDllName.Buffer;
-    }
-    else
-    {
-        /* Set name pointer to the provided path */
-        NamePtr = FullPath;
-    }
-
-    /* Determine application path length */
-    if (NamePtr)
-    {
-        ch = NamePtr;
-        while (*ch)
-        {
-            /* Check if there is a slash */
-            if (*ch == L'\\')
-            {
-                /* Update app length */
-                AppLength = (ULONG_PTR)ch - (ULONG_PTR)NamePtr + sizeof(WCHAR);
-            }
-
-            ch++;
-        }
-    }
-
-    /* Now check, if we found a valid path in the provided full path */
-    if (!AppLength && FullPath && !SecondAttempt)
-    {
-        /* We were provided with a bad full path, retry again using just this app's path */
-        FullPath = NULL;
-        SecondAttempt = TRUE;
-        goto secondattempt;
-    }
-
-    /* Allocate the path buffer */
-    PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, DefaultLength + AppLength + 2*sizeof(WCHAR));
-    if (!PathBuffer)
-    {
-        /* Fail */
-        if (!Environment) RtlReleasePebLock();
-        if (AllocatedPath) RtlFreeHeap(RtlGetProcessHeap(), 0, AllocatedPath);
-        return NULL;
-    }
-
-    /* Copy contents there */
-    if (AppLength)
-    {
-        /* Remove trailing slashes if it's not root dir */
-        if (AppLength != 3*sizeof(WCHAR))
-            AppLength -= sizeof(WCHAR);
-
-        /* Copy contents */
-        RtlMoveMemory(PathBuffer, NamePtr, AppLength);
-    }
-
-    /* Release the lock */
-    if (!Environment) RtlReleasePebLock();
-
-    /* Finish preparing the path string */
-    NamePtr = &PathBuffer[AppLength / sizeof(WCHAR)];
-
-    /* Put a separating ";" if something was added */
-    if (AppLength)
-    {
-        *NamePtr = L';';
-        NamePtr++;
-    }
-
-    if (AllocatedPath)
-    {
-        /* Dynamically allocated env path, copy from the static buffer,
-           concatenate with dynamic buffer and free it */
-        RtlMoveMemory(NamePtr, BaseDefaultPath.Buffer, BaseDefaultPath.Length);
-        RtlMoveMemory(&NamePtr[BaseDefaultPath.Length / sizeof(WCHAR)], AllocatedPath, EnvPath.Length);
-
-        /* Free it */
-        RtlFreeHeap(RtlGetProcessHeap(), 0, AllocatedPath);
-    }
-    else
-    {
-        /* Static env path string, copy directly from BaseDefaultPath */
-        RtlMoveMemory(NamePtr, BaseDefaultPath.Buffer, DefaultLength);
-    }
-
-    /* Null terminate the string */
-    NamePtr[DefaultLength / sizeof(WCHAR)] = 0;
-
-    return PathBuffer;
-}
-
-LPWSTR
-WINAPI
-BasepGetDllPath(LPWSTR FullPath,
-                PVOID Environment)
-{
-#if 0
-    LPWSTR DllPath = NULL;
-
-    /* Acquire DLL directory lock */
-    RtlEnterCriticalSection(&BaseDllDirectoryLock);
-
-    /* Check if we have a base dll directory */
-    if (BaseDllDirectory.Buffer)
+    /* Call CSR */
+    Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+                                 NULL,
+                                 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepCreateThread),
+                                 sizeof(BASE_CREATE_THREAD));
+    if (!NT_SUCCESS(Status))
     {
-        /* Then get process path */
-        DllPath = BasepGetProcessPath(0, FullPath, Environment);
-
-        /* Release DLL directory lock */
-        RtlLeaveCriticalSection(&BaseDllDirectoryLock);
-
-        /* Return dll path */
-        return DllPath;
+        DPRINT1("Failed to tell CSRSS about new thread: %lx\n", Status);
+        return Status;
     }
 
-    /* Release DLL directory lock */
-    RtlLeaveCriticalSection(&BaseDllDirectoryLock);
-
-    /* There is no base DLL directory */
-    UNIMPLEMENTED;
-
-    /* Return dll path */
-    return DllPath;
-#else
-    return BasepGetProcessPath(0, FullPath, Environment);
-#endif
-}
-
-VOID
-WINAPI
-BasepCopyHandles(IN PRTL_USER_PROCESS_PARAMETERS Params,
-                 IN PRTL_USER_PROCESS_PARAMETERS PebParams,
-                 IN BOOL InheritHandles)
-{
-    DPRINT("BasepCopyHandles %p %p, %d\n", Params, PebParams, InheritHandles);
-
-    /* Copy the handle if we are inheriting or if it's a console handle */
-    if (InheritHandles || IsConsoleHandle(PebParams->StandardInput))
-    {
-        Params->StandardInput = PebParams->StandardInput;
-    }
-    if (InheritHandles || IsConsoleHandle(PebParams->StandardOutput))
-    {
-        Params->StandardOutput = PebParams->StandardOutput;
-    }
-    if (InheritHandles || IsConsoleHandle(PebParams->StandardError))
-    {
-        Params->StandardError = PebParams->StandardError;
-    }
+    /* Return Success */
+    return STATUS_SUCCESS;
 }
 
-NTSTATUS
+BOOLEAN
 WINAPI
-BasepInitializeEnvironment(HANDLE ProcessHandle,
-                           PPEB Peb,
-                           LPWSTR ApplicationPathName,
-                           LPWSTR lpCurrentDirectory,
-                           LPWSTR lpCommandLine,
-                           LPVOID lpEnvironment,
-                           SIZE_T EnvSize,
-                           LPSTARTUPINFOW StartupInfo,
-                           DWORD CreationFlags,
-                           BOOL InheritHandles)
+BasePushProcessParameters(IN ULONG ParameterFlags,
+                          IN HANDLE ProcessHandle,
+                          IN PPEB RemotePeb,
+                          IN LPCWSTR ApplicationPathName,
+                          IN LPWSTR lpCurrentDirectory,
+                          IN LPWSTR lpCommandLine,
+                          IN LPVOID lpEnvironment,
+                          IN LPSTARTUPINFOW StartupInfo,
+                          IN DWORD CreationFlags,
+                          IN BOOL InheritHandles,
+                          IN ULONG ImageSubsystem,
+                          IN PVOID AppCompatData,
+                          IN ULONG AppCompatDataSize)
 {
-    WCHAR FullPath[MAX_PATH];
-    LPWSTR Remaining;
-    LPWSTR DllPathString;
-    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
-    PRTL_USER_PROCESS_PARAMETERS RemoteParameters = NULL;
+    WCHAR FullPath[MAX_PATH + 5];
+    PWCHAR Remaining, DllPathString, ScanChar;
+    PRTL_USER_PROCESS_PARAMETERS ProcessParameters, RemoteParameters;
+    PVOID RemoteAppCompatData;
     UNICODE_STRING DllPath, ImageName, CommandLine, CurrentDirectory;
+    UNICODE_STRING Desktop, Shell, Runtime, Title;
     NTSTATUS Status;
-    PWCHAR ScanChar;
     ULONG EnviroSize;
     SIZE_T Size;
-    UNICODE_STRING Desktop, Shell, Runtime, Title;
-    PPEB OurPeb = NtCurrentPeb();
-    LPVOID Environment = lpEnvironment;
-
-    DPRINT("BasepInitializeEnvironment\n");
+    BOOLEAN HavePebLock = FALSE, Result;
+    PPEB Peb = NtCurrentPeb();
 
     /* Get the full path name */
-    GetFullPathNameW(ApplicationPathName,
-                     MAX_PATH,
-                     FullPath,
-                     &Remaining);
-    DPRINT("ApplicationPathName: %S, FullPath: %S\n", ApplicationPathName,
-            FullPath);
+    Size = GetFullPathNameW(ApplicationPathName,
+                            MAX_PATH + 4,
+                            FullPath,
+                            &Remaining);
+    if ((Size) && (Size <= (MAX_PATH + 4)))
+    {
+        /* Get the DLL Path */
+        DllPathString = BaseComputeProcessDllPath(FullPath, lpEnvironment);
+        if (!DllPathString)
+        {
+            /* Fail */
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
 
-    /* Get the DLL Path */
-    DllPathString = BasepGetDllPath(FullPath, Environment);
+        /* Initialize Strings */
+        RtlInitUnicodeString(&DllPath, DllPathString);
+        RtlInitUnicodeString(&ImageName, FullPath);
+    }
+    else
+    {
+        /* Couldn't get the path name. Just take the original path */
+        DllPathString = BaseComputeProcessDllPath((LPWSTR)ApplicationPathName,
+                                                  lpEnvironment);
+        if (!DllPathString)
+        {
+            /* Fail */
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
+
+        /* Initialize Strings */
+        RtlInitUnicodeString(&DllPath, DllPathString);
+        RtlInitUnicodeString(&ImageName, ApplicationPathName);
+    }
 
     /* Initialize Strings */
-    RtlInitUnicodeString(&DllPath, DllPathString);
-    RtlInitUnicodeString(&ImageName, FullPath);
     RtlInitUnicodeString(&CommandLine, lpCommandLine);
     RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory);
 
@@ -661,95 +617,93 @@ BasepInitializeEnvironment(HANDLE ProcessHandle,
     }
     else
     {
-        RtlInitUnicodeString(&Title, L"");
+        RtlInitUnicodeString(&Title, ApplicationPathName);
     }
 
     /* This one is special because the length can differ */
     Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2;
     Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2;
 
+    /* Enforce no app compat data if the pointer was NULL */
+    if (!AppCompatData) AppCompatDataSize = 0;
+
     /* Create the Parameter Block */
-    DPRINT("Creating Process Parameters: %wZ %wZ %wZ %wZ %wZ %wZ %wZ\n",
-            &ImageName, &DllPath, &CommandLine, &Desktop, &Title, &Shell,
-            &Runtime);
+    ProcessParameters = NULL;
+    DPRINT("ImageName: '%wZ'\n", &ImageName);
+    DPRINT("DllPath  : '%wZ'\n", &DllPath);
+    DPRINT("CurDir   : '%wZ'\n", &CurrentDirectory);
+    DPRINT("CmdLine  : '%wZ'\n", &CommandLine);
+    DPRINT("Title    : '%wZ'\n", &Title);
+    DPRINT("Desktop  : '%wZ'\n", &Desktop);
+    DPRINT("Shell    : '%wZ'\n", &Shell);
+    DPRINT("Runtime  : '%wZ'\n", &Runtime);
     Status = RtlCreateProcessParameters(&ProcessParameters,
                                         &ImageName,
                                         &DllPath,
                                         lpCurrentDirectory ?
                                         &CurrentDirectory : NULL,
                                         &CommandLine,
-                                        Environment,
+                                        lpEnvironment,
                                         &Title,
                                         &Desktop,
                                         &Shell,
                                         &Runtime);
+    if (!NT_SUCCESS(Status)) goto FailPath;
 
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("Failed to create process parameters!\n");
-        return Status;
-    }
+    /* Clear the current directory handle if not inheriting */
+    if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL;
 
-    /* Check if we got an environment. If not, use ours */
-    if (Environment)
+    /* Check if the user passed in an environment */
+    if (lpEnvironment)
     {
-        /* Save pointer and start lookup */
-        Environment = ScanChar = ProcessParameters->Environment;
+        /* We should've made it part of the parameters block, enforce this */
+        ASSERT(ProcessParameters->Environment == lpEnvironment);
+        lpEnvironment = ProcessParameters->Environment;
     }
     else
     {
-        /* Save pointer and start lookup */
-        Environment = ScanChar = OurPeb->ProcessParameters->Environment;
+        /* The user did not, so use the one from the current PEB */
+        HavePebLock = TRUE;
+        RtlAcquirePebLock();
+        lpEnvironment = Peb->ProcessParameters->Environment;
     }
 
-    /* Find the environment size */
-    if (ScanChar)
+    /* Save pointer and start lookup */
+    ScanChar = lpEnvironment;
+    if (lpEnvironment)
     {
-        if (EnvSize && Environment == lpEnvironment)
-        {
-            /* its a converted ansi environment, bypass the length calculation */
-            EnviroSize = EnvSize;
-        }
-        else
-        {
-            while (*ScanChar)
-            {
-                ScanChar += wcslen(ScanChar) + 1;
-            }
-
-            /* Calculate the size of the block */
-            if (ScanChar == Environment)
-            {
-                EnviroSize = 2 * sizeof(WCHAR);
-            }
-            else
-            {
-                EnviroSize = (ULONG)((ULONG_PTR)ScanChar - (ULONG_PTR)Environment + sizeof(WCHAR));
-            }
-        }
-        DPRINT("EnvironmentSize %ld\n", EnviroSize);
+        /* Find the environment size */
+        while (*ScanChar++) while (*ScanChar++);
+        EnviroSize = (ULONG)((ULONG_PTR)ScanChar - (ULONG_PTR)lpEnvironment);
 
         /* Allocate and Initialize new Environment Block */
         Size = EnviroSize;
         ProcessParameters->Environment = NULL;
-        Status = ZwAllocateVirtualMemory(ProcessHandle,
+        Status = NtAllocateVirtualMemory(ProcessHandle,
                                          (PVOID*)&ProcessParameters->Environment,
                                          0,
                                          &Size,
                                          MEM_COMMIT,
                                          PAGE_READWRITE);
-        if (!NT_SUCCESS(Status))
+        if (!NT_SUCCESS(Status)) goto FailPath;
+
+        /* Write the Environment Block */
+        Status = NtWriteVirtualMemory(ProcessHandle,
+                                      ProcessParameters->Environment,
+                                      lpEnvironment,
+                                      EnviroSize,
+                                      NULL);
+
+        /* No longer need the PEB lock anymore */
+        if (HavePebLock)
         {
-            DPRINT1("Failed to allocate Environment Block\n");
-            return(Status);
+            /* Release it */
+            RtlReleasePebLock();
+            HavePebLock = FALSE;
         }
 
-        /* Write the Environment Block */
-        ZwWriteVirtualMemory(ProcessHandle,
-                             ProcessParameters->Environment,
-                             Environment,
-                             EnviroSize,
-                             NULL);
+        /* Check if the write failed */
+        if (!NT_SUCCESS(Status)) goto FailPath;
     }
 
     /* Write new parameters */
@@ -764,76 +718,96 @@ BasepInitializeEnvironment(HANDLE ProcessHandle,
     ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow;
 
     /* Write the handles only if we have to */
-    if (StartupInfo->dwFlags & STARTF_USESTDHANDLES)
+    if (StartupInfo->dwFlags &
+        (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))
     {
-        DPRINT("Using Standard Handles\n");
         ProcessParameters->StandardInput = StartupInfo->hStdInput;
         ProcessParameters->StandardOutput = StartupInfo->hStdOutput;
         ProcessParameters->StandardError = StartupInfo->hStdError;
     }
 
-    /* Use Special Flags for ConDllInitialize in Kernel32 */
+    /* Use Special Flags for BasepInitConsole in Kernel32 */
     if (CreationFlags & DETACHED_PROCESS)
     {
         ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS;
     }
-    else if (CreationFlags & CREATE_NO_WINDOW)
-    {
-        ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW;
-    }
     else if (CreationFlags & CREATE_NEW_CONSOLE)
     {
         ProcessParameters->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE;
     }
+    else if (CreationFlags & CREATE_NO_WINDOW)
+    {
+        ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW;
+    }
     else
     {
         /* Inherit our Console Handle */
-        ProcessParameters->ConsoleHandle = OurPeb->ProcessParameters->ConsoleHandle;
+        ProcessParameters->ConsoleHandle = Peb->ProcessParameters->ConsoleHandle;
 
-        /* Is the shell trampling on our Handles? */
+        /* Make sure that the shell isn't trampling on our handles first */
         if (!(StartupInfo->dwFlags &
-              (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
+             (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
         {
-            /* Use handles from PEB, if inheriting or they are console */
-            DPRINT("Copying handles from parent\n");
-            BasepCopyHandles(ProcessParameters,
-                             OurPeb->ProcessParameters,
-                             InheritHandles);
+            /* Copy the handle if we are inheriting or if it's a console handle */
+            if ((InheritHandles) ||
+                (IsConsoleHandle(Peb->ProcessParameters->StandardInput)))
+            {
+                ProcessParameters->StandardInput = Peb->ProcessParameters->StandardInput;
+            }
+            if ((InheritHandles) ||
+                (IsConsoleHandle(Peb->ProcessParameters->StandardOutput)))
+            {
+                ProcessParameters->StandardOutput = Peb->ProcessParameters->StandardOutput;
+            }
+            if ((InheritHandles) ||
+                (IsConsoleHandle(Peb->ProcessParameters->StandardError)))
+            {
+                ProcessParameters->StandardError = Peb->ProcessParameters->StandardError;
+            }
         }
     }
 
     /* Also set the Console Flag */
-    if (CreationFlags & CREATE_NEW_PROCESS_GROUP)
+    if ((CreationFlags & CREATE_NEW_PROCESS_GROUP) &&
+        (!(CreationFlags & CREATE_NEW_CONSOLE)))
     {
         ProcessParameters->ConsoleFlags = 1;
     }
 
+    /* Check if there's a .local file present */
+    if (ParameterFlags & 1)
+    {
+        ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH;
+    }
+
+    /* Check if we failed to open the IFEO key */
+    if (ParameterFlags & 2)
+    {
+        ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_IMAGE_KEY_MISSING;
+    }
+
     /* Allocate memory for the parameter block */
     Size = ProcessParameters->Length;
+    RemoteParameters = NULL;
     Status = NtAllocateVirtualMemory(ProcessHandle,
                                      (PVOID*)&RemoteParameters,
                                      0,
                                      &Size,
                                      MEM_COMMIT,
                                      PAGE_READWRITE);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("Failed to allocate Parameters Block\n");
-        return(Status);
-    }
+    if (!NT_SUCCESS(Status)) goto FailPath;
 
     /* Set the allocated size */
     ProcessParameters->MaximumLength = Size;
 
     /* Handle some Parameter Flags */
-    ProcessParameters->ConsoleFlags = (CreationFlags & CREATE_NEW_PROCESS_GROUP);
     ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ?
                                  RTL_USER_PROCESS_PARAMETERS_PROFILE_USER : 0;
     ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ?
                                  RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL : 0;
     ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ?
                                  RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER : 0;
-    ProcessParameters->Flags |= (NtCurrentPeb()->ProcessParameters->Flags &
+    ProcessParameters->Flags |= (Peb->ProcessParameters->Flags &
                                  RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS);
 
     /* Write the Parameter Block */
@@ -842,88 +816,104 @@ BasepInitializeEnvironment(HANDLE ProcessHandle,
                                   ProcessParameters,
                                   ProcessParameters->Length,
                                   NULL);
+    if (!NT_SUCCESS(Status)) goto FailPath;
 
     /* Write the PEB Pointer */
     Status = NtWriteVirtualMemory(ProcessHandle,
-                                  &Peb->ProcessParameters,
+                                  &RemotePeb->ProcessParameters,
                                   &RemoteParameters,
                                   sizeof(PVOID),
                                   NULL);
+    if (!NT_SUCCESS(Status)) goto FailPath;
 
-    /* Cleanup */
-    RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath.Buffer);
-    RtlDestroyProcessParameters(ProcessParameters);
-
-    DPRINT("Completed\n");
-    return STATUS_SUCCESS;
-}
+    /* Check if there's any app compat data to write */
+    RemoteAppCompatData = NULL;
+    if (AppCompatData)
+    {
+        /* Allocate some space for the application compatibility data */
+        Size = AppCompatDataSize;
+        Status = NtAllocateVirtualMemory(ProcessHandle,
+                                         &RemoteAppCompatData,
+                                         0,
+                                         &Size,
+                                         MEM_COMMIT,
+                                         PAGE_READWRITE);
+        if (!NT_SUCCESS(Status)) goto FailPath;
 
-VOID
-WINAPI
-InitCommandLines(VOID)
-{
-    PRTL_USER_PROCESS_PARAMETERS Params;
+        /* Write the application compatibility data */
+        Status = NtWriteVirtualMemory(ProcessHandle,
+                                      RemoteAppCompatData,
+                                      AppCompatData,
+                                      AppCompatDataSize,
+                                      NULL);
+        if (!NT_SUCCESS(Status)) goto FailPath;
+    }
 
-    /* get command line */
-    Params = NtCurrentPeb()->ProcessParameters;
-    RtlNormalizeProcessParams (Params);
+    /* Write the PEB Pointer to the app compat data (might be NULL) */
+    Status = NtWriteVirtualMemory(ProcessHandle,
+                                  &RemotePeb->pShimData,
+                                  &RemoteAppCompatData,
+                                  sizeof(PVOID),
+                                  NULL);
+    if (!NT_SUCCESS(Status)) goto FailPath;
 
-    /* initialize command line buffers */
-    CommandLineStringW.Length = Params->CommandLine.Length;
-    CommandLineStringW.MaximumLength = CommandLineStringW.Length + sizeof(WCHAR);
-    CommandLineStringW.Buffer = RtlAllocateHeap(GetProcessHeap(),
-                                                HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY,
-                                                CommandLineStringW.MaximumLength);
-    if (CommandLineStringW.Buffer == NULL)
+    /* Now write Peb->ImageSubSystem */
+    if (ImageSubsystem)
     {
-        return;
+        NtWriteVirtualMemory(ProcessHandle,
+                             &RemotePeb->ImageSubsystem,
+                             &ImageSubsystem,
+                             sizeof(ImageSubsystem),
+                             NULL);
     }
 
-    RtlInitAnsiString(&CommandLineStringA, NULL);
+    /* Success path */
+    Result = TRUE;
 
-    /* Copy command line */
-    RtlCopyUnicodeString(&CommandLineStringW,
-                         &(Params->CommandLine));
-    CommandLineStringW.Buffer[CommandLineStringW.Length / sizeof(WCHAR)] = 0;
+Quickie:
+    /* Cleanup */
+    if (HavePebLock) RtlReleasePebLock();
+    RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath.Buffer);
+    if (ProcessParameters) RtlDestroyProcessParameters(ProcessParameters);
+    return Result;
+FailPath:
+    DPRINT1("Failure to create process parameters: %lx\n", Status);
+    BaseSetLastNTError(Status);
+    Result = FALSE;
+    goto Quickie;
+}
 
-    /* convert unicode string to ansi (or oem) */
-    if (bIsFileApiAnsi)
-        RtlUnicodeStringToAnsiString(&CommandLineStringA,
-                                     &CommandLineStringW,
-                                     TRUE);
-    else
-        RtlUnicodeStringToOemString(&CommandLineStringA,
-                                    &CommandLineStringW,
-                                    TRUE);
+VOID
+WINAPI
+InitCommandLines(VOID)
+{
+    NTSTATUS Status;
 
-    CommandLineStringA.Buffer[CommandLineStringA.Length] = 0;
+    /* Read the UNICODE_STRING from the PEB */
+    BaseUnicodeCommandLine = NtCurrentPeb()->ProcessParameters->CommandLine;
 
-    bCommandLineInitialized = TRUE;
+    /* Convert to ANSI_STRING for the *A callers */
+    Status = RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine,
+                                          &BaseUnicodeCommandLine,
+                                          TRUE);
+    if (!NT_SUCCESS(Status)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine, 0, 0);
 }
 
+/* PUBLIC FUNCTIONS ***********************************************************/
+
 /*
  * @implemented
  */
 BOOL
 WINAPI
-GetProcessAffinityMask(HANDLE hProcess,
-                       PDWORD_PTR lpProcessAffinityMask,
-                       PDWORD_PTR lpSystemAffinityMask)
+GetProcessAffinityMask(IN HANDLE hProcess,
+                       OUT PDWORD_PTR lpProcessAffinityMask,
+                       OUT PDWORD_PTR lpSystemAffinityMask)
 {
     PROCESS_BASIC_INFORMATION ProcessInfo;
-    SYSTEM_BASIC_INFORMATION SystemInfo;
     NTSTATUS Status;
 
-    Status = NtQuerySystemInformation(SystemBasicInformation,
-                                      &SystemInfo,
-                                      sizeof(SystemInfo),
-                                      NULL);
-    if (!NT_SUCCESS(Status))
-    {
-        BaseSetLastNTError(Status);
-        return FALSE;
-    }
-
+    /* Query information on the process from the kernel */
     Status = NtQueryInformationProcess(hProcess,
                                        ProcessBasicInformation,
                                        (PVOID)&ProcessInfo,
@@ -931,174 +921,239 @@ GetProcessAffinityMask(HANDLE hProcess,
                                        NULL);
     if (!NT_SUCCESS(Status))
     {
+        /* Fail */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* Copy the affinity mask, and get the system one from our shared data */
     *lpProcessAffinityMask = (DWORD)ProcessInfo.AffinityMask;
-    *lpSystemAffinityMask = (DWORD)SystemInfo.ActiveProcessorsAffinityMask;
-
+    *lpSystemAffinityMask = (DWORD)BaseStaticServerData->SysInfo.ActiveProcessorsAffinityMask;
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-SetProcessAffinityMask(HANDLE hProcess,
-                       DWORD_PTR dwProcessAffinityMask)
+SetProcessAffinityMask(IN HANDLE hProcess,
+                       IN DWORD_PTR dwProcessAffinityMask)
 {
     NTSTATUS Status;
 
+    /* Directly set the affinity mask */
     Status = NtSetInformationProcess(hProcess,
                                      ProcessAffinityMask,
                                      (PVOID)&dwProcessAffinityMask,
                                      sizeof(DWORD));
     if (!NT_SUCCESS(Status))
     {
+        /* Handle failure */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* Everything was ok */
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-GetProcessShutdownParameters(LPDWORD lpdwLevel,
-                             LPDWORD lpdwFlags)
+GetProcessShutdownParameters(OUT LPDWORD lpdwLevel,
+                             OUT LPDWORD lpdwFlags)
 {
-    CSR_API_MESSAGE CsrRequest;
-    ULONG Request;
     NTSTATUS Status;
+    BASE_API_MESSAGE ApiMessage;
+    PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest = &ApiMessage.Data.ShutdownParametersRequest;
 
-    Request = GET_SHUTDOWN_PARAMETERS;
-    Status = CsrClientCallServer(&CsrRequest,
+    /* Ask CSRSS for shutdown information */
+    Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
                                  NULL,
-                                 MAKE_CSR_API(Request, CSR_NATIVE),
-                                 sizeof(CSR_API_MESSAGE));
-    if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
+                                 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetProcessShutdownParam),
+                                 sizeof(BASE_GETSET_PROCESS_SHUTDOWN_PARAMS));
+    if (!NT_SUCCESS(Status))
     {
+        /* Return the failure from CSRSS */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
-    *lpdwLevel = CsrRequest.Data.GetShutdownParametersRequest.Level;
-    *lpdwFlags = CsrRequest.Data.GetShutdownParametersRequest.Flags;
-
+    /* Get the data back */
+    *lpdwLevel = ShutdownParametersRequest->ShutdownLevel;
+    *lpdwFlags = ShutdownParametersRequest->ShutdownFlags;
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-SetProcessShutdownParameters(DWORD dwLevel,
-                             DWORD dwFlags)
+SetProcessShutdownParameters(IN DWORD dwLevel,
+                             IN DWORD dwFlags)
 {
-    CSR_API_MESSAGE CsrRequest;
-    ULONG Request;
     NTSTATUS Status;
+    BASE_API_MESSAGE ApiMessage;
+    PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest = &ApiMessage.Data.ShutdownParametersRequest;
 
-    CsrRequest.Data.SetShutdownParametersRequest.Level = dwLevel;
-    CsrRequest.Data.SetShutdownParametersRequest.Flags = dwFlags;
-
-    Request = SET_SHUTDOWN_PARAMETERS;
-    Status = CsrClientCallServer(&CsrRequest,
+    /* Write the data into the CSRSS request and send it */
+    ShutdownParametersRequest->ShutdownLevel = dwLevel;
+    ShutdownParametersRequest->ShutdownFlags = dwFlags;
+    Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
                                  NULL,
-                                 MAKE_CSR_API(Request, CSR_NATIVE),
-                                 sizeof(CSR_API_MESSAGE));
-    if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
+                                 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetProcessShutdownParam),
+                                 sizeof(BASE_GETSET_PROCESS_SHUTDOWN_PARAMS));
+    if (!NT_SUCCESS(Status))
     {
+        /* Return the failure from CSRSS */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* All went well */
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-GetProcessWorkingSetSize(HANDLE hProcess,
-                         PSIZE_T lpMinimumWorkingSetSize,
-                         PSIZE_T lpMaximumWorkingSetSize)
+GetProcessWorkingSetSizeEx(IN HANDLE hProcess,
+                           OUT PSIZE_T lpMinimumWorkingSetSize,
+                           OUT PSIZE_T lpMaximumWorkingSetSize,
+                           OUT PDWORD Flags)
 {
-    QUOTA_LIMITS QuotaLimits;
+    QUOTA_LIMITS_EX QuotaLimits;
     NTSTATUS Status;
 
+    /* Query the kernel about this */
     Status = NtQueryInformationProcess(hProcess,
                                        ProcessQuotaLimits,
                                        &QuotaLimits,
-                                       sizeof(QUOTA_LIMITS),
+                                       sizeof(QUOTA_LIMITS_EX),
                                        NULL);
     if (!NT_SUCCESS(Status))
     {
+        /* Return error */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* Copy the quota information out */
     *lpMinimumWorkingSetSize = QuotaLimits.MinimumWorkingSetSize;
     *lpMaximumWorkingSetSize = QuotaLimits.MaximumWorkingSetSize;
-
+    *Flags = QuotaLimits.Flags;
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-SetProcessWorkingSetSize(HANDLE hProcess,
-                         SIZE_T dwMinimumWorkingSetSize,
-                         SIZE_T dwMaximumWorkingSetSize)
+GetProcessWorkingSetSize(IN HANDLE hProcess,
+                         OUT PSIZE_T lpMinimumWorkingSetSize,
+                         OUT PSIZE_T lpMaximumWorkingSetSize)
 {
-    QUOTA_LIMITS QuotaLimits;
-    NTSTATUS Status;
-
-    QuotaLimits.MinimumWorkingSetSize = dwMinimumWorkingSetSize;
-    QuotaLimits.MaximumWorkingSetSize = dwMaximumWorkingSetSize;
+    DWORD Dummy;
+    return GetProcessWorkingSetSizeEx(hProcess,
+                                      lpMinimumWorkingSetSize,
+                                      lpMaximumWorkingSetSize,
+                                      &Dummy);
+}
 
-    Status = NtSetInformationProcess(hProcess,
-                                     ProcessQuotaLimits,
-                                     &QuotaLimits,
-                                     sizeof(QUOTA_LIMITS));
-    if (!NT_SUCCESS(Status))
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetProcessWorkingSetSizeEx(IN HANDLE hProcess,
+                           IN SIZE_T dwMinimumWorkingSetSize,
+                           IN SIZE_T dwMaximumWorkingSetSize,
+                           IN DWORD Flags)
+{
+    QUOTA_LIMITS_EX QuotaLimits;
+    NTSTATUS Status, ReturnStatus;
+    BOOL Result;
+    PVOID State;
+    ULONG Privilege = SE_INC_BASE_PRIORITY_PRIVILEGE;
+
+    /* Zero out the input structure */
+    RtlZeroMemory(&QuotaLimits, sizeof(QuotaLimits));
+
+    /* Check if the caller sent any limits */
+    if ((dwMinimumWorkingSetSize) && (dwMaximumWorkingSetSize))
+    {
+        /* Write the quota information */
+        QuotaLimits.MinimumWorkingSetSize = dwMinimumWorkingSetSize;
+        QuotaLimits.MaximumWorkingSetSize = dwMaximumWorkingSetSize;
+        QuotaLimits.Flags = Flags;
+
+        /* Acquire the required privilege */
+        Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
+
+        /* Request the new quotas */
+        ReturnStatus = NtSetInformationProcess(hProcess,
+                                               ProcessQuotaLimits,
+                                               &QuotaLimits,
+                                               sizeof(QuotaLimits));
+        Result = NT_SUCCESS(ReturnStatus);
+        if (NT_SUCCESS(Status))
+        {
+            /* Release the privilege and set succes code */
+            ASSERT(State != NULL);
+            RtlReleasePrivilege(State);
+            State = NULL;
+        }
+    }
+    else
     {
-        BaseSetLastNTError(Status);
-        return FALSE;
+        /* No limits, fail the call */
+        ReturnStatus = STATUS_INVALID_PARAMETER;
+        Result = FALSE;
     }
 
-    return TRUE;
+    /* Return result code, set error code if this was a failure */
+    if (!Result) BaseSetLastNTError(ReturnStatus);
+    return Result;
 }
 
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetProcessWorkingSetSize(IN HANDLE hProcess,
+                         IN SIZE_T dwMinimumWorkingSetSize,
+                         IN SIZE_T dwMaximumWorkingSetSize)
+{
+    /* Call the newer API */
+    return SetProcessWorkingSetSizeEx(hProcess,
+                                      dwMinimumWorkingSetSize,
+                                      dwMaximumWorkingSetSize,
+                                      0);
+}
 
 /*
  * @implemented
  */
 BOOL
 WINAPI
-GetProcessTimes(HANDLE hProcess,
-                LPFILETIME lpCreationTime,
-                LPFILETIME lpExitTime,
-                LPFILETIME lpKernelTime,
-                LPFILETIME lpUserTime)
+GetProcessTimes(IN HANDLE hProcess,
+                IN LPFILETIME lpCreationTime,
+                IN LPFILETIME lpExitTime,
+                IN LPFILETIME lpKernelTime,
+                IN LPFILETIME lpUserTime)
 {
     KERNEL_USER_TIMES Kut;
     NTSTATUS Status;
 
+    /* Query the times */
     Status = NtQueryInformationProcess(hProcess,
                                        ProcessTimes,
                                        &Kut,
@@ -1106,26 +1161,23 @@ GetProcessTimes(HANDLE hProcess,
                                        NULL);
     if (!NT_SUCCESS(Status))
     {
+        /* Handle failure */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* Copy all the times and return success */
     lpCreationTime->dwLowDateTime = Kut.CreateTime.u.LowPart;
     lpCreationTime->dwHighDateTime = Kut.CreateTime.u.HighPart;
-
     lpExitTime->dwLowDateTime = Kut.ExitTime.u.LowPart;
     lpExitTime->dwHighDateTime = Kut.ExitTime.u.HighPart;
-
     lpKernelTime->dwLowDateTime = Kut.KernelTime.u.LowPart;
     lpKernelTime->dwHighDateTime = Kut.KernelTime.u.HighPart;
-
     lpUserTime->dwLowDateTime = Kut.UserTime.u.LowPart;
     lpUserTime->dwHighDateTime = Kut.UserTime.u.HighPart;
-
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
@@ -1136,7 +1188,6 @@ GetCurrentProcess(VOID)
     return (HANDLE)NtCurrentProcess();
 }
 
-
 /*
  * @implemented
  */
@@ -1147,7 +1198,6 @@ GetCurrentThread(VOID)
     return (HANDLE)NtCurrentThread();
 }
 
-
 /*
  * @implemented
  */
@@ -1155,21 +1205,21 @@ DWORD
 WINAPI
 GetCurrentProcessId(VOID)
 {
-    return HandleToUlong(GetTeb()->ClientId.UniqueProcess);
+    return HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess);
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-GetExitCodeProcess(HANDLE hProcess,
-                   LPDWORD lpExitCode)
+GetExitCodeProcess(IN HANDLE hProcess,
+                   IN LPDWORD lpExitCode)
 {
     PROCESS_BASIC_INFORMATION ProcessBasic;
     NTSTATUS Status;
 
+    /* Ask the kernel */
     Status = NtQueryInformationProcess(hProcess,
                                        ProcessBasicInformation,
                                        &ProcessBasic,
@@ -1177,26 +1227,30 @@ GetExitCodeProcess(HANDLE hProcess,
                                        NULL);
     if (!NT_SUCCESS(Status))
     {
+        /* We failed, was this because this is a VDM process? */
+        if (BaseCheckForVDM(hProcess, lpExitCode) == TRUE) return TRUE;
+
+        /* Not a VDM process, fail the call */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* Succes case, return the exit code */
     *lpExitCode = (DWORD)ProcessBasic.ExitStatus;
-
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 DWORD
 WINAPI
-GetProcessId(HANDLE Process)
+GetProcessId(IN HANDLE Process)
 {
     PROCESS_BASIC_INFORMATION ProcessBasic;
     NTSTATUS Status;
 
+    /* Query the kernel */
     Status = NtQueryInformationProcess(Process,
                                        ProcessBasicInformation,
                                        &ProcessBasic,
@@ -1204,105 +1258,65 @@ GetProcessId(HANDLE Process)
                                        NULL);
     if (!NT_SUCCESS(Status))
     {
+        /* Handle failure */
         BaseSetLastNTError(Status);
         return 0;
     }
 
+    /* Return the PID */
     return (DWORD)ProcessBasic.UniqueProcessId;
 }
 
-
 /*
  * @implemented
  */
 HANDLE
 WINAPI
-OpenProcess(DWORD dwDesiredAccess,
-            BOOL bInheritHandle,
-            DWORD dwProcessId)
+OpenProcess(IN DWORD dwDesiredAccess,
+            IN BOOL bInheritHandle,
+            IN DWORD dwProcessId)
 {
-    NTSTATUS errCode;
+    NTSTATUS Status;
     HANDLE ProcessHandle;
     OBJECT_ATTRIBUTES ObjectAttributes;
     CLIENT_ID ClientId;
 
+    /* Setup the input client ID structure */
     ClientId.UniqueProcess = UlongToHandle(dwProcessId);
     ClientId.UniqueThread = 0;
 
+    /* This is needed just to define the inheritance flags */
     InitializeObjectAttributes(&ObjectAttributes,
                                NULL,
                                (bInheritHandle ? OBJ_INHERIT : 0),
                                NULL,
                                NULL);
 
-    errCode = NtOpenProcess(&ProcessHandle,
-                            dwDesiredAccess,
-                            &ObjectAttributes,
-                            &ClientId);
-    if (!NT_SUCCESS(errCode))
+    /* Now try to open the process */
+    Status = NtOpenProcess(&ProcessHandle,
+                           dwDesiredAccess,
+                           &ObjectAttributes,
+                           &ClientId);
+    if (!NT_SUCCESS(Status))
     {
-        BaseSetLastNTError(errCode);
+        /* Handle failure */
+        BaseSetLastNTError(Status);
         return NULL;
     }
 
+    /* Otherwise return a handle to the process */
     return ProcessHandle;
 }
 
-
-/*
- * @implemented
- */
-UINT
-WINAPI
-WinExec(LPCSTR lpCmdLine,
-        UINT uCmdShow)
-{
-    STARTUPINFOA StartupInfo;
-    PROCESS_INFORMATION  ProcessInformation;
-    DWORD dosErr;
-
-    RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
-    StartupInfo.cb = sizeof(STARTUPINFOA);
-    StartupInfo.wShowWindow = (WORD)uCmdShow;
-    StartupInfo.dwFlags = 0;
-
-    if (!CreateProcessA(NULL,
-                        (PVOID)lpCmdLine,
-                        NULL,
-                        NULL,
-                        FALSE,
-                        0,
-                        NULL,
-                        NULL,
-                        &StartupInfo,
-                        &ProcessInformation))
-    {
-        dosErr = GetLastError();
-        return dosErr < 32 ? dosErr : ERROR_BAD_FORMAT;
-    }
-
-    if (NULL != lpfnGlobalRegisterWaitForInputIdle)
-    {
-        lpfnGlobalRegisterWaitForInputIdle(ProcessInformation.hProcess,
-                                           10000);
-    }
-
-    NtClose(ProcessInformation.hProcess);
-    NtClose(ProcessInformation.hThread);
-
-    return 33; /* Something bigger than 31 means success. */
-}
-
-
 /*
  * @implemented
  */
 VOID
 WINAPI
-RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle)
+RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle)
 {
-    lpfnGlobalRegisterWaitForInputIdle = lpfnRegisterWaitForInputIdle;
-    return;
+    /* Write the global function pointer */
+    UserWaitForInputIdleRoutine = lpfnRegisterWaitForInputIdle;
 }
 
 /*
@@ -1310,19 +1324,16 @@ RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle)
  */
 VOID
 WINAPI
-GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo)
+GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo)
 {
     PRTL_USER_PROCESS_PARAMETERS Params;
 
-    if (lpStartupInfo == NULL)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return;
-    }
-
+    /* Get the process parameters */
     Params = NtCurrentPeb()->ProcessParameters;
 
+    /* Copy the data out of there */
     lpStartupInfo->cb = sizeof(STARTUPINFOW);
+    lpStartupInfo->lpReserved = Params->ShellInfo.Buffer;
     lpStartupInfo->lpDesktop = Params->DesktopInfo.Buffer;
     lpStartupInfo->lpTitle = Params->WindowTitle.Buffer;
     lpStartupInfo->dwX = Params->StartingX;
@@ -1337,298 +1348,396 @@ GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo)
     lpStartupInfo->cbReserved2 = Params->RuntimeData.Length;
     lpStartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer;
 
-    lpStartupInfo->hStdInput = Params->StandardInput;
-    lpStartupInfo->hStdOutput = Params->StandardOutput;
-    lpStartupInfo->hStdError = Params->StandardError;
+    /* Check if the standard handles are being used for other features */
+    if (lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES |
+                                  STARTF_USEHOTKEY |
+                                  STARTF_SHELLPRIVATE))
+    {
+        /* These are, so copy the standard handles too */
+        lpStartupInfo->hStdInput = Params->StandardInput;
+        lpStartupInfo->hStdOutput = Params->StandardOutput;
+        lpStartupInfo->hStdError = Params->StandardError;
+    }
 }
 
-
 /*
  * @implemented
  */
 VOID
 WINAPI
-GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo)
+GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo)
 {
     PRTL_USER_PROCESS_PARAMETERS Params;
-    ANSI_STRING AnsiString;
-
-    if (lpStartupInfo == NULL)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return;
-    }
-
-    Params = NtCurrentPeb ()->ProcessParameters;
+    ANSI_STRING TitleString, ShellString, DesktopString;
+    LPSTARTUPINFOA StartupInfo;
+    NTSTATUS Status;
 
-    RtlAcquirePebLock ();
+    /* Get the cached information as well as the PEB parameters */
+    StartupInfo = BaseAnsiStartupInfo;
+    Params = NtCurrentPeb()->ProcessParameters;
 
-    /* FIXME - not thread-safe */
-    if (lpLocalStartupInfo == NULL)
+    /* Check if this is the first time we have to get the cached version */
+    while (!StartupInfo)
     {
-        /* create new local startup info (ansi) */
-        lpLocalStartupInfo = RtlAllocateHeap(RtlGetProcessHeap(),
-                                             0,
-                                             sizeof(STARTUPINFOA));
-        if (lpLocalStartupInfo == NULL)
+        /* Create new ANSI startup info */
+        StartupInfo = RtlAllocateHeap(RtlGetProcessHeap(),
+                                      0,
+                                      sizeof(*StartupInfo));
+        if (StartupInfo)
         {
-            RtlReleasePebLock();
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            return;
-        }
-
-        lpLocalStartupInfo->cb = sizeof(STARTUPINFOA);
-
-        /* copy window title string */
-        RtlUnicodeStringToAnsiString(&AnsiString,
-                                     &Params->WindowTitle,
-                                     TRUE);
-        lpLocalStartupInfo->lpTitle = AnsiString.Buffer;
-
-        /* copy desktop info string */
-        RtlUnicodeStringToAnsiString(&AnsiString,
-                                     &Params->DesktopInfo,
-                                     TRUE);
-        lpLocalStartupInfo->lpDesktop = AnsiString.Buffer;
-
-        /* copy shell info string */
-        RtlUnicodeStringToAnsiString(&AnsiString,
-                                     &Params->ShellInfo,
-                                     TRUE);
-        lpLocalStartupInfo->lpReserved = AnsiString.Buffer;
-
-        lpLocalStartupInfo->dwX = Params->StartingX;
-        lpLocalStartupInfo->dwY = Params->StartingY;
-        lpLocalStartupInfo->dwXSize = Params->CountX;
-        lpLocalStartupInfo->dwYSize = Params->CountY;
-        lpLocalStartupInfo->dwXCountChars = Params->CountCharsX;
-        lpLocalStartupInfo->dwYCountChars = Params->CountCharsY;
-        lpLocalStartupInfo->dwFillAttribute = Params->FillAttribute;
-        lpLocalStartupInfo->dwFlags = Params->WindowFlags;
-        lpLocalStartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags;
-        lpLocalStartupInfo->cbReserved2 = Params->RuntimeData.Length;
-        lpLocalStartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer;
-
-        lpLocalStartupInfo->hStdInput = Params->StandardInput;
-        lpLocalStartupInfo->hStdOutput = Params->StandardOutput;
-        lpLocalStartupInfo->hStdError = Params->StandardError;
-    }
-
-    RtlReleasePebLock();
-
-    /* copy local startup info data to external startup info */
-    memcpy(lpStartupInfo,
-           lpLocalStartupInfo,
-           sizeof(STARTUPINFOA));
-}
+            /* Zero out string pointers in case we fail to create them */
+            StartupInfo->lpReserved = 0;
+            StartupInfo->lpDesktop = 0;
+            StartupInfo->lpTitle = 0;
+
+            /* Set the size */
+            StartupInfo->cb = sizeof(*StartupInfo);
+
+            /* Copy what's already stored in the PEB */
+            StartupInfo->dwX = Params->StartingX;
+            StartupInfo->dwY = Params->StartingY;
+            StartupInfo->dwXSize = Params->CountX;
+            StartupInfo->dwYSize = Params->CountY;
+            StartupInfo->dwXCountChars = Params->CountCharsX;
+            StartupInfo->dwYCountChars = Params->CountCharsY;
+            StartupInfo->dwFillAttribute = Params->FillAttribute;
+            StartupInfo->dwFlags = Params->WindowFlags;
+            StartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags;
+            StartupInfo->cbReserved2 = Params->RuntimeData.Length;
+            StartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer;
+            StartupInfo->hStdInput = Params->StandardInput;
+            StartupInfo->hStdOutput = Params->StandardOutput;
+            StartupInfo->hStdError = Params->StandardError;
+
+            /* Copy shell info string */
+            Status = RtlUnicodeStringToAnsiString(&ShellString,
+                                                  &Params->ShellInfo,
+                                                  TRUE);
+            if (NT_SUCCESS(Status))
+            {
+                /* Save it */
+                StartupInfo->lpReserved = ShellString.Buffer;
+
+                /* Copy desktop info string */
+                Status = RtlUnicodeStringToAnsiString(&DesktopString,
+                                                      &Params->DesktopInfo,
+                                                      TRUE);
+                if (NT_SUCCESS(Status))
+                {
+                    /* Save it */
+                    StartupInfo->lpDesktop = DesktopString.Buffer;
+
+                    /* Copy window title string */
+                    Status = RtlUnicodeStringToAnsiString(&TitleString,
+                                                          &Params->WindowTitle,
+                                                          TRUE);
+                    if (NT_SUCCESS(Status))
+                    {
+                        /* Save it */
+                        StartupInfo->lpTitle = TitleString.Buffer;
+
+                        /* We finished with the ANSI version, try to cache it */
+                        if (!InterlockedCompareExchangePointer(&BaseAnsiStartupInfo,
+                                                               StartupInfo,
+                                                               NULL))
+                        {
+                            /* We were the first thread through, use the data */
+                            break;
+                        }
+
+                        /* Someone beat us to it, use their data instead */
+                        StartupInfo = BaseAnsiStartupInfo;
+                        Status = STATUS_SUCCESS;
+
+                        /* We're going to free our own stuff, but not raise */
+                        RtlFreeAnsiString(&TitleString);
+                    }
+                    RtlFreeAnsiString(&DesktopString);
+                }
+                RtlFreeAnsiString(&ShellString);
+            }
+            RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo);
+        }
+        else
+        {
+            /* No memory, fail */
+            Status = STATUS_NO_MEMORY;
+        }
 
+        /* Raise an error unless we got here due to the race condition */
+        if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status);
+    }
+
+    /* Now copy from the cached ANSI version */
+    lpStartupInfo->cb = StartupInfo->cb;
+    lpStartupInfo->lpReserved = StartupInfo->lpReserved;
+    lpStartupInfo->lpDesktop = StartupInfo->lpDesktop;
+    lpStartupInfo->lpTitle = StartupInfo->lpTitle;
+    lpStartupInfo->dwX = StartupInfo->dwX;
+    lpStartupInfo->dwY = StartupInfo->dwY;
+    lpStartupInfo->dwXSize = StartupInfo->dwXSize;
+    lpStartupInfo->dwYSize = StartupInfo->dwYSize;
+    lpStartupInfo->dwXCountChars = StartupInfo->dwXCountChars;
+    lpStartupInfo->dwYCountChars = StartupInfo->dwYCountChars;
+    lpStartupInfo->dwFillAttribute = StartupInfo->dwFillAttribute;
+    lpStartupInfo->dwFlags = StartupInfo->dwFlags;
+    lpStartupInfo->wShowWindow = StartupInfo->wShowWindow;
+    lpStartupInfo->cbReserved2 = StartupInfo->cbReserved2;
+    lpStartupInfo->lpReserved2 = StartupInfo->lpReserved2;
+
+    /* Check if the shell is hijacking the handles for other features */
+    if (lpStartupInfo->dwFlags &
+        (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))
+    {
+        /* It isn't, so we can return the raw values */
+        lpStartupInfo->hStdInput = StartupInfo->hStdInput;
+        lpStartupInfo->hStdOutput = StartupInfo->hStdOutput;
+        lpStartupInfo->hStdError = StartupInfo->hStdError;
+    }
+    else
+    {
+        /* It is, so make sure nobody uses these as console handles */
+        lpStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
+        lpStartupInfo->hStdOutput = INVALID_HANDLE_VALUE;
+        lpStartupInfo->hStdError = INVALID_HANDLE_VALUE;
+    }
+}
 
 /*
  * @implemented
  */
 BOOL
 WINAPI
-FlushInstructionCache(HANDLE hProcess,
-                      LPCVOID lpBaseAddress,
-                      SIZE_T dwSize)
+FlushInstructionCache(IN HANDLE hProcess,
+                      IN LPCVOID lpBaseAddress,
+                      IN SIZE_T dwSize)
 {
     NTSTATUS Status;
 
-    Status = NtFlushInstructionCache(hProcess,
-                                     (PVOID)lpBaseAddress,
-                                     dwSize);
+    /* Call the native function */
+    Status = NtFlushInstructionCache(hProcess, (PVOID)lpBaseAddress, dwSize);
     if (!NT_SUCCESS(Status))
     {
+        /* Handle failure case */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* All good */
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 VOID
 WINAPI
-ExitProcess(UINT uExitCode)
+ExitProcess(IN UINT uExitCode)
 {
-    CSR_API_MESSAGE CsrRequest;
-    ULONG Request;
-    NTSTATUS Status;
+    BASE_API_MESSAGE ApiMessage;
+    PBASE_EXIT_PROCESS ExitProcessRequest = &ApiMessage.Data.ExitProcessRequest;
+
+    ASSERT(!BaseRunningInServerProcess);
+
+    _SEH2_TRY
+    {
+        /* Acquire the PEB lock */
+        RtlAcquirePebLock();
 
-    /* kill sibling threads ... we want to be alone at this point */
-    NtTerminateProcess(NULL, 0);
+        /* Kill all the threads */
+        NtTerminateProcess(NULL, 0);
 
-    /* unload all dll's */
-    LdrShutdownProcess();
+        /* Unload all DLLs */
+        LdrShutdownProcess();
 
-    /* notify csrss of process termination */
-    Request = TERMINATE_PROCESS;
-    Status = CsrClientCallServer(&CsrRequest,
-                                 NULL,
-                                 MAKE_CSR_API(Request, CSR_NATIVE),
-                                 sizeof(CSR_API_MESSAGE));
-    if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
+        /* Notify Base Server of process termination */
+        ExitProcessRequest->uExitCode = uExitCode;
+        CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+                            NULL,
+                            CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepExitProcess),
+                            sizeof(BASE_EXIT_PROCESS));
+
+        /* Now do it again */
+        NtTerminateProcess(NtCurrentProcess(), uExitCode);
+    }
+    _SEH2_FINALLY
     {
-        DPRINT("Failed to tell csrss about terminating process\n");
+        /* Release the PEB lock */
+        RtlReleasePebLock();
     }
-
-    NtTerminateProcess(NtCurrentProcess (),
-                       uExitCode);
+    _SEH2_END;
 
     /* should never get here */
     ASSERT(0);
     while(1);
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-TerminateProcess(HANDLE hProcess,
-                 UINT uExitCode)
+TerminateProcess(IN HANDLE hProcess,
+                 IN UINT uExitCode)
 {
     NTSTATUS Status;
 
-    if (hProcess == NULL)
+    /* Check if no handle was passed in */
+    if (!hProcess)
     {
-      return FALSE;
+        /* Set error code */
+        SetLastError(ERROR_INVALID_HANDLE);
     }
-
-    Status = NtTerminateProcess(hProcess, uExitCode);
-    if (NT_SUCCESS(Status))
+    else
     {
-        return TRUE;
+        /* Otherwise, try to terminate the process */
+        Status = NtTerminateProcess(hProcess, uExitCode);
+        if (NT_SUCCESS(Status)) return TRUE;
+
+        /* It failed, convert error code */
+        BaseSetLastNTError(Status);
     }
 
-    BaseSetLastNTError(Status);
+    /* This is the failure path */
     return FALSE;
 }
 
-
 /*
- * @unimplemented
+ * @implemented
  */
 VOID
 WINAPI
 FatalAppExitA(UINT uAction,
               LPCSTR lpMessageText)
 {
-    UNICODE_STRING MessageTextU;
+    PUNICODE_STRING MessageTextU;
     ANSI_STRING MessageText;
+    NTSTATUS Status;
 
+    /* Initialize the string using the static TEB pointer */
+    MessageTextU = &NtCurrentTeb()->StaticUnicodeString;
     RtlInitAnsiString(&MessageText, (LPSTR)lpMessageText);
 
-    RtlAnsiStringToUnicodeString(&MessageTextU,
-                                 &MessageText,
-                                 TRUE);
-
-    FatalAppExitW(uAction, MessageTextU.Buffer);
+    /* Convert to unicode and just exit normally if this failed */
+    Status = RtlAnsiStringToUnicodeString(MessageTextU, &MessageText, FALSE);
+    if (!NT_SUCCESS(Status)) ExitProcess(0);
 
-    RtlFreeUnicodeString(&MessageTextU);
+    /* Call the Wide function */
+    FatalAppExitW(uAction, MessageTextU->Buffer);
 }
 
-
 /*
- * @unimplemented
+ * @implemented
  */
 VOID
 WINAPI
-FatalAppExitW(UINT uAction,
-              LPCWSTR lpMessageText)
+FatalAppExitW(IN UINT uAction,
+              IN LPCWSTR lpMessageText)
 {
-    static const WCHAR szUser32[] = L"user32.dll\0";
-
-    HMODULE hModule = GetModuleHandleW(szUser32);
-    MessageBoxW_Proc pMessageBoxW = NULL;
+    UNICODE_STRING UnicodeString;
+    ULONG Response;
+    NTSTATUS Status;
 
-    DPRINT1("AppExit\n");
+    /* Setup the string to print out */
+    RtlInitUnicodeString(&UnicodeString, lpMessageText);
 
-    if (hModule)
-        pMessageBoxW = (MessageBoxW_Proc)GetProcAddress(hModule, "MessageBoxW");
+    /* Display the hard error no matter what */
+    Status = NtRaiseHardError(STATUS_FATAL_APP_EXIT | HARDERROR_OVERRIDE_ERRORMODE,
+                              1,
+                              1,
+                              (PULONG_PTR)&UnicodeString,
+                              OptionOkCancel,
+                              &Response);
 
-    if (pMessageBoxW)
-        pMessageBoxW(0, lpMessageText, NULL, MB_SYSTEMMODAL | MB_OK);
-    else
-        DPRINT1("%s\n", lpMessageText);
+    /* Give the user a chance to abort */
+    if ((NT_SUCCESS(Status)) && (Response == ResponseCancel)) return;
 
+    /* Otherwise kill the process */
     ExitProcess(0);
 }
 
-
 /*
  * @implemented
  */
 VOID
 WINAPI
-FatalExit(int ExitCode)
+FatalExit(IN int ExitCode)
 {
+#if DBG
+    /* On Checked builds, Windows gives you a nice little debugger UI */
+    CHAR ch[2];
+    DbgPrint("FatalExit...\n");
+    DbgPrint("\n");
+
+    while (TRUE)
+    {
+        DbgPrompt( "A (Abort), B (Break), I (Ignore)? ", ch, sizeof(ch));
+        switch (ch[0])
+        {
+            case 'B': case 'b':
+                 DbgBreakPoint();
+                 break;
+
+            case 'A': case 'a':
+                ExitProcess(ExitCode);
+
+            case 'I': case 'i':
+                return;
+        }
+    }
+#endif
+    /* On other builds, just kill the process */
     ExitProcess(ExitCode);
 }
 
-
 /*
  * @implemented
  */
 DWORD
 WINAPI
-GetPriorityClass(HANDLE hProcess)
+GetPriorityClass(IN HANDLE hProcess)
 {
-  NTSTATUS Status;
-  PROCESS_PRIORITY_CLASS PriorityClass;
+    NTSTATUS Status;
+    PROCESS_PRIORITY_CLASS PriorityClass;
 
-  Status = NtQueryInformationProcess(hProcess,
-                                     ProcessPriorityClass,
-                                     &PriorityClass,
-                                     sizeof(PROCESS_PRIORITY_CLASS),
-                                     NULL);
-  if(NT_SUCCESS(Status))
-  {
-    switch(PriorityClass.PriorityClass)
+    /* Query the kernel */
+    Status = NtQueryInformationProcess(hProcess,
+                                       ProcessPriorityClass,
+                                       &PriorityClass,
+                                       sizeof(PROCESS_PRIORITY_CLASS),
+                                       NULL);
+    if (NT_SUCCESS(Status))
     {
-      case PROCESS_PRIORITY_CLASS_IDLE:
-        return IDLE_PRIORITY_CLASS;
-
-      case PROCESS_PRIORITY_CLASS_BELOW_NORMAL:
-        return BELOW_NORMAL_PRIORITY_CLASS;
-
-      case PROCESS_PRIORITY_CLASS_NORMAL:
-        return NORMAL_PRIORITY_CLASS;
-
-      case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL:
-        return ABOVE_NORMAL_PRIORITY_CLASS;
-
-      case PROCESS_PRIORITY_CLASS_HIGH:
-        return HIGH_PRIORITY_CLASS;
-
-      case PROCESS_PRIORITY_CLASS_REALTIME:
-        return REALTIME_PRIORITY_CLASS;
-
-      default:
-        return NORMAL_PRIORITY_CLASS;
+        /* Handle the conversion from NT to Win32 classes */
+        switch (PriorityClass.PriorityClass)
+        {
+            case PROCESS_PRIORITY_CLASS_IDLE: return IDLE_PRIORITY_CLASS;
+            case PROCESS_PRIORITY_CLASS_BELOW_NORMAL: return BELOW_NORMAL_PRIORITY_CLASS;
+            case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL: return ABOVE_NORMAL_PRIORITY_CLASS;
+            case PROCESS_PRIORITY_CLASS_HIGH: return HIGH_PRIORITY_CLASS;
+            case PROCESS_PRIORITY_CLASS_REALTIME: return REALTIME_PRIORITY_CLASS;
+            case PROCESS_PRIORITY_CLASS_NORMAL: default: return NORMAL_PRIORITY_CLASS;
+        }
     }
-  }
 
-  BaseSetLastNTError(Status);
-  return FALSE;
+    /* Failure path */
+    BaseSetLastNTError(Status);
+    return FALSE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-SetPriorityClass(HANDLE hProcess,
-                 DWORD dwPriorityClass)
+SetPriorityClass(IN HANDLE hProcess,
+                 IN DWORD dwPriorityClass)
 {
     NTSTATUS Status;
+    PVOID State = NULL;
     PROCESS_PRIORITY_CLASS PriorityClass;
 
+    /* Handle conversion from Win32 to NT priority classes */
     switch (dwPriorityClass)
     {
         case IDLE_PRIORITY_CLASS:
@@ -1652,68 +1761,85 @@ SetPriorityClass(HANDLE hProcess,
             break;
 
         case REALTIME_PRIORITY_CLASS:
-            PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME;
+            /* Try to acquire the privilege. If it fails, just use HIGH */
+            State = BasepIsRealtimeAllowed(TRUE);
+            PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
+            PriorityClass.PriorityClass += (State != NULL);
             break;
 
         default:
+            /* Unrecognized priority classes don't make it to the kernel */
             SetLastError(ERROR_INVALID_PARAMETER);
             return FALSE;
     }
 
+    /* Send the request to the kernel, and don't touch the foreground flag */
     PriorityClass.Foreground = FALSE;
-
     Status = NtSetInformationProcess(hProcess,
                                      ProcessPriorityClass,
                                      &PriorityClass,
                                      sizeof(PROCESS_PRIORITY_CLASS));
+
+    /* Release the privilege if we had it */
+    if (State) RtlReleasePrivilege(State);
     if (!NT_SUCCESS(Status))
     {
+        /* Handle error path */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* All done */
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 DWORD
 WINAPI
-GetProcessVersion(DWORD ProcessId)
+GetProcessVersion(IN DWORD ProcessId)
 {
     DWORD Version = 0;
-    PIMAGE_NT_HEADERS NtHeader = NULL;
-    IMAGE_NT_HEADERS NtHeaders;
-    IMAGE_DOS_HEADER DosHeader;
+    PIMAGE_NT_HEADERS NtHeader;
+    PIMAGE_DOS_HEADER DosHeader;
+    PPEB Peb;
     PROCESS_BASIC_INFORMATION ProcessBasicInfo;
-    PVOID BaseAddress = NULL;
+    PVOID BaseAddress;
+    ULONG e_lfanew;
     HANDLE ProcessHandle = NULL;
     NTSTATUS Status;
-    SIZE_T Count;
-    PEB Peb;
+    USHORT VersionData[2];
+    BOOLEAN Result;
 
+    /* We'll be accessing stuff that can fault, so protect everything with SEH */
     _SEH2_TRY
     {
-        if (0 == ProcessId || GetCurrentProcessId() == ProcessId)
+        /* It this an in-process or out-of-process request? */
+        if (!(ProcessId) || (GetCurrentProcessId() == ProcessId))
         {
-            /* Caller's */
-            BaseAddress = (PVOID) NtCurrentPeb()->ImageBaseAddress;
-            NtHeader = RtlImageNtHeader(BaseAddress);
+            /* It's in-process, so just read our own header */
+            NtHeader = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
+            if (!NtHeader)
+            {
+                /* Unable to read the NT header, something is wrong here... */
+                Status = STATUS_INVALID_IMAGE_FORMAT;
+                goto Error;
+            }
 
-            Version = (NtHeader->OptionalHeader.MajorOperatingSystemVersion << 16) |
-                      (NtHeader->OptionalHeader.MinorOperatingSystemVersion);
+            /* Get the version straight out of the NT header */
+            Version = MAKELONG(NtHeader->OptionalHeader.MinorSubsystemVersion,
+                               NtHeader->OptionalHeader.MajorSubsystemVersion);
         }
         else
         {
-            /* Other process */
+            /* Out-of-process, so open it */
             ProcessHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
                                         FALSE,
                                         ProcessId);
+            if (!ProcessHandle) _SEH2_YIELD(return 0);
 
-            if (!ProcessHandle) return 0;
-
+            /* Try to find out where its PEB lives */
             Status = NtQueryInformationProcess(ProcessHandle,
                                                ProcessBasicInformation,
                                                &ProcessBasicInfo,
@@ -1721,65 +1847,64 @@ GetProcessVersion(DWORD ProcessId)
                                                NULL);
 
             if (!NT_SUCCESS(Status)) goto Error;
+            Peb = ProcessBasicInfo.PebBaseAddress;
 
-            Status = NtReadVirtualMemory(ProcessHandle,
-                                         ProcessBasicInfo.PebBaseAddress,
-                                         &Peb,
-                                         sizeof(Peb),
-                                         &Count);
-
-            if (!NT_SUCCESS(Status) || Count != sizeof(Peb)) goto Error;
-
-            memset(&DosHeader, 0, sizeof(DosHeader));
-            Status = NtReadVirtualMemory(ProcessHandle,
-                                         Peb.ImageBaseAddress,
-                                         &DosHeader,
-                                         sizeof(DosHeader),
-                                         &Count);
-
-            if (!NT_SUCCESS(Status) || Count != sizeof(DosHeader)) goto Error;
-            if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) goto Error;
-
-            memset(&NtHeaders, 0, sizeof(NtHeaders));
-            Status = NtReadVirtualMemory(ProcessHandle,
-                                         (char *)Peb.ImageBaseAddress + DosHeader.e_lfanew,
-                                         &NtHeaders,
-                                         sizeof(NtHeaders),
-                                         &Count);
-
-            if (!NT_SUCCESS(Status) || Count != sizeof(NtHeaders)) goto Error;
-            if (NtHeaders.Signature != IMAGE_NT_SIGNATURE) goto Error;
+            /* Now that we have the PEB, read the image base address out of it */
+            Result = ReadProcessMemory(ProcessHandle,
+                                       &Peb->ImageBaseAddress,
+                                       &BaseAddress,
+                                       sizeof(BaseAddress),
+                                       NULL);
+            if (!Result) goto Error;
+
+            /* Now read the e_lfanew (offset to NT header) from the base */
+            DosHeader = BaseAddress;
+            Result = ReadProcessMemory(ProcessHandle,
+                                       &DosHeader->e_lfanew,
+                                       &e_lfanew,
+                                       sizeof(e_lfanew),
+                                       NULL);
+            if (!Result) goto Error;
+
+            /* And finally, read the NT header itself by adding the offset */
+            NtHeader = (PVOID)((ULONG_PTR)BaseAddress + e_lfanew);
+            Result = ReadProcessMemory(ProcessHandle,
+                                       &NtHeader->OptionalHeader.MajorSubsystemVersion,
+                                       &VersionData,
+                                       sizeof(VersionData),
+                                       NULL);
+            if (!Result) goto Error;
 
-            Version = MAKELONG(NtHeaders.OptionalHeader.MinorSubsystemVersion,
-                               NtHeaders.OptionalHeader.MajorSubsystemVersion);
+            /* Get the version straight out of the NT header */
+            Version = MAKELONG(VersionData[0], VersionData[1]);
 
 Error:
-            if (!NT_SUCCESS(Status))
-            {
-                BaseSetLastNTError(Status);
-            }
+            /* If there was an error anywhere, set the last error */
+            if (!NT_SUCCESS(Status)) BaseSetLastNTError(Status);
         }
     }
     _SEH2_FINALLY
     {
+        /* Close the process handle */
         if (ProcessHandle) CloseHandle(ProcessHandle);
     }
     _SEH2_END;
 
+    /* And return the version data */
     return Version;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-GetProcessIoCounters(HANDLE hProcess,
-                     PIO_COUNTERS lpIoCounters)
+GetProcessIoCounters(IN HANDLE hProcess,
+                     OUT PIO_COUNTERS lpIoCounters)
 {
     NTSTATUS Status;
 
+    /* Query the kernel. Structures are identical, so let it do the copy too. */
     Status = NtQueryInformationProcess(hProcess,
                                        ProcessIoCounters,
                                        lpIoCounters,
@@ -1787,25 +1912,27 @@ GetProcessIoCounters(HANDLE hProcess,
                                        NULL);
     if (!NT_SUCCESS(Status))
     {
+        /* Handle error path */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* All done */
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-GetProcessPriorityBoost(HANDLE hProcess,
-                        PBOOL pDisablePriorityBoost)
+GetProcessPriorityBoost(IN HANDLE hProcess,
+                        OUT PBOOL pDisablePriorityBoost)
 {
     NTSTATUS Status;
     ULONG PriorityBoost;
 
+    /* Query the kernel */
     Status = NtQueryInformationProcess(hProcess,
                                        ProcessPriorityBoost,
                                        &PriorityBoost,
@@ -1813,78 +1940,85 @@ GetProcessPriorityBoost(HANDLE hProcess,
                                        NULL);
     if (NT_SUCCESS(Status))
     {
-        *pDisablePriorityBoost = PriorityBoost;
+        /* Convert from ULONG to a BOOL */
+        *pDisablePriorityBoost = PriorityBoost ? TRUE : FALSE;
         return TRUE;
     }
 
+    /* Handle error path */
     BaseSetLastNTError(Status);
     return FALSE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-SetProcessPriorityBoost(HANDLE hProcess,
-                        BOOL bDisablePriorityBoost)
+SetProcessPriorityBoost(IN HANDLE hProcess,
+                        IN BOOL bDisablePriorityBoost)
 {
     NTSTATUS Status;
-    ULONG PriorityBoost = (bDisablePriorityBoost ? TRUE : FALSE); /* prevent setting values other than 1 and 0 */
+    ULONG PriorityBoost;
 
+    /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */
+    PriorityBoost = (bDisablePriorityBoost ? TRUE : FALSE);
     Status = NtSetInformationProcess(hProcess,
                                      ProcessPriorityBoost,
                                      &PriorityBoost,
                                      sizeof(ULONG));
     if (!NT_SUCCESS(Status))
     {
+        /* Handle error path */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* All done */
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-GetProcessHandleCount(HANDLE hProcess,
-                      PDWORD pdwHandleCount)
+GetProcessHandleCount(IN HANDLE hProcess,
+                      OUT PDWORD pdwHandleCount)
 {
     ULONG phc;
     NTSTATUS Status;
 
+    /* Query the kernel */
     Status = NtQueryInformationProcess(hProcess,
                                        ProcessHandleCount,
                                        &phc,
                                        sizeof(ULONG),
                                        NULL);
-    if(NT_SUCCESS(Status))
+    if (NT_SUCCESS(Status))
     {
-      *pdwHandleCount = phc;
-      return TRUE;
+        /* Copy the count and return sucecss */
+        *pdwHandleCount = phc;
+        return TRUE;
     }
 
+    /* Handle error path */
     BaseSetLastNTError(Status);
     return FALSE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-IsWow64Process(HANDLE hProcess,
-               PBOOL Wow64Process)
+IsWow64Process(IN HANDLE hProcess,
+               OUT PBOOL Wow64Process)
 {
     ULONG_PTR pbi;
     NTSTATUS Status;
 
+    /* Query the kernel */
     Status = NtQueryInformationProcess(hProcess,
                                        ProcessWow64Information,
                                        &pbi,
@@ -1892,12 +2026,13 @@ IsWow64Process(HANDLE hProcess,
                                        NULL);
     if (!NT_SUCCESS(Status))
     {
-        SetLastError(RtlNtStatusToDosError(Status));
+        /* Handle error path */
+        BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* Enforce this is a BOOL, and return success */
     *Wow64Process = (pbi != 0);
-
     return TRUE;
 }
 
@@ -1908,11 +2043,9 @@ LPSTR
 WINAPI
 GetCommandLineA(VOID)
 {
-    DPRINT("CommandLine \'%s\'\n", CommandLineStringA.Buffer);
-    return CommandLineStringA.Buffer;
+    return BaseAnsiCommandLine.Buffer;
 }
 
-
 /*
  * @implemented
  */
@@ -1920,8 +2053,7 @@ LPWSTR
 WINAPI
 GetCommandLineW(VOID)
 {
-    DPRINT("CommandLine \'%S\'\n", CommandLineStringW.Buffer);
-    return CommandLineStringW.Buffer;
+    return BaseUnicodeCommandLine.Buffer;
 }
 
 /*
@@ -1942,11 +2074,14 @@ ReadProcessMemory(IN HANDLE hProcess,
                                  (PVOID)lpBaseAddress,
                                  lpBuffer,
                                  nSize,
-                                 lpNumberOfBytesRead);
+                                 &nSize);
+
+    /* In user-mode, this parameter is optional */
+    if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
     if (!NT_SUCCESS(Status))
     {
         /* We failed */
-        BaseSetLastNTError (Status);
+        BaseSetLastNTError(Status);
         return FALSE;
     }
 
@@ -2002,7 +2137,11 @@ WriteProcessMemory(IN HANDLE hProcess,
                                           lpBaseAddress,
                                           (LPVOID)lpBuffer,
                                           nSize,
-                                          lpNumberOfBytesWritten);
+                                          &nSize);
+
+            /* In Win32, the parameter is optional, so handle this case */
+            if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
+
             if (!NT_SUCCESS(Status))
             {
                 /* We failed */
@@ -2017,7 +2156,7 @@ WriteProcessMemory(IN HANDLE hProcess,
         else
         {
             /* Check if we were read only */
-            if ((OldValue & PAGE_NOACCESS) || (OldValue & PAGE_READONLY))
+            if (OldValue & (PAGE_NOACCESS | PAGE_READONLY))
             {
                 /* Restore protection and fail */
                 NtProtectVirtualMemory(hProcess,
@@ -2026,7 +2165,9 @@ WriteProcessMemory(IN HANDLE hProcess,
                                        OldValue,
                                        &OldValue);
                 BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
-                return FALSE;
+
+                /* Note: This is what Windows returns and code depends on it */
+                return STATUS_ACCESS_VIOLATION;
             }
 
             /* Otherwise, do the write */
@@ -2034,7 +2175,10 @@ WriteProcessMemory(IN HANDLE hProcess,
                                           lpBaseAddress,
                                           (LPVOID)lpBuffer,
                                           nSize,
-                                          lpNumberOfBytesWritten);
+                                          &nSize);
+
+            /* In Win32, the parameter is optional, so handle this case */
+            if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
 
             /* And restore the protection */
             NtProtectVirtualMemory(hProcess,
@@ -2046,7 +2190,9 @@ WriteProcessMemory(IN HANDLE hProcess,
             {
                 /* We failed */
                 BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
-                return FALSE;
+
+                /* Note: This is what Windows returns and code depends on it */
+                return STATUS_ACCESS_VIOLATION;
             }
 
             /* Flush the ITLB */
@@ -2068,7 +2214,7 @@ WriteProcessMemory(IN HANDLE hProcess,
 BOOL
 WINAPI
 ProcessIdToSessionId(IN DWORD dwProcessId,
-                     OUT DWORD *pSessionId)
+                     OUT PDWORD pSessionId)
 {
     PROCESS_SESSION_INFORMATION SessionInformation;
     OBJECT_ATTRIBUTES ObjectAttributes;
@@ -2076,592 +2222,1622 @@ ProcessIdToSessionId(IN DWORD dwProcessId,
     HANDLE ProcessHandle;
     NTSTATUS Status;
 
+    /* Do a quick check if the pointer is not writable */
     if (IsBadWritePtr(pSessionId, sizeof(DWORD)))
     {
+        /* Fail fast */
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
 
+    /* Open the process passed in by ID */
     ClientId.UniqueProcess = UlongToHandle(dwProcessId);
     ClientId.UniqueThread = 0;
-
     InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
-
     Status = NtOpenProcess(&ProcessHandle,
                            PROCESS_QUERY_INFORMATION,
                            &ObjectAttributes,
                            &ClientId);
     if (NT_SUCCESS(Status))
     {
+        /* Query the session ID from the kernel */
         Status = NtQueryInformationProcess(ProcessHandle,
                                            ProcessSessionInformation,
                                            &SessionInformation,
                                            sizeof(SessionInformation),
                                            NULL);
-        NtClose(ProcessHandle);
 
+        /* Close the handle and check if we suceeded */
+        NtClose(ProcessHandle);
         if (NT_SUCCESS(Status))
         {
+            /* Return the session ID */
             *pSessionId = SessionInformation.SessionId;
             return TRUE;
         }
     }
 
+    /* Set error code and fail */
     BaseSetLastNTError(Status);
     return FALSE;
 }
 
-BOOL
-WINAPI
-SetProcessWorkingSetSizeEx(IN HANDLE hProcess,
-                           IN SIZE_T dwMinimumWorkingSetSize,
-                           IN SIZE_T dwMaximumWorkingSetSize,
-                           IN DWORD Flags)
-{
-    STUB;
-    return FALSE;
-}
-
 
-BOOL
-WINAPI
-GetProcessWorkingSetSizeEx(IN HANDLE hProcess,
-                           OUT PSIZE_T lpMinimumWorkingSetSize,
-                           OUT PSIZE_T lpMaximumWorkingSetSize,
-                           OUT PDWORD Flags)
-{
-    STUB;
-    return FALSE;
-}
+#define AddToHandle(x,y)  (x) = (HANDLE)((ULONG_PTR)(x) | (y));
+#define RemoveFromHandle(x,y)  (x) = (HANDLE)((ULONG_PTR)(x) & ~(y));
+C_ASSERT(PROCESS_PRIORITY_CLASS_REALTIME == (PROCESS_PRIORITY_CLASS_HIGH + 1));
 
 /*
  * @implemented
  */
 BOOL
 WINAPI
-CreateProcessInternalW(HANDLE hToken,
-                       LPCWSTR lpApplicationName,
-                       LPWSTR lpCommandLine,
-                       LPSECURITY_ATTRIBUTES lpProcessAttributes,
-                       LPSECURITY_ATTRIBUTES lpThreadAttributes,
-                       BOOL bInheritHandles,
-                       DWORD dwCreationFlags,
-                       LPVOID lpEnvironment,
-                       LPCWSTR lpCurrentDirectory,
-                       LPSTARTUPINFOW lpStartupInfo,
-                       LPPROCESS_INFORMATION lpProcessInformation,
-                       PHANDLE hNewToken)
+CreateProcessInternalW(IN HANDLE hUserToken,
+                       IN LPCWSTR lpApplicationName,
+                       IN LPWSTR lpCommandLine,
+                       IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
+                       IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
+                       IN BOOL bInheritHandles,
+                       IN DWORD dwCreationFlags,
+                       IN LPVOID lpEnvironment,
+                       IN LPCWSTR lpCurrentDirectory,
+                       IN LPSTARTUPINFOW lpStartupInfo,
+                       IN LPPROCESS_INFORMATION lpProcessInformation,
+                       OUT PHANDLE hNewToken)
 {
-    NTSTATUS Status;
-    PROCESS_PRIORITY_CLASS PriorityClass;
-    BOOLEAN FoundQuotes = FALSE;
-    BOOLEAN QuotesNeeded = FALSE;
-    BOOLEAN CmdLineIsAppName = FALSE;
-    UNICODE_STRING ApplicationName = { 0, 0, NULL };
+    //
+    // Core variables used for creating the initial process and thread
+    //
+    SECURITY_ATTRIBUTES LocalThreadAttributes, LocalProcessAttributes;
     OBJECT_ATTRIBUTES LocalObjectAttributes;
     POBJECT_ATTRIBUTES ObjectAttributes;
-    HANDLE hSection = NULL, hProcess = NULL, hThread = NULL, hDebug = NULL;
-    SECTION_IMAGE_INFORMATION SectionImageInfo;
-    LPWSTR CurrentDirectory = NULL;
-    LPWSTR CurrentDirectoryPart;
-    PROCESS_BASIC_INFORMATION ProcessBasicInfo;
-    STARTUPINFOW StartupInfo;
-    ULONG Dummy;
-    LPWSTR BatchCommandLine;
-    ULONG CmdLineLength;
-    UNICODE_STRING CommandLineString;
-    PWCHAR Extension;
-    LPWSTR QuotedCmdLine = NULL;
-    LPWSTR ScanString;
-    LPWSTR NullBuffer = NULL;
-    LPWSTR NameBuffer = NULL;
-    WCHAR SaveChar = 0;
-    ULONG RetVal;
-    UINT Error = 0;
-    BOOLEAN SearchDone = FALSE;
-    BOOLEAN Escape = FALSE;
+    SECTION_IMAGE_INFORMATION ImageInformation;
+    IO_STATUS_BLOCK IoStatusBlock;
     CLIENT_ID ClientId;
-    PPEB OurPeb = NtCurrentPeb();
-    PPEB RemotePeb;
-    SIZE_T EnvSize = 0;
-    BOOL Ret = FALSE;
+    ULONG NoWindow, RegionSize, StackSize, ErrorCode, Flags;
+    USHORT ImageMachine;
+    ULONG ParameterFlags, PrivilegeValue, HardErrorMode, ErrorResponse;
+    ULONG_PTR ErrorParameters[2];
+    BOOLEAN InJob, SaferNeeded, UseLargePages, HavePrivilege;
+    BOOLEAN QuerySection, SkipSaferAndAppCompat;
+    CONTEXT Context;
+    BASE_API_MESSAGE CsrMsg;
+    PBASE_CREATE_PROCESS CreateProcessMsg;
+    PCSR_CAPTURE_BUFFER CaptureBuffer;
+    PVOID BaseAddress, PrivilegeState, RealTimePrivilegeState;
+    HANDLE DebugHandle, TokenHandle, JobHandle, KeyHandle, ThreadHandle;
+    HANDLE FileHandle, SectionHandle, ProcessHandle;
+    ULONG ResumeCount;
+    PROCESS_PRIORITY_CLASS PriorityClass;
+    NTSTATUS Status, Status1, ImageDbgStatus;
+    PPEB Peb, RemotePeb;
+    PTEB Teb;
+    INITIAL_TEB InitialTeb;
+    PVOID TibValue;
+    PIMAGE_NT_HEADERS NtHeaders;
+    STARTUPINFOW StartupInfo;
+    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
+    UNICODE_STRING DebuggerString;
+    BOOL Result;
+    //
+    // Variables used for command-line and argument parsing
+    //
+    PCHAR pcScan;
+    SIZE_T n;
+    WCHAR SaveChar;
+    ULONG Length, CurdirLength, CmdQuoteLength;
+    ULONG CmdLineLength, ResultSize;
+    PWCHAR QuotedCmdLine, AnsiCmdCommand, ExtBuffer, CurrentDirectory;
+    PWCHAR NullBuffer, ScanString, NameBuffer, SearchPath, DebuggerCmdLine;
+    ANSI_STRING AnsiEnv;
+    UNICODE_STRING UnicodeEnv, PathName;
+    BOOLEAN SearchRetry, QuotesNeeded, CmdLineIsAppName, HasQuotes;
+
+    //
+    // Variables used for Fusion/SxS (Side-by-Side Assemblies)
+    //
+    RTL_PATH_TYPE SxsPathType, PathType;
+#if _SXS_SUPPORT_ENABLED_
+    PRTL_BUFFER ByteBuffer;
+    PRTL_UNICODE_STRING_BUFFER ThisBuffer, Buffer, SxsStaticBuffers[5];
+    PRTL_UNICODE_STRING_BUFFER* BufferHead, SxsStringBuffer;
+    RTL_UNICODE_STRING_BUFFER SxsWin32ManifestPath, SxsNtManifestPath;
+    RTL_UNICODE_STRING_BUFFER SxsWin32PolicyPath, SxsNtPolicyPath;
+    RTL_UNICODE_STRING_BUFFER SxsWin32AssemblyDirectory;
+    BASE_MSG_SXS_HANDLES MappedHandles, Handles, FileHandles;
+    PVOID CapturedStrings[3];
+    SXS_WIN32_NT_PATH_PAIR ExePathPair, ManifestPathPair, PolicyPathPair;
+    SXS_OVERRIDE_MANIFEST OverrideMannifest;
+    UNICODE_STRING FreeString, SxsNtExePath;
+    PWCHAR SxsConglomeratedBuffer, StaticBuffer;
+    ULONG ConglomeratedBufferSizeBytes, StaticBufferSize, i;
+#endif
+    ULONG FusionFlags;
+
+    //
+    // Variables used for path conversion (and partially Fusion/SxS)
+    //
+    PWCHAR FilePart, PathBuffer, FreeBuffer;
+    BOOLEAN TranslationStatus;
+    RTL_RELATIVE_NAME_U SxsWin32RelativePath;
+    UNICODE_STRING PathBufferString, SxsWin32ExePath;
+
+    //
+    // Variables used by Application Compatibility (and partially Fusion/SxS)
+    //
+    PVOID AppCompatSxsData, AppCompatData;
+    ULONG AppCompatSxsDataSize, AppCompatDataSize;
+    //
+    // Variables used by VDM (Virtual Dos Machine) and WOW32 (16-bit Support)
+    //
+    ULONG BinarySubType, VdmBinaryType, VdmTask, VdmReserve;
+    ULONG VdmUndoLevel;
+    BOOLEAN UseVdmReserve;
+    HANDLE VdmWaitObject;
+    ANSI_STRING VdmAnsiEnv;
+    UNICODE_STRING VdmString, VdmUnicodeEnv;
+    BOOLEAN IsWowApp;
+    PBASE_CHECK_VDM CheckVdmMsg;
+
+    /* Zero out the initial core variables and handles */
+    QuerySection = FALSE;
+    InJob = FALSE;
+    SkipSaferAndAppCompat = TRUE; // HACK for making .bat/.cmd launch working again.
+    ParameterFlags = 0;
+    Flags = 0;
+    DebugHandle = NULL;
+    JobHandle = NULL;
+    TokenHandle = NULL;
+    FileHandle = NULL;
+    SectionHandle = NULL;
+    ProcessHandle = NULL;
+    ThreadHandle = NULL;
+    BaseAddress = (PVOID)1;
+
+    /* Zero out initial SxS and Application Compatibility state */
+    AppCompatData = NULL;
+    AppCompatDataSize = 0;
+    AppCompatSxsData = NULL;
+    AppCompatSxsDataSize = 0;
+    CaptureBuffer = NULL;
+#if _SXS_SUPPORT_ENABLED_
+    SxsConglomeratedBuffer = NULL;
+#endif
+    FusionFlags = 0;
+
+    /* Zero out initial parsing variables -- others are initialized later */
+    DebuggerCmdLine = NULL;
+    PathBuffer = NULL;
+    SearchPath = NULL;
+    NullBuffer = 0;
+    FreeBuffer = NULL;
+    NameBuffer = NULL;
+    CurrentDirectory = NULL;
+    FilePart = NULL;
+    DebuggerString.Buffer = NULL;
+    HasQuotes = FALSE;
+    QuotedCmdLine = NULL;
+
+    /* Zero out initial VDM state */
+    VdmAnsiEnv.Buffer = NULL;
+    VdmUnicodeEnv.Buffer = NULL;
+    VdmString.Buffer = NULL;
+    VdmTask = 0;
+    VdmUndoLevel = 0;
+    VdmBinaryType = 0;
+    VdmReserve = 0;
+    VdmWaitObject = NULL;
+    UseVdmReserve = FALSE;
+    IsWowApp = FALSE;
+
+    /* Set message structures */
+    CreateProcessMsg = &CsrMsg.Data.CreateProcessRequest;
+    CheckVdmMsg = &CsrMsg.Data.CheckVDMRequest;
+
+    /* Clear the more complex structures by zeroing out their entire memory */
+    RtlZeroMemory(&Context, sizeof(Context));
+#if _SXS_SUPPORT_ENABLED_
+    RtlZeroMemory(&FileHandles, sizeof(FileHandles));
+    RtlZeroMemory(&MappedHandles, sizeof(MappedHandles));
+    RtlZeroMemory(&Handles, sizeof(Handles));
+#endif
+    RtlZeroMemory(&CreateProcessMsg->Sxs, sizeof(CreateProcessMsg->Sxs));
+    RtlZeroMemory(&LocalProcessAttributes, sizeof(LocalProcessAttributes));
+    RtlZeroMemory(&LocalThreadAttributes, sizeof(LocalThreadAttributes));
+
+    /* Zero out output arguments as well */
+    RtlZeroMemory(lpProcessInformation, sizeof(*lpProcessInformation));
+    if (hNewToken) *hNewToken = NULL;
+
+    /* Capture the special window flag */
+    NoWindow = dwCreationFlags & CREATE_NO_WINDOW;
+    dwCreationFlags &= ~CREATE_NO_WINDOW;
+
+#if _SXS_SUPPORT_ENABLED_
+    /* Setup the SxS static string arrays and buffers */
+    SxsStaticBuffers[0] = &SxsWin32ManifestPath;
+    SxsStaticBuffers[1] = &SxsWin32PolicyPath;
+    SxsStaticBuffers[2] = &SxsWin32AssemblyDirectory;
+    SxsStaticBuffers[3] = &SxsNtManifestPath;
+    SxsStaticBuffers[4] = &SxsNtPolicyPath;
+    ExePathPair.Win32 = &SxsWin32ExePath;
+    ExePathPair.Nt = &SxsNtExePath;
+    ManifestPathPair.Win32 = &SxsWin32ManifestPath.String;
+    ManifestPathPair.Nt = &SxsNtManifestPath.String;
+    PolicyPathPair.Win32 = &SxsWin32PolicyPath.String;
+    PolicyPathPair.Nt = &SxsNtPolicyPath.String;
+#endif
 
-    /* FIXME should process
-     * HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
-     * key (see http://blogs.msdn.com/oldnewthing/archive/2005/12/19/505449.aspx)
-     */
+    DPRINT("CreateProcessInternalW: %S %S %lx\n", lpApplicationName, lpCommandLine, dwCreationFlags);
 
-    DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
-           " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
-           lpApplicationName, lpCommandLine, lpEnvironment, lpCurrentDirectory,
-           dwCreationFlags);
+    /* Finally, set our TEB and PEB */
+    Teb = NtCurrentTeb();
+    Peb = NtCurrentPeb();
+
+    /* This combination is illegal (see MSDN) */
+    if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
+        (DETACHED_PROCESS | CREATE_NEW_CONSOLE))
+    {
+        DPRINT1("Invalid flag combo used\n");
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
 
-    /* Flags we don't handle yet */
-    if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)
+    /* Convert the priority class */
+    if (dwCreationFlags & IDLE_PRIORITY_CLASS)
     {
-        DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
+        PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE;
     }
-    if (dwCreationFlags & CREATE_SHARED_WOW_VDM)
+    else if (dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
     {
-        DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
+        PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
     }
-    if (dwCreationFlags & CREATE_FORCEDOS)
+    else if (dwCreationFlags & NORMAL_PRIORITY_CLASS)
     {
-        DPRINT1("CREATE_FORCEDOS not handled\n");
+        PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
     }
-
-    /* Fail on this flag, it's only valid with the WithLogonW function */
-    if (dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
+    else if (dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
     {
-        DPRINT1("Invalid flag used\n");
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
+        PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
     }
-
-    /* This combination is illegal (see MSDN) */
-    if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
-        (DETACHED_PROCESS | CREATE_NEW_CONSOLE))
+    else if (dwCreationFlags & HIGH_PRIORITY_CLASS)
     {
-        DPRINT1("Invalid flag combo used\n");
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
+        PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
     }
-
-    /* Another illegal combo */
-    if ((dwCreationFlags & (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) ==
-        (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM))
+    else if (dwCreationFlags & REALTIME_PRIORITY_CLASS)
     {
-        DPRINT1("Invalid flag combo used\n");
+        PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
+        PriorityClass.PriorityClass += (BasepIsRealtimeAllowed(FALSE) != NULL);
+    }
+    else
+    {
+        PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_INVALID;
+    }
+
+    /* Done with the priority masks, so get rid of them */
+    PriorityClass.Foreground = FALSE;
+    dwCreationFlags &= ~(NORMAL_PRIORITY_CLASS |
+                         IDLE_PRIORITY_CLASS |
+                         HIGH_PRIORITY_CLASS |
+                         REALTIME_PRIORITY_CLASS |
+                         BELOW_NORMAL_PRIORITY_CLASS |
+                         ABOVE_NORMAL_PRIORITY_CLASS);
+
+    /* You cannot request both a shared and a separate WoW VDM */
+    if ((dwCreationFlags & CREATE_SEPARATE_WOW_VDM) &&
+        (dwCreationFlags & CREATE_SHARED_WOW_VDM))
+    {
+        /* Fail such nonsensical attempts */
+        DPRINT1("Invalid WOW flags\n");
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
+    else if (!(dwCreationFlags & CREATE_SHARED_WOW_VDM) &&
+             (BaseStaticServerData->DefaultSeparateVDM))
+    {
+        /* A shared WoW VDM was not requested but system enforces separation */
+        dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
+    }
 
-    if (lpCurrentDirectory)
+    /* If a shared WoW VDM is used, make sure the process isn't in a job */
+    if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM) &&
+        (NtIsProcessInJob(NtCurrentProcess(), NULL)))
     {
-        if ((GetFileAttributesW(lpCurrentDirectory) == INVALID_FILE_ATTRIBUTES) ||
-            !(GetFileAttributesW(lpCurrentDirectory) & FILE_ATTRIBUTE_DIRECTORY))
-        {
-            SetLastError(ERROR_DIRECTORY);
-            return FALSE;
-        }
+        /* Remove the shared flag and add the separate flag */
+        dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
+                                              CREATE_SEPARATE_WOW_VDM;
     }
 
-    /*
-     * We're going to modify and mask out flags and stuff in lpStartupInfo,
-     * so we'll use our own local copy for that.
-     */
-    StartupInfo = *lpStartupInfo;
+    /* Convert the environment */
+    if ((lpEnvironment) && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+    {
+        /* Scan the environment to calculate its Unicode size */
+        AnsiEnv.Buffer = pcScan = (PCHAR)lpEnvironment;
+        while ((*pcScan) || (*(pcScan + 1))) ++pcScan;
 
-    /* FIXME: Use default Separate/Shared VDM Flag */
+        /* Create our ANSI String */
+        AnsiEnv.Length = pcScan - (PCHAR)lpEnvironment + sizeof(ANSI_NULL);
+        AnsiEnv.MaximumLength = AnsiEnv.Length + sizeof(ANSI_NULL);
 
-    /* If we are inside a Job, use Separate VDM so it won't escape the Job */
-    if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
-    {
-        if (NtIsProcessInJob(NtCurrentProcess(), NULL))
+        /* Allocate memory for the Unicode Environment */
+        UnicodeEnv.Buffer = NULL;
+        RegionSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
+        Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+                                         (PVOID)&UnicodeEnv.Buffer,
+                                         0,
+                                         &RegionSize,
+                                         MEM_COMMIT,
+                                         PAGE_READWRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Fail */
+            BaseSetLastNTError(Status);
+            return FALSE;
+        }
+
+        /* Use the allocated size and convert */
+        UnicodeEnv.MaximumLength = (USHORT)RegionSize;
+        Status = RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
+        if (!NT_SUCCESS(Status))
         {
-            /* Remove the shared flag and add the separate flag. */
-            dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
-                                                  CREATE_SEPARATE_WOW_VDM;
+            /* Fail */
+            NtFreeVirtualMemory(NtCurrentProcess(),
+                                (PVOID)&UnicodeEnv.Buffer,
+                                &RegionSize,
+                                MEM_RELEASE);
+            BaseSetLastNTError(Status);
+            return FALSE;
         }
+
+        /* Now set the Unicode environment as the environment string pointer */
+        lpEnvironment = UnicodeEnv.Buffer;
     }
 
-    /*
-     * According to some sites, ShellExecuteEx uses an undocumented flag to
-     * send private handle data (such as HMONITOR or HICON). See:
-     * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
-     * standard handles anymore since we'd be overwriting this private data
-     */
+    /* Make a copy of the caller's startup info since we'll modify it */
+    StartupInfo = *lpStartupInfo;
+
+    /* Check if private data is being sent on the same channel as std handles */
     if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
         (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
     {
+        /* Cannot use the std handles since we have monitor/hotkey values */
         StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
     }
 
-    /* Start by zeroing out the fields */
-    RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION));
+    /* If there's a debugger, or we have to launch cmd.exe, we go back here */
+AppNameRetry:
+    /* New iteration -- free any existing name buffer */
+    if (NameBuffer)
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
+        NameBuffer = NULL;
+    }
 
-    /* Easy stuff first, convert the process priority class */
-    PriorityClass.Foreground = FALSE;
-    PriorityClass.PriorityClass = (UCHAR)BasepConvertPriorityClass(dwCreationFlags);
+    /* New iteration -- free any existing free buffer */
+    if (FreeBuffer)
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
+        FreeBuffer = NULL;
+    }
 
-    if (lpCommandLine)
+    /* New iteration -- close any existing file handle */
+    if (FileHandle)
     {
-        /* Search for escape sequences */
-        ScanString = lpCommandLine;
-        while (NULL != (ScanString = wcschr(ScanString, L'^')))
-        {
-            ScanString++;
-            if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\"')
-            {
-                Escape = TRUE;
-                break;
-            }
-        }
+        NtClose(FileHandle);
+        FileHandle = NULL;
     }
 
-    /* Get the application name and do all the proper formating necessary */
-GetAppName:
-    /* See if we have an application name (oh please let us have one!) */
+    /* Set the initial parsing state. This code can loop -- don't move this! */
+    ErrorCode = 0;
+    SearchRetry = TRUE;
+    QuotesNeeded = FALSE;
+    CmdLineIsAppName = FALSE;
+
+    /* First check if we don't have an application name */
     if (!lpApplicationName)
     {
-        /* The fun begins */
+        /* This should be the first time we attempt creating one */
+        ASSERT(NameBuffer == NULL);
+
+        /* Allocate a buffer to hold it */
         NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
                                      0,
                                      MAX_PATH * sizeof(WCHAR));
-        if (NameBuffer == NULL)
+        if (!NameBuffer)
         {
             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto Cleanup;
+            Result = FALSE;
+            goto Quickie;
         }
 
-        /* This is all we have to work with :( */
-        lpApplicationName = lpCommandLine;
+        /* Initialize the application name and our parsing parameters */
+        lpApplicationName = NullBuffer = ScanString = lpCommandLine;
 
-        /* Initialize our friends at the beginning */
-        NullBuffer = (LPWSTR)lpApplicationName;
-        ScanString = (LPWSTR)lpApplicationName;
-
-        /* We will start by looking for a quote */
-        if (*ScanString == L'\"')
+        /* Check for an initial quote*/
+        if (*lpCommandLine == L'\"')
         {
-             /* That was quick */
-             SearchDone = TRUE;
-
-             /* Advance past quote */
-             ScanString++;
-             lpApplicationName = ScanString;
-
-             /* Find the closing quote */
-             while (*ScanString)
-             {
-                 if (*ScanString == L'\"' && *(ScanString - 1) != L'^')
-                 {
-                     /* Found it */
-                     NullBuffer = ScanString;
-                     FoundQuotes = TRUE;
-                     break;
-                 }
+            /* We found a quote, keep searching for another one */
+            SearchRetry = FALSE;
+            ScanString++;
+            lpApplicationName = ScanString;
+            while (*ScanString)
+            {
+                /* Have we found the terminating quote? */
+                if (*ScanString == L'\"')
+                {
+                    /* We're done, get out of here */
+                    NullBuffer = ScanString;
+                    HasQuotes = TRUE;
+                    break;
+                }
 
-                 /* Keep looking */
-                 ScanString++;
-                 NullBuffer = ScanString;
-             }
+                /* Keep searching for the quote */
+                ScanString++;
+                NullBuffer = ScanString;
+            }
         }
         else
         {
-            /* No quotes, so we'll be looking for white space */
-        WhiteScan:
-            /* Reset the pointer */
+StartScan:
+            /* We simply make the application name be the command line*/
             lpApplicationName = lpCommandLine;
-
-            /* Find whitespace of Tab */
             while (*ScanString)
             {
-                if (*ScanString == ' ' || *ScanString == '\t')
+                /* Check if it starts with a space or tab */
+                if ((*ScanString == L' ') || (*ScanString == L'\t'))
                 {
-                    /* Found it */
+                    /* Break out of the search loop */
                     NullBuffer = ScanString;
                     break;
                 }
 
-                /* Keep looking */
+                /* Keep searching for a space or tab */
                 ScanString++;
                 NullBuffer = ScanString;
             }
         }
 
-        /* Set the Null Buffer */
+        /* We have found the end of the application name, terminate it */
         SaveChar = *NullBuffer;
         *NullBuffer = UNICODE_NULL;
 
-        /* Do a search for the file */
-        DPRINT("Ready for SearchPathW: %S\n", lpApplicationName);
-        RetVal = SearchPathW(NULL,
+        /* New iteration -- free any existing saved path */
+        if (SearchPath)
+        {
+            RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
+            SearchPath = NULL;
+        }
+
+        /* Now compute the final EXE path based on the name */
+        SearchPath = BaseComputeProcessExePath((LPWSTR)lpApplicationName);
+        DPRINT("Search Path: %S\n", SearchPath);
+        if (!SearchPath)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            Result = FALSE;
+            goto Quickie;
+        }
+
+        /* And search for the executable in the search path */
+        Length = SearchPathW(SearchPath,
                              lpApplicationName,
                              L".exe",
                              MAX_PATH,
                              NameBuffer,
-                             NULL) * sizeof(WCHAR);
+                             NULL);
 
-        /* Did it find something? */
-        if (RetVal)
+        /* Did we find it? */
+        if ((Length) && (Length < MAX_PATH))
         {
             /* Get file attributes */
-            ULONG Attributes = GetFileAttributesW(NameBuffer);
-            if (Attributes & FILE_ATTRIBUTE_DIRECTORY)
+            CurdirLength = GetFileAttributesW(NameBuffer);
+            if ((CurdirLength != 0xFFFFFFFF) &&
+                (CurdirLength & FILE_ATTRIBUTE_DIRECTORY))
             {
-                /* Give it a length of 0 to fail, this was a directory. */
-                RetVal = 0;
+                /* This was a directory, fail later on */
+                Length = 0;
             }
             else
             {
                 /* It's a file! */
-                RetVal += sizeof(WCHAR);
+                Length++;
             }
         }
 
-        /* Now check if we have a file, and if the path size is OK */
-        if (!RetVal || RetVal >= (MAX_PATH * sizeof(WCHAR)))
-        {
-            ULONG PathType;
-            HANDLE hFile;
+        DPRINT("Length: %lu Buffer: %S\n", Length, NameBuffer);
 
-            /* We failed, try to get the Path Type */
-            DPRINT("SearchPathW failed. Retval: %ld\n", RetVal);
+        /* Check if there was a failure in SearchPathW */
+        if ((Length) && (Length < MAX_PATH))
+        {
+            /* Everything looks good, restore the name */
+            *NullBuffer = SaveChar;
+            lpApplicationName = NameBuffer;
+        }
+        else
+        {
+            /* Check if this was a relative path, which would explain it */
             PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
-
-            /* If it's not relative, try to get the error */
             if (PathType != RtlPathTypeRelative)
             {
                 /* This should fail, and give us a detailed LastError */
-                hFile = CreateFileW(lpApplicationName,
-                                    GENERIC_READ,
-                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
-                                    NULL,
-                                    OPEN_EXISTING,
-                                    FILE_ATTRIBUTE_NORMAL,
-                                    NULL);
-
-                /* Did it actually NOT fail? */
-                if (hFile != INVALID_HANDLE_VALUE)
+                FileHandle = CreateFileW(lpApplicationName,
+                                         GENERIC_READ,
+                                         FILE_SHARE_READ |
+                                         FILE_SHARE_WRITE,
+                                         NULL,
+                                         OPEN_EXISTING,
+                                         FILE_ATTRIBUTE_NORMAL,
+                                         NULL);
+                if (FileHandle != INVALID_HANDLE_VALUE)
                 {
-                    /* Fake the error */
-                    CloseHandle(hFile);
+                    /* It worked? Return a generic error */
+                    CloseHandle(FileHandle);
+                    FileHandle = NULL;
                     BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
                 }
             }
             else
             {
-                /* Immediately set the error */
+                /* Path was absolute, which means it doesn't exist */
                 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
             }
 
             /* Did we already fail once? */
-            if (Error)
+            if (ErrorCode)
             {
-                SetLastError(Error);
+                /* Set the error code */
+                SetLastError(ErrorCode);
             }
             else
             {
                 /* Not yet, cache it */
-                Error = GetLastError();
+                ErrorCode = GetLastError();
             }
 
             /* Put back the command line */
             *NullBuffer = SaveChar;
             lpApplicationName = NameBuffer;
 
-            /*
-             * If the search isn't done and we still have cmdline
-             * then start over. Ex: c:\ha ha ha\haha.exe
-             */
-            if (*ScanString && !SearchDone)
+            /* It's possible there's whitespace in the directory name */
+            if (!(*ScanString) || !(SearchRetry))
             {
-                /* Move in the buffer */
-                ScanString++;
-                NullBuffer = ScanString;
+                /* Not the case, give up completely */
+                Result = FALSE;
+                goto Quickie;
+            }
+
+            /* There are spaces, so keep trying the next possibility */
+            ScanString++;
+            NullBuffer = ScanString;
+
+            /* We will have to add a quote, since there is a space */
+            QuotesNeeded = TRUE;
+            HasQuotes = TRUE;
+            goto StartScan;
+        }
+    }
+    else if (!(lpCommandLine) || !(*lpCommandLine))
+    {
+        /* We don't have a command line, so just use the application name */
+        CmdLineIsAppName = TRUE;
+        lpCommandLine = (LPWSTR)lpApplicationName;
+    }
+
+    /* Convert the application name to its NT path */
+    TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(lpApplicationName,
+                                                             &PathName,
+                                                             NULL,
+                                                             &SxsWin32RelativePath);
+    if (!TranslationStatus)
+    {
+        /* Path must be invaild somehow, bail out */
+        DPRINT1("Path translation for SxS failed\n");
+        SetLastError(ERROR_PATH_NOT_FOUND);
+        Result = FALSE;
+        goto Quickie;
+    }
+
+    /* Setup the buffer that needs to be freed at the end */
+    ASSERT(FreeBuffer == NULL);
+    FreeBuffer = PathName.Buffer;
+
+    /* Check what kind of path the application is, for SxS (Fusion) purposes */
+    RtlInitUnicodeString(&SxsWin32ExePath, lpApplicationName);
+    SxsPathType = RtlDetermineDosPathNameType_U(lpApplicationName);
+    if ((SxsPathType != RtlPathTypeDriveAbsolute) &&
+        (SxsPathType != RtlPathTypeLocalDevice) &&
+        (SxsPathType != RtlPathTypeRootLocalDevice) &&
+        (SxsPathType != RtlPathTypeUncAbsolute))
+    {
+        /* Relative-type path, get the full path */
+        RtlInitEmptyUnicodeString(&PathBufferString, NULL, 0);
+        Status = RtlGetFullPathName_UstrEx(&SxsWin32ExePath,
+                                           NULL,
+                                           &PathBufferString,
+                                           NULL,
+                                           NULL,
+                                           NULL,
+                                           &SxsPathType,
+                                           NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Fail the rest of the create */
+            RtlReleaseRelativeName(&SxsWin32RelativePath);
+            BaseSetLastNTError(Status);
+            Result = FALSE;
+            goto Quickie;
+        }
+
+        /* Use this full path as the SxS path */
+        SxsWin32ExePath = PathBufferString;
+        PathBuffer = PathBufferString.Buffer;
+        PathBufferString.Buffer = NULL;
+        DPRINT("SxS Path: %S\n", PathBuffer);
+    }
+
+    /* Also set the .EXE path based on the path name */
+#if _SXS_SUPPORT_ENABLED_
+    SxsNtExePath = PathName;
+#endif
+    if (SxsWin32RelativePath.RelativeName.Length)
+    {
+        /* If it's relative, capture the relative name */
+        PathName = SxsWin32RelativePath.RelativeName;
+    }
+    else
+    {
+        /* Otherwise, it's absolute, make sure no relative dir is used */
+        SxsWin32RelativePath.ContainingDirectory = NULL;
+    }
+
+    /* Now use the path name, and the root path, to try opening the app */
+    DPRINT("Path: %wZ. Dir: %p\n", &PathName, SxsWin32RelativePath.ContainingDirectory);
+    InitializeObjectAttributes(&LocalObjectAttributes,
+                               &PathName,
+                               OBJ_CASE_INSENSITIVE,
+                               SxsWin32RelativePath.ContainingDirectory,
+                               NULL);
+    Status = NtOpenFile(&FileHandle,
+                        SYNCHRONIZE |
+                        FILE_READ_ATTRIBUTES |
+                        FILE_READ_DATA |
+                        FILE_EXECUTE,
+                        &LocalObjectAttributes,
+                        &IoStatusBlock,
+                        FILE_SHARE_READ | FILE_SHARE_DELETE,
+                        FILE_SYNCHRONOUS_IO_NONALERT |
+                        FILE_NON_DIRECTORY_FILE);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Try to open the app just for execute purposes instead */
+        Status = NtOpenFile(&FileHandle,
+                            SYNCHRONIZE | FILE_EXECUTE,
+                            &LocalObjectAttributes,
+                            &IoStatusBlock,
+                            FILE_SHARE_READ | FILE_SHARE_DELETE,
+                            FILE_SYNCHRONOUS_IO_NONALERT |
+                            FILE_NON_DIRECTORY_FILE);
+    }
 
-                /* We will have to add a quote, since there is a space*/
-                QuotesNeeded = TRUE;
+    /* Cleanup in preparation for failure or success */
+    RtlReleaseRelativeName(&SxsWin32RelativePath);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failure path, try to understand why */
+        DPRINT1("Open file failed: %lx\n", Status);
+        if (RtlIsDosDeviceName_U(lpApplicationName))
+        {
+            /* If a device is being executed, return this special error code */
+            SetLastError(ERROR_BAD_DEVICE);
+            Result = FALSE;
+            goto Quickie;
+        }
+        else
+        {
+            /* Otherwise return the converted NT error code */
+            BaseSetLastNTError(Status);
+            Result = FALSE;
+            goto Quickie;
+        }
+    }
 
-                /* And we will also fake the fact we found one */
-                FoundQuotes = TRUE;
+    /* Did the caller specify a desktop? */
+    if (!StartupInfo.lpDesktop)
+    {
+        /* Use the one from the current process */
+        StartupInfo.lpDesktop = Peb->ProcessParameters->DesktopInfo.Buffer;
+    }
 
-                /* Start over */
-                goto WhiteScan;
+    /* Create a section for this file */
+    Status = NtCreateSection(&SectionHandle,
+                             SECTION_ALL_ACCESS,
+                             NULL,
+                             NULL,
+                             PAGE_EXECUTE,
+                             SEC_IMAGE,
+                             FileHandle);
+    DPRINT("Section status: %lx\n", Status);
+    if (NT_SUCCESS(Status))
+    {
+        /* Are we running on Windows Embedded, Datacenter, Blade or Starter? */
+        if (SharedUserData->SuiteMask & (VER_SUITE_EMBEDDEDNT |
+                                         VER_SUITE_DATACENTER |
+                                         VER_SUITE_PERSONAL |
+                                         VER_SUITE_BLADE))
+        {
+            /* These SKUs do not allow running certain applications */
+            Status = BasepCheckWebBladeHashes(FileHandle);
+            if (Status == STATUS_ACCESS_DENIED)
+            {
+                /* And this is one of them! */
+                DPRINT1("Invalid Blade hashes!\n");
+                SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE);
+                Result = FALSE;
+                goto Quickie;
             }
 
-            /* We totally failed */
-            goto Cleanup;
+            /* Did we get some other failure? */
+            if (!NT_SUCCESS(Status))
+            {
+                /* If we couldn't check the hashes, assume nefariousness */
+                DPRINT1("Tampered Blade hashes!\n");
+                SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER);
+                Result = FALSE;
+                goto Quickie;
+            }
         }
 
-        /* Put back the command line */
-        *NullBuffer = SaveChar;
-        lpApplicationName = NameBuffer;
-        DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer);
+        /* Now do Winsafer, etc, checks */
+        Status = BasepIsProcessAllowed((LPWSTR)lpApplicationName);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Fail if we're not allowed to launch the process */
+            DPRINT1("Process not allowed to launch: %lx\n", Status);
+            BaseSetLastNTError(Status);
+            if (SectionHandle)
+            {
+                NtClose(SectionHandle);
+                SectionHandle = NULL;
+            }
+            Result = FALSE;
+            goto Quickie;
+        }
+
+        /* Is a DOS VDM being forced, but we already have a WOW32 instance ready? */
+        if ((dwCreationFlags & CREATE_FORCEDOS) &&
+            (BaseStaticServerData->IsWowTaskReady))
+        {
+            /* This request can't be satisfied, instead, a separate VDM is needed */
+            dwCreationFlags &= ~(CREATE_FORCEDOS | CREATE_SHARED_WOW_VDM);
+            dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
+
+            /* Set a failure code, ask for VDM reservation */
+            Status = STATUS_INVALID_IMAGE_WIN_16;
+            UseVdmReserve = TRUE;
+
+            /* Close the current handle */
+            NtClose(SectionHandle);
+            SectionHandle = NULL;
+
+            /* Don't query the section later */
+            QuerySection = FALSE;
+        }
     }
-    else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL)
+
+    /* Did we already do these checks? */
+    if (!SkipSaferAndAppCompat)
     {
-        /* We have an app name (good!) but no command line */
-        CmdLineIsAppName = TRUE;
-        lpCommandLine = (LPWSTR)lpApplicationName;
+        /* Is everything OK so far, OR do we have an non-MZ, non-DOS app? */
+        if ((NT_SUCCESS(Status)) ||
+            ((Status == STATUS_INVALID_IMAGE_NOT_MZ) &&
+            !(BaseIsDosApplication(&PathName, Status))))
+        {
+            /* Clear the machine type in case of failure */
+            ImageMachine = 0;
+
+            /* Clean any app compat data that may have accumulated */
+            BasepFreeAppCompatData(AppCompatData, AppCompatSxsData);
+            AppCompatData = NULL;
+            AppCompatSxsData = NULL;
+
+            /* Do we have a section? */
+            if (SectionHandle)
+            {
+                /* Have we already queried it? */
+                if (QuerySection)
+                {
+                    /* Nothing to do */
+                    Status = STATUS_SUCCESS;
+                }
+                else
+                {
+                    /* Get some information about the executable */
+                    Status = NtQuerySection(SectionHandle,
+                                            SectionImageInformation,
+                                            &ImageInformation,
+                                            sizeof(ImageInformation),
+                                            NULL);
+                }
+
+                /* Do we have section information now? */
+                if (NT_SUCCESS(Status))
+                {
+                    /* Don't ask for it again, save the machine type */
+                    QuerySection = TRUE;
+                    ImageMachine = ImageInformation.Machine;
+                }
+            }
+
+            /* Is there a reason/Shim we shouldn't run this application? */
+            Status = BasepCheckBadapp(FileHandle,
+                                      FreeBuffer,
+                                      lpEnvironment,
+                                      ImageMachine,
+                                      &AppCompatData,
+                                      &AppCompatDataSize,
+                                      &AppCompatSxsData,
+                                      &AppCompatSxsDataSize,
+                                      &FusionFlags);
+            if (!NT_SUCCESS(Status))
+            {
+                /* This is usually the status we get back */
+                DPRINT1("App compat launch failure: %lx\n", Status);
+                if (Status == STATUS_ACCESS_DENIED)
+                {
+                    /* Convert it to something more Win32-specific */
+                    SetLastError(ERROR_CANCELLED);
+                }
+                else
+                {
+                    /* Some other error */
+                    BaseSetLastNTError(Status);
+                }
+
+                /* Did we have a section? */
+                if (SectionHandle)
+                {
+                    /* Clean it up */
+                    NtClose(SectionHandle);
+                    SectionHandle = NULL;
+                }
+
+                /* Fail the call */
+                Result = FALSE;
+                goto Quickie;
+            }
+        }
     }
 
-    /* At this point the name has been toyed with enough to be openable */
-    Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName);
+    //ASSERT((dwFusionFlags & ~SXS_APPCOMPACT_FLAG_APP_RUNNING_SAFEMODE) == 0);
 
-    /* Check for failure */
-    if (!NT_SUCCESS(Status))
+    /* Have we already done, and do we need to do, SRP (WinSafer) checks? */
+    if (!(SkipSaferAndAppCompat) &&
+        ~(dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL))
     {
-        /* Could be a non-PE File */
+        /* Assume yes */
+        SaferNeeded = TRUE;
         switch (Status)
         {
-            /* Check if the Kernel tells us it's not even valid MZ */
             case STATUS_INVALID_IMAGE_NE_FORMAT:
             case STATUS_INVALID_IMAGE_PROTECT:
+            case STATUS_INVALID_IMAGE_WIN_16:
+            case STATUS_FILE_IS_OFFLINE:
+                /* For all DOS, 16-bit, OS/2 images, we do*/
+                break;
+
             case STATUS_INVALID_IMAGE_NOT_MZ:
+                /* For invalid files, we don't, unless it's a .BAT file */
+                if (BaseIsDosApplication(&PathName, Status)) break;
+
+            default:
+                /* Any other error codes we also don't */
+                if (!NT_SUCCESS(Status))
+                {
+                    SaferNeeded = FALSE;
+                }
 
-#if 0
-            /* If it's a DOS app, use VDM */
-            if ((BasepCheckDosApp(&ApplicationName)))
+                /* But for success, we do */
+                break;
+        }
+
+        /* Okay, so what did the checks above result in? */
+        if (SaferNeeded)
+        {
+            /* We have to call into the WinSafer library and actually check */
+            Status = BasepCheckWinSaferRestrictions(hUserToken,
+                                                    (LPWSTR)lpApplicationName,
+                                                    FileHandle,
+                                                    &InJob,
+                                                    &TokenHandle,
+                                                    &JobHandle);
+            if (Status == 0xFFFFFFFF)
             {
-                DPRINT1("Launching VDM...\n");
-                RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
-                RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
-                return CreateProcessW(L"ntvdm.exe",
-                                      (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */
-                                      lpProcessAttributes,
-                                      lpThreadAttributes,
-                                      bInheritHandles,
-                                      dwCreationFlags,
-                                      lpEnvironment,
-                                      lpCurrentDirectory,
-                                      &StartupInfo,
-                                      lpProcessInformation);
+                /* Back in 2003, they didn't have an NTSTATUS for this... */
+                DPRINT1("WinSafer blocking process launch\n");
+                SetLastError(ERROR_ACCESS_DISABLED_BY_POLICY);
+                Result = FALSE;
+                goto Quickie;
             }
-#endif
-            /* It's a batch file */
-            Extension = &ApplicationName.Buffer[ApplicationName.Length /
-                                                sizeof(WCHAR) - 4];
 
-            /* Make sure the extensions are correct */
-            if (_wcsnicmp(Extension, L".bat", 4) && _wcsnicmp(Extension, L".cmd", 4))
+            /* Other status codes are not-Safer related, just convert them */
+            if (!NT_SUCCESS(Status))
             {
-                SetLastError(ERROR_BAD_EXE_FORMAT);
-                return FALSE;
+                DPRINT1("Error checking WinSafer: %lx\n", Status);
+                BaseSetLastNTError(Status);
+                Result = FALSE;
+                goto Quickie;
             }
+        }
+    }
 
-            /* Calculate the length of the command line */
-            CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1;
+    /* The last step is to figure out why the section object was not created */
+    switch (Status)
+    {
+        case STATUS_INVALID_IMAGE_WIN_16:
+        {
+            /* 16-bit binary. Should we use WOW or does the caller force VDM? */
+            if (!(dwCreationFlags & CREATE_FORCEDOS))
+            {
+                /* Remember that we're launching WOW */
+                IsWowApp = TRUE;
+
+                /* Create the VDM environment, it's valid for WOW too */
+                Result = BaseCreateVDMEnvironment(lpEnvironment,
+                                                  &VdmAnsiEnv,
+                                                  &VdmUnicodeEnv);
+                if (!Result)
+                {
+                    DPRINT1("VDM environment for WOW app failed\n");
+                    goto Quickie;
+                }
 
-            /* If we found quotes, then add them into the length size */
-            if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2;
-            CmdLineLength *= sizeof(WCHAR);
+                /* We're going to try this twice, so do a loop */
+                while (TRUE)
+                {
+                    /* Pick which kind of WOW mode we want to run in */
+                    VdmBinaryType = (dwCreationFlags &
+                                     CREATE_SEPARATE_WOW_VDM) ?
+                                     BINARY_TYPE_WOW : BINARY_TYPE_SEPARATE_WOW;
+
+                    /* Get all the VDM settings and current status */
+                    Status = BaseCheckVDM(VdmBinaryType,
+                                          lpApplicationName,
+                                          lpCommandLine,
+                                          lpCurrentDirectory,
+                                          &VdmAnsiEnv,
+                                          &CsrMsg,
+                                          &VdmTask,
+                                          dwCreationFlags,
+                                          &StartupInfo,
+                                          hUserToken);
+
+                    /* If it worked, no need to try again */
+                    if (NT_SUCCESS(Status)) break;
+
+                    /* Check if it's disallowed or if it's our second time */
+                    BaseSetLastNTError(Status);
+                    if ((Status == STATUS_VDM_DISALLOWED) ||
+                        (VdmBinaryType == BINARY_TYPE_SEPARATE_WOW) ||
+                        (GetLastError() == ERROR_ACCESS_DENIED))
+                    {
+                        /* Fail the call -- we won't try again */
+                        DPRINT1("VDM message failure for WOW: %lx\n", Status);
+                        Result = FALSE;
+                        goto Quickie;
+                    }
+
+                    /* Try one more time, but with a separate WOW instance */
+                    dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
+                }
 
-            /* Allocate space for the new command line */
-            BatchCommandLine = RtlAllocateHeap(RtlGetProcessHeap(),
-                                               0,
-                                               CmdLineLength);
-            if (BatchCommandLine == NULL)
-            {
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                goto Cleanup;
+                /* Check which VDM state we're currently in */
+                switch (CheckVdmMsg->VDMState & (VDM_NOT_LOADED |
+                                                 VDM_NOT_READY |
+                                                 VDM_READY))
+                {
+                    case VDM_NOT_LOADED:
+                        /* VDM is not fully loaded, so not that much to undo */
+                        VdmUndoLevel = VDM_UNDO_PARTIAL;
+
+                        /* Reset VDM reserve if needed */
+                        if (UseVdmReserve) VdmReserve = 1;
+
+                        /* Get the required parameters and names for launch */
+                        Result = BaseGetVdmConfigInfo(lpCommandLine,
+                                                      VdmTask,
+                                                      VdmBinaryType,
+                                                      &VdmString,
+                                                      &VdmReserve);
+                        if (!Result)
+                        {
+                            DPRINT1("VDM Configuration failed for WOW\n");
+                            BaseSetLastNTError(Status);
+                            goto Quickie;
+                        }
+
+                        /* Update the command-line with the VDM one instead */
+                        lpCommandLine = VdmString.Buffer;
+                        lpApplicationName = NULL;
+
+                        /* We don't want a console, detachment, nor a window */
+                        dwCreationFlags |= CREATE_NO_WINDOW;
+                        dwCreationFlags &= ~(CREATE_NEW_CONSOLE | DETACHED_PROCESS);
+
+                        /* Force feedback on */
+                        StartupInfo.dwFlags |= STARTF_FORCEONFEEDBACK;
+                        break;
+
+
+                    case VDM_READY:
+                        /* VDM is ready, so we have to undo everything */
+                        VdmUndoLevel = VDM_UNDO_REUSE;
+
+                        /* Check if CSRSS wants us to wait on VDM */
+                        VdmWaitObject = CheckVdmMsg->WaitObjectForParent;
+                        break;
+
+                    case VDM_NOT_READY:
+                        /* Something is wrong with VDM, we'll fail the call */
+                        DPRINT1("VDM is not ready for WOW\n");
+                        SetLastError(ERROR_NOT_READY);
+                        Result = FALSE;
+                        goto Quickie;
+
+                    default:
+                        break;
+                }
+
+                /* Since to get NULL, we allocate from 0x1, account for this */
+                VdmReserve--;
+
+                /* This implies VDM is ready, so skip everything else */
+                if (VdmWaitObject) goto VdmShortCircuit;
+
+                /* Don't inherit handles since we're doing VDM now */
+                bInheritHandles = FALSE;
+
+                /* Had the user passed in environment? If so, destroy it */
+                if ((lpEnvironment) &&
+                    !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+                {
+                    RtlDestroyEnvironment(lpEnvironment);
+                }
+
+                /* We've already done all these checks, don't do them again */
+                SkipSaferAndAppCompat = TRUE;
+                goto AppNameRetry;
             }
 
-            /* Build it */
-            wcscpy(BatchCommandLine, CMD_STRING);
-            if (CmdLineIsAppName || FoundQuotes)
+            // There is no break here on purpose, so FORCEDOS drops down!
+        }
+
+        case STATUS_INVALID_IMAGE_PROTECT:
+        case STATUS_INVALID_IMAGE_NOT_MZ:
+        case STATUS_INVALID_IMAGE_NE_FORMAT:
+        {
+            /* We're launching an executable application */
+            BinarySubType = BINARY_TYPE_EXE;
+
+            /* We can drop here from other "cases" above too, so check */
+            if ((Status == STATUS_INVALID_IMAGE_PROTECT) ||
+                (Status == STATUS_INVALID_IMAGE_NE_FORMAT) ||
+                (BinarySubType = BaseIsDosApplication(&PathName, Status)))
             {
-                wcscat(BatchCommandLine, L"\"");
+                /* We're launching a DOS application */
+                VdmBinaryType = BINARY_TYPE_DOS;
+
+                /* Based on the caller environment, create a VDM one */
+                Result = BaseCreateVDMEnvironment(lpEnvironment,
+                                                  &VdmAnsiEnv,
+                                                  &VdmUnicodeEnv);
+                if (!Result)
+                {
+                    DPRINT1("VDM environment for DOS failed\n");
+                    goto Quickie;
+                }
+
+                /* Check the current state of the VDM subsystem */
+                Status = BaseCheckVDM(VdmBinaryType | BinarySubType,
+                                      lpApplicationName,
+                                      lpCommandLine,
+                                      lpCurrentDirectory,
+                                      &VdmAnsiEnv,
+                                      &CsrMsg,
+                                      &VdmTask,
+                                      dwCreationFlags,
+                                      &StartupInfo,
+                                      NULL);
+                if (!NT_SUCCESS(Status))
+                {
+                    /* Failed to inquire about VDM, fail the call */
+                    DPRINT1("VDM message failure for DOS: %lx\n", Status);
+                    BaseSetLastNTError(Status);
+                    Result = FALSE;
+                    goto Quickie;
+                };
+
+                /* Handle possible VDM states */
+                switch (CheckVdmMsg->VDMState & (VDM_NOT_LOADED |
+                                                 VDM_NOT_READY |
+                                                 VDM_READY))
+                {
+                    case VDM_NOT_LOADED:
+                        /* If VDM is not loaded, we'll do a partial undo */
+                        VdmUndoLevel = VDM_UNDO_PARTIAL;
+
+                        /* A VDM process can't also be detached, so fail */
+                        if (dwCreationFlags & DETACHED_PROCESS)
+                        {
+                            DPRINT1("Detached process but no VDM, not allowed\n");
+                            SetLastError(ERROR_ACCESS_DENIED);
+                            return FALSE;
+                        }
+
+                        /* Get the required parameters and names for launch */
+                        Result = BaseGetVdmConfigInfo(lpCommandLine,
+                                                      VdmTask,
+                                                      VdmBinaryType,
+                                                      &VdmString,
+                                                      &VdmReserve);
+                        if (!Result)
+                        {
+                            DPRINT1("VDM Configuration failed for DOS\n");
+                            BaseSetLastNTError(Status);
+                            goto Quickie;
+                        }
+
+                        /* Update the command-line to launch VDM instead */
+                        lpCommandLine = VdmString.Buffer;
+                        lpApplicationName = NULL;
+                        break;
+
+                    case VDM_READY:
+                        /* VDM is ready, so we have to undo everything */
+                        VdmUndoLevel = VDM_UNDO_REUSE;
+
+                        /* Check if CSRSS wants us to wait on VDM */
+                        VdmWaitObject = CheckVdmMsg->WaitObjectForParent;
+                        break;
+
+                    case VDM_NOT_READY:
+                        /* Something is wrong with VDM, we'll fail the call */
+                        DPRINT1("VDM is not ready for DOS\n");
+                        SetLastError(ERROR_NOT_READY);
+                        Result = FALSE;
+                        goto Quickie;
+
+                    default:
+                        break;
+                }
+
+                /* Since to get NULL, we allocate from 0x1, account for this */
+                VdmReserve--;
+
+                /* This implies VDM is ready, so skip everything else */
+                if (VdmWaitObject) goto VdmShortCircuit;
+
+                /* Don't inherit handles since we're doing VDM now */
+                bInheritHandles = FALSE;
+
+                /* Had the user passed in environment? If so, destroy it */
+                if ((lpEnvironment) &&
+                    !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+                {
+                    RtlDestroyEnvironment(lpEnvironment);
+                }
+
+                /* Use our VDM Unicode environment instead */
+                lpEnvironment = VdmUnicodeEnv.Buffer;
             }
-            wcscat(BatchCommandLine, lpCommandLine);
-            if (CmdLineIsAppName || FoundQuotes)
+            else
             {
-                wcscat(BatchCommandLine, L"\"");
-            }
+                /* It's a batch file, get the extension */
+                ExtBuffer = &PathName.Buffer[PathName.Length / sizeof(WCHAR) - 4];
 
-            /* Create it as a Unicode String */
-            RtlInitUnicodeString(&CommandLineString, BatchCommandLine);
+                /* Make sure the extensions are correct */
+                if ((PathName.Length < (4 * sizeof(WCHAR))) ||
+                    ((_wcsnicmp(ExtBuffer, L".bat", 4)) &&
+                     (_wcsnicmp(ExtBuffer, L".cmd", 4))))
+                {
+                    DPRINT1("'%wZ': Invalid EXE, and not a batch or script file\n", &PathName);
+                    SetLastError(ERROR_BAD_EXE_FORMAT);
+                    Result = FALSE;
+                    goto Quickie;
+                }
 
-            /* Set the command line to this */
-            lpCommandLine = CommandLineString.Buffer;
-            lpApplicationName = NULL;
+                /* Check if we need to account for quotes around the path */
+                CmdQuoteLength = CmdLineIsAppName || HasQuotes;
+                if (!CmdLineIsAppName)
+                {
+                    if (HasQuotes) CmdQuoteLength++;
+                }
+                else
+                {
+                    CmdQuoteLength++;
+                }
 
-            /* Free memory */
-            RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
-            ApplicationName.Buffer = NULL;
-            goto GetAppName;
-            break;
+                /* Calculate the length of the command line */
+                CmdLineLength = wcslen(lpCommandLine);
+                CmdLineLength += wcslen(CMD_STRING);
+                CmdLineLength += CmdQuoteLength + sizeof(ANSI_NULL);
+                CmdLineLength *= sizeof(WCHAR);
+
+                /* Allocate space for the new command line */
+                AnsiCmdCommand = RtlAllocateHeap(RtlGetProcessHeap(),
+                                                 0,
+                                                 CmdLineLength);
+                if (!AnsiCmdCommand)
+                {
+                    BaseSetLastNTError(STATUS_NO_MEMORY);
+                    Result = FALSE;
+                    goto Quickie;
+                }
 
-            case STATUS_INVALID_IMAGE_WIN_16:
+                /* Build it */
+                wcscpy(AnsiCmdCommand, CMD_STRING);
+                if ((CmdLineIsAppName) || (HasQuotes))
+                {
+                    wcscat(AnsiCmdCommand, L"\"");
+                }
+                wcscat(AnsiCmdCommand, lpCommandLine);
+                if ((CmdLineIsAppName) || (HasQuotes))
+                {
+                    wcscat(AnsiCmdCommand, L"\"");
+                }
 
-                /* It's a Win16 Image, use VDM */
-                DPRINT1("Launching VDM...\n");
-                RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
-                RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
-                return CreateProcessW(L"ntvdm.exe",
-                                      (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */
-                                      lpProcessAttributes,
-                                      lpThreadAttributes,
-                                      bInheritHandles,
-                                      dwCreationFlags,
-                                      lpEnvironment,
-                                      lpCurrentDirectory,
-                                      &StartupInfo,
-                                      lpProcessInformation);
+                /* Create it as a Unicode String */
+                RtlInitUnicodeString(&DebuggerString, AnsiCmdCommand);
 
-            case STATUS_OBJECT_NAME_NOT_FOUND:
-            case STATUS_OBJECT_PATH_NOT_FOUND:
-                BaseSetLastNTError(Status);
-                goto Cleanup;
+                /* Set the command line to this */
+                lpCommandLine = DebuggerString.Buffer;
+                lpApplicationName = NULL;
+                DPRINT1("Retrying with: %S\n", lpCommandLine);
+            }
 
-            default:
-                /* Invalid Image Type */
+            /* We've already done all these checks, don't do them again */
+            SkipSaferAndAppCompat = TRUE;
+            goto AppNameRetry;
+        }
+
+        case STATUS_INVALID_IMAGE_WIN_64:
+        {
+            /* 64-bit binaries are not allowed to run on 32-bit ReactOS */
+            DPRINT1("64-bit binary, failing\n");
+            SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH);
+            Result = FALSE;
+            goto Quickie;
+        }
+
+        case STATUS_FILE_IS_OFFLINE:
+        {
+            /* Set the correct last error for this */
+            DPRINT1("File is offline, failing\n");
+            SetLastError(ERROR_FILE_OFFLINE);
+            break;
+        }
+
+        default:
+        {
+            /* Any other error, convert it to a generic Win32 error */
+            if (!NT_SUCCESS(Status))
+            {
+                DPRINT1("Failed to create section: %lx\n", Status);
                 SetLastError(ERROR_BAD_EXE_FORMAT);
-                goto Cleanup;
+                Result = FALSE;
+                goto Quickie;
+            }
+
+            /* Otherwise, this must be success */
+            ASSERT(Status == STATUS_SUCCESS);
+            break;
         }
     }
 
-    /* Use our desktop if we didn't get any */
-    if (!StartupInfo.lpDesktop)
+    /* Is this not a WOW application, but a WOW32 VDM was requested for it? */
+    if (!(IsWowApp) && (dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
     {
-        StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer;
+        /* Ignore the nonsensical request */
+        dwCreationFlags &= ~CREATE_SEPARATE_WOW_VDM;
     }
 
-    /* FIXME: Check if Application is allowed to run */
+    /* Did we already check information for the section? */
+    if (!QuerySection)
+    {
+        /* Get some information about the executable */
+        Status = NtQuerySection(SectionHandle,
+                                SectionImageInformation,
+                                &ImageInformation,
+                                sizeof(ImageInformation),
+                                NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            /* We failed, bail out */
+            DPRINT1("Section query failed\n");
+            BaseSetLastNTError(Status);
+            Result = FALSE;
+            goto Quickie;
+        }
 
-    /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
+        /* Don't check this later */
+        QuerySection = TRUE;
+    }
 
-    /* Get some information about the executable */
-    Status = ZwQuerySection(hSection,
-                            SectionImageInformation,
-                            &SectionImageInfo,
-                            sizeof(SectionImageInfo),
-                            NULL);
-    if(!NT_SUCCESS(Status))
+    /* Check if this was linked as a DLL */
+    if (ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL)
     {
-        DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status);
-        BaseSetLastNTError(Status);
-        goto Cleanup;
+        /* These aren't valid images to try to execute! */
+        DPRINT1("Trying to launch a DLL, failing\n");
+        SetLastError(ERROR_BAD_EXE_FORMAT);
+        Result = FALSE;
+        goto Quickie;
     }
 
-    /* Don't execute DLLs */
-    if (SectionImageInfo.ImageCharacteristics & IMAGE_FILE_DLL)
+    /* Don't let callers pass in this flag -- we'll only get it from IFRO */
+    Flags &= ~PROCESS_CREATE_FLAGS_LARGE_PAGES;
+
+    /* Clear the IFEO-missing flag, before we know for sure... */
+    ParameterFlags &= ~2;
+
+    /* If the process is being debugged, only read IFEO if the PEB says so */
+    if (!(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) ||
+        (NtCurrentPeb()->ReadImageFileExecOptions))
     {
-        DPRINT1("Can't execute a DLL\n");
-        SetLastError(ERROR_BAD_EXE_FORMAT);
-        goto Cleanup;
+        /* Let's do this! Attempt to open IFEO */
+        Status1 = LdrOpenImageFileOptionsKey(&PathName, 0, &KeyHandle);
+        if (!NT_SUCCESS(Status1))
+        {
+            /* We failed, set the flag so we store this in the parameters */
+            if (Status1 == STATUS_OBJECT_NAME_NOT_FOUND) ParameterFlags |= 2;
+        }
+        else
+        {
+            /* Was this our first time going through this path? */
+            if (!DebuggerCmdLine)
+            {
+                /* Allocate a buffer for the debugger path */
+                DebuggerCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
+                                                  0,
+                                                  MAX_PATH * sizeof(WCHAR));
+                if (!DebuggerCmdLine)
+                {
+                    /* Close IFEO on failure */
+                    Status1 = NtClose(KeyHandle);
+                    ASSERT(NT_SUCCESS(Status1));
+
+                    /* Fail the call */
+                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                    Result = FALSE;
+                    goto Quickie;
+                }
+            }
+
+            /* Now query for the debugger */
+            Status1 = LdrQueryImageFileKeyOption(KeyHandle,
+                                                 L"Debugger",
+                                                 REG_SZ,
+                                                 DebuggerCmdLine,
+                                                 MAX_PATH * sizeof(WCHAR),
+                                                 &ResultSize);
+            if (!(NT_SUCCESS(Status1)) ||
+                (ResultSize < sizeof(WCHAR)) ||
+                (DebuggerCmdLine[0] == UNICODE_NULL))
+            {
+                /* If it's not there, or too small, or invalid, ignore it */
+                RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
+                DebuggerCmdLine = NULL;
+            }
+
+            /* Also query if we should map with large pages */
+            Status1 = LdrQueryImageFileKeyOption(KeyHandle,
+                                                 L"UseLargePages",
+                                                 REG_DWORD,
+                                                 &UseLargePages,
+                                                 sizeof(UseLargePages),
+                                                 NULL);
+            if ((NT_SUCCESS(Status1)) && (UseLargePages))
+            {
+                /* Do it! This is the only way this flag can be set */
+                Flags |= PROCESS_CREATE_FLAGS_LARGE_PAGES;
+            }
+
+            /* We're done with IFEO, can close it now */
+            Status1 = NtClose(KeyHandle);
+            ASSERT(NT_SUCCESS(Status1));
+        }
     }
 
-    /* FIXME: Check for Debugger */
+    /* Make sure the image was compiled for this processor */
+    if ((ImageInformation.Machine < SharedUserData->ImageNumberLow) ||
+        (ImageInformation.Machine > SharedUserData->ImageNumberHigh))
+    {
+        /* It was not -- raise a hard error */
+        ErrorResponse = ResponseOk;
+        ErrorParameters[0] = (ULONG_PTR)&PathName;
+        NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE,
+                         1,
+                         1,
+                         ErrorParameters,
+                         OptionOk,
+                         &ErrorResponse);
+        if (Peb->ImageSubsystemMajorVersion <= 3)
+        {
+            /* If it's really old, return this error */
+            SetLastError(ERROR_BAD_EXE_FORMAT);
+        }
+        else
+        {
+            /* Otherwise, return a more modern error */
+            SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH);
+        }
 
-    /* FIXME: Check if Machine Type and SubSys Version Match */
+        /* Go to the failure path */
+        DPRINT1("Invalid image architecture: %lx\n", ImageInformation.Machine);
+        Result = FALSE;
+        goto Quickie;
+    }
 
-    /* We don't support POSIX or anything else for now */
-    if (IMAGE_SUBSYSTEM_WINDOWS_GUI != SectionImageInfo.SubSystemType &&
-        IMAGE_SUBSYSTEM_WINDOWS_CUI != SectionImageInfo.SubSystemType)
+    /* Check if this isn't a Windows image */
+    if ((ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI) &&
+        (ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI))
     {
-        DPRINT1("Invalid subsystem %d\n", SectionImageInfo.SubSystemType);
+        /* Get rid of section-related information since we'll retry */
+        NtClose(SectionHandle);
+        SectionHandle = NULL;
+        QuerySection = FALSE;
+
+        /* The only other non-Windows image type we support here is POSIX */
+        if (ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_POSIX_CUI)
+        {
+            /* Bail out if it's something else */
+            SetLastError(ERROR_CHILD_NOT_COMPLETE);
+            Result = FALSE;
+            goto Quickie;
+        }
+
+        /* Now build the command-line to have posix launch this image */
+        Result = BuildSubSysCommandLine(L"POSIX /P ",
+                                        lpApplicationName,
+                                        lpCommandLine,
+                                        &DebuggerString);
+        if (!Result)
+        {
+            /* Bail out if that failed */
+            DPRINT1("Subsystem command line failed\n");
+            goto Quickie;
+        }
+
+        /* And re-try launching the process, with the new command-line now */
+        lpCommandLine = DebuggerString.Buffer;
+        lpApplicationName = NULL;
+
+        /* We've already done all these checks, don't do them again */
+        SkipSaferAndAppCompat = TRUE;
+        DPRINT1("Retrying with: %S\n", lpCommandLine);
+        goto AppNameRetry;
+    }
+
+    /* Was this image built for a version of Windows whose images we can run? */
+    Result = BasepIsImageVersionOk(ImageInformation.SubSystemMajorVersion,
+                                   ImageInformation.SubSystemMinorVersion);
+    if (!Result)
+    {
+        /* It was not, bail out */
+        DPRINT1("Invalid subsystem version: %hu.%hu\n",
+                ImageInformation.SubSystemMajorVersion,
+                ImageInformation.SubSystemMinorVersion);
         SetLastError(ERROR_BAD_EXE_FORMAT);
-        goto Cleanup;
+        goto Quickie;
     }
 
-    if (IMAGE_SUBSYSTEM_WINDOWS_GUI == SectionImageInfo.SubSystemType)
-    {
-        /* Do not create a console for GUI applications */
-        dwCreationFlags &= ~CREATE_NEW_CONSOLE;
-        dwCreationFlags |= DETACHED_PROCESS;
+    /* Check if there is a debugger associated with the application */
+    if (DebuggerCmdLine)
+    {
+        /* Get the length of the command line */
+        n = wcslen(lpCommandLine);
+        if (!n)
+        {
+            /* There's no command line, use the application name instead */
+            lpCommandLine = (LPWSTR)lpApplicationName;
+            n = wcslen(lpCommandLine);
+        }
+
+        /* Protect against overflow */
+        if (n > UNICODE_STRING_MAX_CHARS)
+        {
+            BaseSetLastNTError(STATUS_NAME_TOO_LONG);
+            Result = FALSE;
+            goto Quickie;
+        }
+
+        /* Now add the length of the debugger command-line */
+        n += wcslen(DebuggerCmdLine);
+
+        /* Again make sure we don't overflow */
+        if (n > UNICODE_STRING_MAX_CHARS)
+        {
+            BaseSetLastNTError(STATUS_NAME_TOO_LONG);
+            Result = FALSE;
+            goto Quickie;
+        }
+
+        /* Account for the quotes and space between the two */
+        n += sizeof("\" \"") - sizeof(ANSI_NULL);
+
+        /* Convert to bytes, and make sure we don't overflow */
+        n *= sizeof(WCHAR);
+        if (n > UNICODE_STRING_MAX_BYTES)
+        {
+            BaseSetLastNTError(STATUS_NAME_TOO_LONG);
+            Result = FALSE;
+            goto Quickie;
+        }
+
+        /* Allocate space for the string */
+        DebuggerString.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, n);
+        if (!DebuggerString.Buffer)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            Result = FALSE;
+            goto Quickie;
+        }
+
+        /* Set the length */
+        RtlInitEmptyUnicodeString(&DebuggerString,
+                                  DebuggerString.Buffer,
+                                  (USHORT)n);
+
+        /* Now perform the command line creation */
+        ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString,
+                                                  DebuggerCmdLine);
+        ASSERT(NT_SUCCESS(ImageDbgStatus));
+        ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString, L" ");
+        ASSERT(NT_SUCCESS(ImageDbgStatus));
+        ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString, lpCommandLine);
+        ASSERT(NT_SUCCESS(ImageDbgStatus));
+
+        /* Make sure it all looks nice */
+        DbgPrint("BASE: Calling debugger with '%wZ'\n", &DebuggerString);
+
+        /* Update the command line and application name */
+        lpCommandLine = DebuggerString.Buffer;
+        lpApplicationName = NULL;
+
+        /* Close all temporary state */
+        NtClose(SectionHandle);
+        SectionHandle = NULL;
+        QuerySection = FALSE;
+
+        /* Free all temporary memory */
+        RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
+        NameBuffer = NULL;
+        RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
+        FreeBuffer = NULL;
+        RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
+        DebuggerCmdLine = NULL;
+        DPRINT1("Retrying with: %S\n", lpCommandLine);
+        goto AppNameRetry;
     }
 
     /* Initialize the process object attributes */
     ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
-                                                    lpProcessAttributes,
-                                                    NULL);
+                                                  lpProcessAttributes,
+                                                  NULL);
+    if ((hUserToken) && (lpProcessAttributes))
+    {
+        /* Auggment them with information from the user */
+
+        LocalProcessAttributes = *lpProcessAttributes;
+        LocalProcessAttributes.lpSecurityDescriptor = NULL;
+        ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
+                                                      &LocalProcessAttributes,
+                                                      NULL);
+    }
 
     /* Check if we're going to be debugged */
     if (dwCreationFlags & DEBUG_PROCESS)
     {
-        /* FIXME: Set process flag */
+        /* Set process flag */
+        Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY;
     }
 
     /* Check if we're going to be debugged */
@@ -2673,288 +3849,755 @@ GetAppName:
         {
             DPRINT1("Failed to connect to DbgUI!\n");
             BaseSetLastNTError(Status);
-            goto Cleanup;
+            Result = FALSE;
+            goto Quickie;
         }
 
         /* Get the debug object */
-        hDebug = DbgUiGetThreadDebugObject();
+        DebugHandle = DbgUiGetThreadDebugObject();
 
         /* Check if only this process will be debugged */
         if (dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
         {
-            /* FIXME: Set process flag */
+            /* Set process flag */
+            Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT;
         }
     }
 
-    /* Create the Process */
-    Status = NtCreateProcess(&hProcess,
-                             PROCESS_ALL_ACCESS,
-                             ObjectAttributes,
-                             NtCurrentProcess(),
-                             (BOOLEAN)bInheritHandles,
-                             hSection,
-                             hDebug,
-                             NULL);
+    /* Set inherit flag */
+    if (bInheritHandles) Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
+
+    /* Check if the process should be created with large pages */
+    HavePrivilege = FALSE;
+    PrivilegeState = NULL;
+    if (Flags & PROCESS_CREATE_FLAGS_LARGE_PAGES)
+    {
+        /* Acquire the required privilege so that the kernel won't fail the call */
+        PrivilegeValue = SE_LOCK_MEMORY_PRIVILEGE;
+        Status = RtlAcquirePrivilege(&PrivilegeValue, TRUE, FALSE, &PrivilegeState);
+        if (NT_SUCCESS(Status))
+        {
+            /* Remember to release it later */
+            HavePrivilege = TRUE;
+        }
+    }
+
+    /* Save the current TIB value since kernel overwrites it to store PEB */
+    TibValue = Teb->NtTib.ArbitraryUserPointer;
+
+    /* Tell the kernel to create the process */
+    Status = NtCreateProcessEx(&ProcessHandle,
+                               PROCESS_ALL_ACCESS,
+                               ObjectAttributes,
+                               NtCurrentProcess(),
+                               Flags,
+                               SectionHandle,
+                               DebugHandle,
+                               NULL,
+                               InJob);
+
+    /* Load the PEB address from the hacky location where the kernel stores it */
+    RemotePeb = Teb->NtTib.ArbitraryUserPointer;
+
+    /* And restore the old TIB value */
+    Teb->NtTib.ArbitraryUserPointer = TibValue;
+
+    /* Release the large page privilege if we had acquired it */
+    if (HavePrivilege) RtlReleasePrivilege(PrivilegeState);
+
+    /* And now check if the kernel failed to create the process */
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Unable to create process, status 0x%x\n", Status);
+        /* Go to failure path */
+        DPRINT1("Failed to create process: %lx\n", Status);
         BaseSetLastNTError(Status);
-        goto Cleanup;
+        Result = FALSE;
+        goto Quickie;
     }
 
-    if (PriorityClass.PriorityClass != PROCESS_PRIORITY_CLASS_INVALID)
+    /* Check if there is a priority class to set */
+    if (PriorityClass.PriorityClass)
     {
-        /* Set new class */
-        Status = NtSetInformationProcess(hProcess,
+        /* Reset current privilege state */
+        RealTimePrivilegeState = NULL;
+
+        /* Is realtime priority being requested? */
+        if (PriorityClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME)
+        {
+            /* Check if the caller has real-time access, and enable it if so */
+            RealTimePrivilegeState = BasepIsRealtimeAllowed(TRUE);
+        }
+
+        /* Set the new priority class and release the privilege */
+        Status = NtSetInformationProcess(ProcessHandle,
                                          ProcessPriorityClass,
                                          &PriorityClass,
                                          sizeof(PROCESS_PRIORITY_CLASS));
-        if(!NT_SUCCESS(Status))
+        if (RealTimePrivilegeState) RtlReleasePrivilege(RealTimePrivilegeState);
+
+        /* Check if we failed to set the priority class */
+        if (!NT_SUCCESS(Status))
         {
-            DPRINT1("Unable to set new process priority, status 0x%x\n", Status);
+            /* Bail out on failure */
+            DPRINT1("Failed to set priority class: %lx\n", Status);
             BaseSetLastNTError(Status);
-            goto Cleanup;
+            Result = FALSE;
+            goto Quickie;
         }
     }
 
-    /* Set Error Mode */
+    /* Check if the caller wants the default error mode */
     if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
     {
-        ULONG ErrorMode = SEM_FAILCRITICALERRORS;
-        NtSetInformationProcess(hProcess,
+        /* Set Error Mode to only fail on critical errors */
+        HardErrorMode = SEM_FAILCRITICALERRORS;
+        NtSetInformationProcess(ProcessHandle,
                                 ProcessDefaultHardErrorMode,
-                                &ErrorMode,
+                                &HardErrorMode,
                                 sizeof(ULONG));
     }
 
-    /* Convert the directory to a full path */
+    /* Check if this was a VDM binary */
+    if (VdmBinaryType)
+    {
+        /* Update VDM by telling it the process has now been created */
+        VdmWaitObject = ProcessHandle;
+        Result = BaseUpdateVDMEntry(VdmEntryUpdateProcess,
+                                    &VdmWaitObject,
+                                    VdmTask,
+                                    VdmBinaryType);
+        {
+            /* Bail out on failure */
+            DPRINT1("Failed to update VDM with wait object\n");
+            VdmWaitObject = NULL;
+            goto Quickie;
+        }
+
+        /* At this point, a failure means VDM has to undo all the state */
+        VdmUndoLevel |= VDM_UNDO_FULL;
+    }
+
+    /* Check if VDM needed reserved low-memory */
+    if (VdmReserve)
+    {
+        /* Reserve the requested allocation */
+        Status = NtAllocateVirtualMemory(ProcessHandle,
+                                         &BaseAddress,
+                                         0,
+                                         &VdmReserve,
+                                         MEM_RESERVE,
+                                         PAGE_EXECUTE_READWRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Bail out on failure */
+            DPRINT1("Failed to reserved memory for VDM: %lx\n", Status);
+            BaseSetLastNTError(Status);
+            Result = FALSE;
+            goto Quickie;
+        }
+    }
+
+    /* Check if we've already queried information on the section */
+    if (!QuerySection)
+    {
+        /* We haven't, so get some information about the executable */
+        Status = NtQuerySection(SectionHandle,
+                                SectionImageInformation,
+                                &ImageInformation,
+                                sizeof(ImageInformation),
+                                NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Bail out on failure */
+            DPRINT1("Failed to query section: %lx\n", Status);
+            BaseSetLastNTError(Status);
+            Result = FALSE;
+            goto Quickie;
+        }
+
+        /* If we encounter a restart, don't re-query this information again */
+        QuerySection = TRUE;
+    }
+
+    /* Do we need to apply SxS to this image? */
+    if (!(ImageInformation.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_ISOLATION))
+    {
+        /* Too bad, we don't support this yet */
+        DPRINT1("Image should receive SxS Fusion Isolation\n");
+    }
+
+    /* There's some SxS flag that we need to set if fusion flags have 1 set */
+    if (FusionFlags & 1) CreateProcessMsg->Sxs.Flags |= 0x10;
+
+    /* Check if we have a current directory */
     if (lpCurrentDirectory)
     {
-        /* Allocate a buffer */
+        /* Allocate a buffer so we can keep a Unicode copy */
+        DPRINT1("Current directory: %S\n", lpCurrentDirectory);
         CurrentDirectory = RtlAllocateHeap(RtlGetProcessHeap(),
                                            0,
-                                           (MAX_PATH + 1) * sizeof(WCHAR));
-        if (CurrentDirectory == NULL)
+                                           (MAX_PATH * sizeof(WCHAR)) +
+                                           sizeof(UNICODE_NULL));
+        if (!CurrentDirectory)
         {
-            DPRINT1("Cannot allocate memory for directory name\n");
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto Cleanup;
+            /* Bail out if this failed */
+            BaseSetLastNTError(STATUS_NO_MEMORY);
+            Result = FALSE;
+            goto Quickie;
         }
 
-        /* Get the length */
-        if (GetFullPathNameW(lpCurrentDirectory,
-                             MAX_PATH,
-                             CurrentDirectory,
-                             &CurrentDirectoryPart) > MAX_PATH)
+        /* Get the length in Unicode */
+        Length = GetFullPathNameW(lpCurrentDirectory,
+                                  MAX_PATH,
+                                  CurrentDirectory,
+                                  &FilePart);
+        if (Length > MAX_PATH)
         {
-            DPRINT1("Directory name too long\n");
+            /* The directory is too long, so bail out */
             SetLastError(ERROR_DIRECTORY);
-            goto Cleanup;
+            Result = FALSE;
+            goto Quickie;
+        }
+
+        /* Make sure the directory is actually valid */
+        CurdirLength = GetFileAttributesW(CurrentDirectory);
+        if ((CurdirLength == 0xffffffff) ||
+           !(CurdirLength & FILE_ATTRIBUTE_DIRECTORY))
+        {
+            /* It isn't, so bail out */
+            DPRINT1("Current directory is invalid\n");
+            SetLastError(ERROR_DIRECTORY);
+            Result = FALSE;
+            goto Quickie;
         }
     }
 
     /* Insert quotes if needed */
-    if (QuotesNeeded || CmdLineIsAppName)
+    if ((QuotesNeeded) || (CmdLineIsAppName))
     {
-        /* Allocate a buffer */
+        /* Allocate our buffer, plus enough space for quotes and a NULL */
         QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
                                         0,
-                                        (wcslen(lpCommandLine) + 2 + 1) *
-                                        sizeof(WCHAR));
-        if (QuotedCmdLine == NULL)
+                                        (wcslen(lpCommandLine) * sizeof(WCHAR)) +
+                                        (2 * sizeof(L'\"') + sizeof(UNICODE_NULL)));
+        if (QuotedCmdLine)
         {
-            DPRINT1("Cannot allocate memory for quoted command line\n");
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto Cleanup;
-        }
+            /* Copy the first quote */
+            wcscpy(QuotedCmdLine, L"\"");
 
-        /* Copy the first quote */
-        wcscpy(QuotedCmdLine, L"\"");
-
-        /* Save a null char */
-        if (QuotesNeeded)
-        {
-            SaveChar = *NullBuffer;
-            *NullBuffer = UNICODE_NULL;
-        }
+            /* Save the current null-character */
+            if (QuotesNeeded)
+            {
+                SaveChar = *NullBuffer;
+                *NullBuffer = UNICODE_NULL;
+            }
 
-        /* Add the command line and the finishing quote */
-        wcscat(QuotedCmdLine, lpCommandLine);
-        wcscat(QuotedCmdLine, L"\"");
+            /* Copy the command line and the final quote */
+            wcscat(QuotedCmdLine, lpCommandLine);
+            wcscat(QuotedCmdLine, L"\"");
 
-        /* Add the null char */
-        if (QuotesNeeded)
+            /* Copy the null-char back */
+            if (QuotesNeeded)
+            {
+                *NullBuffer = SaveChar;
+                wcscat(QuotedCmdLine, NullBuffer);
+            }
+        }
+        else
         {
-            *NullBuffer = SaveChar;
-            wcscat(QuotedCmdLine, NullBuffer);
+            /* We can't put quotes around the thing, so try it anyway */
+            if (QuotesNeeded) QuotesNeeded = FALSE;
+            if (CmdLineIsAppName) CmdLineIsAppName = FALSE;
         }
-
-        DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine);
     }
 
-    if (Escape)
+    /* Use isolation if needed */
+    if (CreateProcessMsg->Sxs.Flags & 1) ParameterFlags |= 1;
+
+    /* Set the new command-line if needed */
+    if ((QuotesNeeded) || (CmdLineIsAppName)) lpCommandLine = QuotedCmdLine;
+
+    /* Call the helper function in charge of RTL_USER_PROCESS_PARAMETERS */
+    Result = BasePushProcessParameters(ParameterFlags,
+                                       ProcessHandle,
+                                       RemotePeb,
+                                       lpApplicationName,
+                                       CurrentDirectory,
+                                       lpCommandLine,
+                                       lpEnvironment,
+                                       &StartupInfo,
+                                       dwCreationFlags | NoWindow,
+                                       bInheritHandles,
+                                       IsWowApp ? IMAGE_SUBSYSTEM_WINDOWS_GUI: 0,
+                                       AppCompatData,
+                                       AppCompatDataSize);
+    if (!Result)
+    {
+        /* The remote process would have an undefined state, so fail the call */
+        DPRINT1("BasePushProcessParameters failed\n");
+        goto Quickie;
+    }
+
+    /* Free the VDM command line string as it's no longer needed */
+    RtlFreeUnicodeString(&VdmString);
+    VdmString.Buffer = NULL;
+
+    /* Non-VDM console applications usually inherit handles unless specified */
+    if (!(VdmBinaryType) &&
+        !(bInheritHandles) &&
+        !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
+        !(dwCreationFlags & (CREATE_NO_WINDOW |
+                             CREATE_NEW_CONSOLE |
+                             DETACHED_PROCESS)) &&
+        (ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI))
     {
-        if (QuotedCmdLine == NULL)
+        /* Get the remote parameters */
+        Status = NtReadVirtualMemory(ProcessHandle,
+                                     &RemotePeb->ProcessParameters,
+                                     &ProcessParameters,
+                                     sizeof(PRTL_USER_PROCESS_PARAMETERS),
+                                     NULL);
+        if (NT_SUCCESS(Status))
         {
-            QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
-                                            0,
-                                            (wcslen(lpCommandLine) + 1) * sizeof(WCHAR));
-            if (QuotedCmdLine == NULL)
+            /* Duplicate standard input unless it's a console handle */
+            if (!IsConsoleHandle(Peb->ProcessParameters->StandardInput))
             {
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                goto Cleanup;
+                StuffStdHandle(ProcessHandle,
+                               Peb->ProcessParameters->StandardInput,
+                               &ProcessParameters->StandardInput);
             }
-            wcscpy(QuotedCmdLine, lpCommandLine);
-        }
 
-        ScanString = QuotedCmdLine;
-        while (NULL != (ScanString = wcschr(ScanString, L'^')))
-        {
-            ScanString++;
-            if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\\')
+            /* Duplicate standard output unless it's a console handle */
+            if (!IsConsoleHandle(Peb->ProcessParameters->StandardOutput))
+            {
+                StuffStdHandle(ProcessHandle,
+                               Peb->ProcessParameters->StandardOutput,
+                               &ProcessParameters->StandardOutput);
+            }
+
+            /* Duplicate standard error unless it's a console handle */
+            if (!IsConsoleHandle(Peb->ProcessParameters->StandardError))
             {
-                memmove(ScanString-1, ScanString, wcslen(ScanString) * sizeof(WCHAR) + sizeof(WCHAR));
+                StuffStdHandle(ProcessHandle,
+                               Peb->ProcessParameters->StandardError,
+                               &ProcessParameters->StandardError);
             }
         }
     }
 
-    /* Get the Process Information */
-    Status = NtQueryInformationProcess(hProcess,
-                                       ProcessBasicInformation,
-                                       &ProcessBasicInfo,
-                                       sizeof(ProcessBasicInfo),
-                                       NULL);
-
-    /* Convert the environment */
-    if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+    /* Create the Thread's Stack */
+    StackSize = max(256 * 1024, ImageInformation.MaximumStackSize);
+    Status = BaseCreateStack(ProcessHandle,
+                             ImageInformation.CommittedStackSize,
+                             StackSize,
+                             &InitialTeb);
+    if (!NT_SUCCESS(Status))
     {
-        lpEnvironment = BasepConvertUnicodeEnvironment(&EnvSize, lpEnvironment);
-        if (!lpEnvironment) goto Cleanup;
+        DPRINT1("Creating the thread stack failed: %lx\n", Status);
+        BaseSetLastNTError(Status);
+        Result = FALSE;
+        goto Quickie;
     }
 
-    /* Create Process Environment */
-    RemotePeb = ProcessBasicInfo.PebBaseAddress;
-    Status = BasepInitializeEnvironment(hProcess,
-                                        RemotePeb,
-                                        (LPWSTR)lpApplicationName,
-                                        CurrentDirectory,
-                                        (QuotesNeeded || CmdLineIsAppName || Escape) ?
-                                        QuotedCmdLine : lpCommandLine,
-                                        lpEnvironment,
-                                        EnvSize,
-                                        &StartupInfo,
-                                        dwCreationFlags,
-                                        bInheritHandles);
+    /* Create the Thread's Context */
+    BaseInitializeContext(&Context,
+                          Peb,
+                          ImageInformation.TransferAddress,
+                          InitialTeb.StackBase,
+                          0);
 
-    /* Cleanup Environment */
-    if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+    /* Convert the thread attributes */
+    ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
+                                                  lpThreadAttributes,
+                                                  NULL);
+    if ((hUserToken) && (lpThreadAttributes))
     {
-        RtlDestroyEnvironment(lpEnvironment);
+        /* If the caller specified a user token, zero the security descriptor */
+        LocalThreadAttributes = *lpThreadAttributes;
+        LocalThreadAttributes.lpSecurityDescriptor = NULL;
+        ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
+                                                      &LocalThreadAttributes,
+                                                      NULL);
     }
 
+    /* Create the Kernel Thread Object */
+    Status = NtCreateThread(&ThreadHandle,
+                            THREAD_ALL_ACCESS,
+                            ObjectAttributes,
+                            ProcessHandle,
+                            &ClientId,
+                            &Context,
+                            &InitialTeb,
+                            TRUE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Could not initialize Process Environment\n");
+        /* A process is not allowed to exist without a main thread, so fail */
+        DPRINT1("Creating the main thread failed: %lx\n", Status);
         BaseSetLastNTError(Status);
-        goto Cleanup;
+        Result = FALSE;
+        goto Quickie;
     }
 
-    /* Close the section */
-    NtClose(hSection);
-    hSection = NULL;
+    /* Begin filling out the CSRSS message, first with our IDs and handles */
+    CreateProcessMsg->ProcessHandle = ProcessHandle;
+    CreateProcessMsg->ThreadHandle = ThreadHandle;
+    CreateProcessMsg->ClientId = ClientId;
+
+    /* Write the remote PEB address and clear it locally, we no longer use it */
+    CreateProcessMsg->PebAddressNative = RemotePeb;
+    CreateProcessMsg->PebAddressWow64 = (ULONG)RemotePeb;
+    RemotePeb = NULL;
 
-    /* Duplicate the handles if needed */
-    if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
-        SectionImageInfo.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
+    /* Now check what kind of architecture this image was made for */
+    switch (ImageInformation.Machine)
     {
-        PRTL_USER_PROCESS_PARAMETERS RemoteParameters;
+        /* IA32, IA64 and AMD64 are supported in Server 2003 */
+        case IMAGE_FILE_MACHINE_I386:
+            CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
+            break;
+        case IMAGE_FILE_MACHINE_IA64:
+            CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64;
+            break;
+        case IMAGE_FILE_MACHINE_AMD64:
+            CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
+            break;
 
-        /* Get the remote parameters */
-        Status = NtReadVirtualMemory(hProcess,
-                                     &RemotePeb->ProcessParameters,
-                                     &RemoteParameters,
-                                     sizeof(PVOID),
-                                     NULL);
-        if (!NT_SUCCESS(Status))
+        /* Anything else results in image unknown -- but no failure */
+        default:
+            DbgPrint("kernel32: No mapping for ImageInformation.Machine == %04x\n",
+                     ImageInformation.Machine);
+            CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
+            break;
+    }
+
+    /* Write the input creation flags except any debugger-related flags */
+    CreateProcessMsg->CreationFlags = dwCreationFlags &
+                                      ~(DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS);
+
+    /* CSRSS needs to know if this is a GUI app or not */
+    if ((ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI) ||
+        (IsWowApp))
+    {
+        /*
+         * For GUI apps we turn on the 2nd bit. This allow CSRSS server dlls
+         * (basesrv in particular) to know whether or not this is a GUI or a
+         * TUI application.
+         */
+        AddToHandle(CreateProcessMsg->ProcessHandle, 2);
+
+        /* Also check if the parent is also a GUI process */
+        NtHeaders = RtlImageNtHeader(GetModuleHandle(NULL));
+        if ((NtHeaders) &&
+            (NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI))
         {
-            DPRINT1("Failed to read memory\n");
-            goto Cleanup;
+            /* Let it know that it should display the hourglass mouse cursor */
+            AddToHandle(CreateProcessMsg->ProcessHandle, 1);
         }
+    }
+
+    /* For all apps, if this flag is on, the hourglass mouse cursor is shown */
+    if (StartupInfo.dwFlags & STARTF_FORCEONFEEDBACK)
+    {
+        AddToHandle(CreateProcessMsg->ProcessHandle, 1);
+    }
 
-        /* Duplicate and write the handles */
-        BasepDuplicateAndWriteHandle(hProcess,
-                                     OurPeb->ProcessParameters->StandardInput,
-                                     &RemoteParameters->StandardInput);
-        BasepDuplicateAndWriteHandle(hProcess,
-                                     OurPeb->ProcessParameters->StandardOutput,
-                                     &RemoteParameters->StandardOutput);
-        BasepDuplicateAndWriteHandle(hProcess,
-                                     OurPeb->ProcessParameters->StandardError,
-                                     &RemoteParameters->StandardError);
+    /* Likewise, the opposite holds as well */
+    if (StartupInfo.dwFlags & STARTF_FORCEOFFFEEDBACK)
+    {
+        RemoveFromHandle(CreateProcessMsg->ProcessHandle, 1);
     }
 
-    /* Notify CSRSS */
-    Status = BasepNotifyCsrOfCreation(dwCreationFlags,
-                                      (HANDLE)ProcessBasicInfo.UniqueProcessId,
-                                      bInheritHandles);
+    /* Also store which kind of VDM app (if any) this is */
+    CreateProcessMsg->VdmBinaryType = VdmBinaryType;
 
-    if (!NT_SUCCESS(Status))
+    /* And if it really is a VDM app... */
+    if (VdmBinaryType)
     {
-        DPRINT1("CSR Notification Failed");
-        BaseSetLastNTError(Status);
-        goto Cleanup;
+        /* Store the task ID and VDM console handle */
+        CreateProcessMsg->hVDM = VdmTask ? 0 : Peb->ProcessParameters->ConsoleHandle;
+        CreateProcessMsg->VdmTask = VdmTask;
+    }
+    else if (VdmReserve)
+    {
+        /* Extended VDM, set a flag */
+        CreateProcessMsg->VdmBinaryType |= BINARY_TYPE_WOW_EX;
+    }
+
+    /* Check if there's side-by-side assembly data associated with the process */
+    if (CreateProcessMsg->Sxs.Flags)
+    {
+        /* This should not happen in ReactOS yet */
+        DPRINT1("This is an SxS Message -- should not happen yet\n");
+        BaseSetLastNTError(STATUS_NOT_IMPLEMENTED);
+        NtTerminateProcess(ProcessHandle, STATUS_NOT_IMPLEMENTED);
+        Result = FALSE;
+        goto Quickie;
+    }
+
+    /* We are finally ready to call CSRSS to tell it about our new process! */
+    CsrClientCallServer((PCSR_API_MESSAGE)&CsrMsg,
+                        CaptureBuffer,
+                        CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
+                                              BasepCreateProcess),
+                        sizeof(*CreateProcessMsg));
+
+    /* CSRSS has returned, free the capture buffer now if we had one */
+    if (CaptureBuffer)
+    {
+        CsrFreeCaptureBuffer(CaptureBuffer);
+        CaptureBuffer = NULL;
+    }
+
+    /* Check if CSRSS failed to accept ownership of the new Windows process */
+    if (!NT_SUCCESS(CsrMsg.Status))
+    {
+        /* Terminate the process and enter failure path with the CSRSS status */
+        DPRINT1("Failed to tell csrss about new process\n");
+        BaseSetLastNTError(CsrMsg.Status);
+        NtTerminateProcess(ProcessHandle, CsrMsg.Status);
+        Result = FALSE;
+        goto Quickie;
+    }
+
+    /* Check if we have a token due to Authz/Safer, not passed by the user */
+    if ((TokenHandle) && !(hUserToken))
+    {
+        /* Replace the process and/or thread token with the one from Safer */
+        Status = BasepReplaceProcessThreadTokens(TokenHandle,
+                                                 ProcessHandle,
+                                                 ThreadHandle);
+        if (!NT_SUCCESS(Status))
+        {
+            /* If this failed, kill the process and enter the failure path */
+            DPRINT1("Failed to update process token: %lx\n", Status);
+            NtTerminateProcess(ProcessHandle, Status);
+            BaseSetLastNTError(Status);
+            Result = FALSE;
+            goto Quickie;
+        }
     }
-    
-    /* Create the first thread */
-    DPRINT("Creating thread for process (EntryPoint = 0x%p)\n",
-            SectionImageInfo.TransferAddress);
-    hThread = BasepCreateFirstThread(hProcess,
-                                     lpThreadAttributes,
-                                     &SectionImageInfo,
-                                     &ClientId);
 
-    if (hThread == NULL)
+    /* Check if a job was associated with this process */
+    if (JobHandle)
     {
-        DPRINT1("Could not create Initial Thread\n");
-        /* FIXME - set last error code */
-        goto Cleanup;
+        /* Bind the process and job together now */
+        Status = NtAssignProcessToJobObject(JobHandle, ProcessHandle);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Kill the process and enter the failure path if binding failed */
+            DPRINT1("Failed to assign process to job: %lx\n", Status);
+            NtTerminateProcess(ProcessHandle, STATUS_ACCESS_DENIED);
+            BaseSetLastNTError(Status);
+            Result = FALSE;
+            goto Quickie;
+        }
     }
 
+    /* Finally, resume the thread to actually get the process started */
     if (!(dwCreationFlags & CREATE_SUSPENDED))
     {
-        NtResumeThread(hThread, &Dummy);
+        NtResumeThread(ThreadHandle, &ResumeCount);
+    }
+
+VdmShortCircuit:
+    /* We made it this far, meaning we have a fully created process and thread */
+    Result = TRUE;
+
+    /* Anyone doing a VDM undo should now undo everything, since we are done */
+    if (VdmUndoLevel) VdmUndoLevel |= VDM_UNDO_COMPLETED;
+
+    /* Having a VDM wait object implies this must be a VDM process */
+    if (VdmWaitObject)
+    {
+        /* Check if it's a 16-bit separate WOW process */
+        if (VdmBinaryType == BINARY_TYPE_SEPARATE_WOW)
+        {
+            /* OR-in the special flag to indicate this, and return to caller */
+            AddToHandle(VdmWaitObject, 2);
+            lpProcessInformation->hProcess = VdmWaitObject;
+
+            /* Check if this was a re-used VDM */
+            if (VdmUndoLevel & VDM_UNDO_REUSE)
+            {
+                /* No Client ID should be returned in this case */
+                ClientId.UniqueProcess = 0;
+                ClientId.UniqueThread = 0;
+            }
+        }
+        else
+        {
+            /* OR-in the special flag to indicate this is not a separate VDM */
+            AddToHandle(VdmWaitObject, 1);
+
+            /* Return handle to the caller */
+            lpProcessInformation->hProcess = VdmWaitObject;
+        }
+
+        /* Close the original process handle, since it's not needed for VDM */
+        if (ProcessHandle) NtClose(ProcessHandle);
+    }
+    else
+    {
+        /* This is a regular process, so return the real process handle */
+        lpProcessInformation->hProcess = ProcessHandle;
     }
 
-    /* Return Data */
-    lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess;
-    lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread;
-    lpProcessInformation->hProcess = hProcess;
-    lpProcessInformation->hThread = hThread;
-    DPRINT("hThread[%p]: %p inside hProcess[%p]: %p\n", hThread,
-            ClientId.UniqueThread, ClientId.UniqueProcess, hProcess);
-    hProcess = hThread = NULL;
-    Ret = TRUE;
+    /* Return the rest of the process information based on what we have so far */
+    lpProcessInformation->hThread = ThreadHandle;
+    lpProcessInformation->dwProcessId = HandleToUlong(ClientId.UniqueProcess);
+    lpProcessInformation->dwThreadId = HandleToUlong(ClientId.UniqueThread);
 
-Cleanup:
-    /* De-allocate heap strings */
-    if (NameBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
-    if (ApplicationName.Buffer)
-        RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
-    if (CurrentDirectory) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory);
-    if (QuotedCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine);
+    /* NULL these out here so we know to treat this as a success scenario */
+    ProcessHandle = NULL;
+    ThreadHandle = NULL;
 
-    /* Kill any handles still alive */
-    if (hSection) NtClose(hSection);
-    if (hThread)
+Quickie:
+    /* Free the debugger command line if one was allocated */
+    if (DebuggerCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
+
+    /* Check if an SxS full path as queried */
+    if (PathBuffer)
     {
-        /* We don't know any more details then this */
-        NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL);
-        NtClose(hThread);
+        /* Reinitialize the executable path */
+        RtlInitEmptyUnicodeString(&SxsWin32ExePath, NULL, 0);
+        SxsWin32ExePath.Length = 0;
+
+        /* Free the path buffer */
+        RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
     }
-    if (hProcess) NtClose(hProcess);
 
-    /* Return Success */
-    return Ret;
+#if _SXS_SUPPORT_ENABLED_
+    /* Check if this was a non-VDM process */
+    if (!VdmBinaryType)
+    {
+        /* Then it must've had SxS data, so close the handles used for it */
+        BasepSxsCloseHandles(&Handles);
+        BasepSxsCloseHandles(&FileHandles);
+
+        /* Check if we built SxS byte buffers for this create process request */
+        if (SxsConglomeratedBuffer)
+        {
+            /* Loop all of them */
+            for (i = 0; i < 5; i++)
+            {
+                /* Check if this one was allocated */
+                ThisBuffer = SxsStaticBuffers[i];
+                if (ThisBuffer)
+                {
+                    /* Get the underlying RTL_BUFFER structure */
+                    ByteBuffer = &ThisBuffer->ByteBuffer;
+                    if ((ThisBuffer != (PVOID)-8) && (ByteBuffer->Buffer))
+                    {
+                        /* Check if it was dynamic */
+                        if (ByteBuffer->Buffer != ByteBuffer->StaticBuffer)
+                        {
+                            /* Free it from the heap */
+                            FreeString.Buffer = (PWCHAR)ByteBuffer->Buffer;
+                            RtlFreeUnicodeString(&FreeString);
+                        }
+
+                        /* Reset the buffer to its static data */
+                        ByteBuffer->Buffer = ByteBuffer->StaticBuffer;
+                        ByteBuffer->Size = ByteBuffer->StaticSize;
+                    }
+
+                    /* Reset the string to the static buffer */
+                    RtlInitEmptyUnicodeString(&ThisBuffer->String,
+                                              (PWCHAR)ByteBuffer->StaticBuffer,
+                                              ByteBuffer->StaticSize);
+                    if (ThisBuffer->String.Buffer)
+                    {
+                        /* Also NULL-terminate it */
+                        *ThisBuffer->String.Buffer = UNICODE_NULL;
+                    }
+                }
+            }
+        }
+    }
+#endif
+    /* Check if an environment was passed in */
+    if ((lpEnvironment) && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+    {
+        /* Destroy it */
+        RtlDestroyEnvironment(lpEnvironment);
+
+        /* If this was the VDM environment too, clear that as well */
+        if (VdmUnicodeEnv.Buffer == lpEnvironment) VdmUnicodeEnv.Buffer = NULL;
+        lpEnvironment = NULL;
+    }
+
+    /* Unconditionally free all the name parsing buffers we always allocate */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine);
+    RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
+    RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory);
+    RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
+
+    /* Close open file/section handles */
+    if (FileHandle) NtClose(FileHandle);
+    if (SectionHandle) NtClose(SectionHandle);
+
+    /* If we have a thread handle, this was a failure path */
+    if (ThreadHandle)
+    {
+        /* So kill the process and close the thread handle */
+        NtTerminateProcess(ProcessHandle, 0);
+        NtClose(ThreadHandle);
+    }
+
+    /* If we have a process handle, this was a failure path, so close it */
+    if (ProcessHandle) NtClose(ProcessHandle);
+
+    /* Thread/process handles, if any, are now processed. Now close this one. */
+    if (JobHandle) NtClose(JobHandle);
+
+    /* Check if we had created a token */
+    if (TokenHandle)
+    {
+        /* And if the user asked for one */
+        if (hUserToken)
+        {
+            /* Then return it */
+            *hNewToken = TokenHandle;
+        }
+        else
+        {
+            /* User didn't want it, so we used it temporarily -- close it */
+            NtClose(TokenHandle);
+        }
+    }
+
+    /* Free any temporary app compatibility data, it's no longer needed */
+    BasepFreeAppCompatData(AppCompatData, AppCompatSxsData);
+
+    /* Free a few strings. The API takes care of these possibly being NULL */
+    RtlFreeUnicodeString(&VdmString);
+    RtlFreeUnicodeString(&DebuggerString);
+
+    /* Check if we had built any sort of VDM environment */
+    if ((VdmAnsiEnv.Buffer) || (VdmUnicodeEnv.Buffer))
+    {
+        /* Free it */
+        BaseDestroyVDMEnvironment(&VdmAnsiEnv, &VdmUnicodeEnv);
+    }
+
+    /* Check if this was any kind of VDM application that we ended up creating */
+    if ((VdmUndoLevel) && (!(VdmUndoLevel & VDM_UNDO_COMPLETED)))
+    {
+        /* Send an undo */
+        BaseUpdateVDMEntry(VdmEntryUndo,
+                           (PHANDLE)&VdmTask,
+                           VdmUndoLevel,
+                           VdmBinaryType);
+
+        /* And close whatever VDM handle we were using for notifications */
+        if (VdmWaitObject) NtClose(VdmWaitObject);
+    }
+
+    /* Check if we ended up here with an allocated search path, and free it */
+    if (SearchPath) RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
+
+    /* Finally, return the API's result */
+    return Result;
 }
 
 /*
@@ -2974,7 +4617,7 @@ CreateProcessW(LPCWSTR lpApplicationName,
                LPPROCESS_INFORMATION lpProcessInformation)
 {
     /* Call the internal (but exported) version */
-    return CreateProcessInternalW(0,
+    return CreateProcessInternalW(NULL,
                                   lpApplicationName,
                                   lpCommandLine,
                                   lpProcessAttributes,
@@ -3014,8 +4657,8 @@ CreateProcessInternalA(HANDLE hToken,
     BOOL bRetVal;
     STARTUPINFOW StartupInfo;
 
-    DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
-            "lpStartupInfo %x, lpProcessInformation %x\n",
+    DPRINT("dwCreationFlags %x, lpEnvironment %p, lpCurrentDirectory %p, "
+            "lpStartupInfo %p, lpProcessInformation %p\n",
             dwCreationFlags, lpEnvironment, lpCurrentDirectory,
             lpStartupInfo, lpProcessInformation);
 
@@ -3142,7 +4785,7 @@ CreateProcessA(LPCSTR lpApplicationName,
                LPPROCESS_INFORMATION lpProcessInformation)
 {
     /* Call the internal (but exported) version */
-    return CreateProcessInternalA(0,
+    return CreateProcessInternalA(NULL,
                                   lpApplicationName,
                                   lpCommandLine,
                                   lpProcessAttributes,
@@ -3156,4 +4799,48 @@ CreateProcessA(LPCSTR lpApplicationName,
                                   NULL);
 }
 
+/*
+ * @implemented
+ */
+UINT
+WINAPI
+WinExec(LPCSTR lpCmdLine,
+        UINT uCmdShow)
+{
+    STARTUPINFOA StartupInfo;
+    PROCESS_INFORMATION  ProcessInformation;
+    DWORD dosErr;
+
+    RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
+    StartupInfo.cb = sizeof(STARTUPINFOA);
+    StartupInfo.wShowWindow = (WORD)uCmdShow;
+    StartupInfo.dwFlags = 0;
+
+    if (!CreateProcessA(NULL,
+                        (PVOID)lpCmdLine,
+                        NULL,
+                        NULL,
+                        FALSE,
+                        0,
+                        NULL,
+                        NULL,
+                        &StartupInfo,
+                        &ProcessInformation))
+    {
+        dosErr = GetLastError();
+        return dosErr < 32 ? dosErr : ERROR_BAD_FORMAT;
+    }
+
+    if (NULL != UserWaitForInputIdleRoutine)
+    {
+        UserWaitForInputIdleRoutine(ProcessInformation.hProcess,
+                                           10000);
+    }
+
+    NtClose(ProcessInformation.hProcess);
+    NtClose(ProcessInformation.hThread);
+
+    return 33; /* Something bigger than 31 means success. */
+}
+
 /* EOF */