Fixed some bugs in CreateProcessA which was introduced by r16730.
[reactos.git] / reactos / lib / kernel32 / process / create.c
index dd7eafc..d1b5047 100644 (file)
-/* $Id: create.c,v 1.59 2003/01/15 21:24:35 chorns Exp $
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/kernel32/process/create.c
  * PURPOSE:         Process functions
- * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
- * UPDATE HISTORY:
- *                  Created 01/11/98
+ * PROGRAMMER:      Alex Ionescu (alex@relsoft.net)
+ *                  Ariadne ( ariadne@xs4all.nl)
  */
 
 /* INCLUDES ****************************************************************/
 
 #include <k32.h>
 
-#define DBG
-#include <kernel32/kernel32.h>
-
-/* FUNCTIONS ****************************************************************/
-
-WINBOOL STDCALL
-CreateProcessA (LPCSTR                 lpApplicationName,
-               LPSTR                   lpCommandLine,
-               LPSECURITY_ATTRIBUTES   lpProcessAttributes,
-               LPSECURITY_ATTRIBUTES   lpThreadAttributes,
-               WINBOOL                 bInheritHandles,
-               DWORD                   dwCreationFlags,
-               LPVOID                  lpEnvironment,
-               LPCSTR                  lpCurrentDirectory,
-               LPSTARTUPINFOA          lpStartupInfo,
-               LPPROCESS_INFORMATION   lpProcessInformation)
-/*
- * FUNCTION: The CreateProcess function creates a new process and its
- * primary thread. The new process executes the specified executable file
- * ARGUMENTS:
- * 
- *     lpApplicationName = Pointer to name of executable module
- *     lpCommandLine = Pointer to command line string
- *     lpProcessAttributes = Process security attributes
- *     lpThreadAttributes = Thread security attributes
- *     bInheritHandles = Handle inheritance flag
- *     dwCreationFlags = Creation flags
- *     lpEnvironment = Pointer to new environment block
- *     lpCurrentDirectory = Pointer to current directory name
- *     lpStartupInfo = Pointer to startup info
- *     lpProcessInformation = Pointer to process information
- */
-{
-       PWCHAR lpEnvironmentW = NULL;
-       UNICODE_STRING ApplicationNameU;
-       UNICODE_STRING CurrentDirectoryU;
-       UNICODE_STRING CommandLineU;
-       ANSI_STRING ApplicationName;
-       ANSI_STRING CurrentDirectory;
-       ANSI_STRING CommandLine;
-       WINBOOL Result;
-       CHAR TempCurrentDirectoryA[256];
-
-       DPRINT("CreateProcessA(%s)\n", lpApplicationName);
-       DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
-               "lpStartupInfo %x, lpProcessInformation %x\n", dwCreationFlags, 
-               lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
-
-       if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
-       {
-               PCHAR ptr = lpEnvironment;
-               ULONG len = 0;
-               UNICODE_STRING EnvironmentU;
-               ANSI_STRING EnvironmentA;
-               while (*ptr)
-               {
-                       RtlInitAnsiString(&EnvironmentA, ptr);
-                       if (bIsFileApiAnsi)
-                               len += RtlAnsiStringToUnicodeSize(&EnvironmentA) + sizeof(WCHAR);
-                       else
-                               len += RtlOemStringToUnicodeSize(&EnvironmentA) + sizeof(WCHAR);
-                       ptr += EnvironmentA.MaximumLength;
-               }
-               len += sizeof(WCHAR);
-               lpEnvironmentW = (PWCHAR)RtlAllocateHeap(GetProcessHeap(),
-                                                        HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY, 
-                                                        len);
-               if (lpEnvironmentW == NULL)
-               {
-                       return FALSE;
-               }
-               ptr = lpEnvironment;
-               EnvironmentU.Buffer = lpEnvironmentW;
-               EnvironmentU.Length = 0;
-               EnvironmentU.MaximumLength = len;
-               while (*ptr)
-               {
-                       RtlInitAnsiString(&EnvironmentA, ptr);
-                       if (bIsFileApiAnsi)
-                               RtlAnsiStringToUnicodeString(&EnvironmentU, &EnvironmentA, FALSE);
-                       else
-                               RtlOemStringToUnicodeString(&EnvironmentU, &EnvironmentA, FALSE);
-                       ptr += EnvironmentA.MaximumLength;
-                       EnvironmentU.Buffer += (EnvironmentU.Length / sizeof(WCHAR) + 1);
-                       EnvironmentU.MaximumLength -= (EnvironmentU.Length + sizeof(WCHAR));
-                       EnvironmentU.Length = 0;
-               }
+#define NDEBUG
+#include "../include/debug.h"
 
-               EnvironmentU.Buffer[0] = 0;     
-       }
-    
-       RtlInitAnsiString (&CommandLine,
-                          lpCommandLine);
-       RtlInitAnsiString (&ApplicationName,
-                          (LPSTR)lpApplicationName);
-       if (lpCurrentDirectory != NULL)
-         {
-           RtlInitAnsiString (&CurrentDirectory,
-                              (LPSTR)lpCurrentDirectory);
-         }
+#define CMD_STRING L"cmd /c "
 
-       /* convert ansi (or oem) strings to unicode */
-       if (bIsFileApiAnsi)
-       {
-               RtlAnsiStringToUnicodeString (&CommandLineU, &CommandLine, TRUE);
-               RtlAnsiStringToUnicodeString (&ApplicationNameU, &ApplicationName, TRUE);
-               if (lpCurrentDirectory != NULL)
-                       RtlAnsiStringToUnicodeString (&CurrentDirectoryU, &CurrentDirectory, TRUE);
-       }
-       else
-       {
-               RtlOemStringToUnicodeString (&CommandLineU, &CommandLine, TRUE);
-               RtlOemStringToUnicodeString (&ApplicationNameU, &ApplicationName, TRUE);
-               if (lpCurrentDirectory != NULL)  
-                       RtlOemStringToUnicodeString (&CurrentDirectoryU, &CurrentDirectory, TRUE);
-       }
+extern __declspec(noreturn)
+VOID
+CALLBACK 
+ConsoleControlDispatcher(DWORD CodeAndFlag);
 
-       Result = CreateProcessW (ApplicationNameU.Buffer,
-                                CommandLineU.Buffer,
-                                lpProcessAttributes,
-                                lpThreadAttributes,
-                                bInheritHandles,
-                                dwCreationFlags,
-                                dwCreationFlags & CREATE_UNICODE_ENVIRONMENT ? lpEnvironment : lpEnvironmentW,
-                                (lpCurrentDirectory == NULL) ? NULL : CurrentDirectoryU.Buffer,
-                                (LPSTARTUPINFOW)lpStartupInfo,
-                                lpProcessInformation);
+/* INTERNAL FUNCTIONS *******************************************************/
 
-       RtlFreeUnicodeString (&ApplicationNameU);
-       RtlFreeUnicodeString (&CommandLineU);
-       if (lpCurrentDirectory != NULL)
-               RtlFreeUnicodeString (&CurrentDirectoryU);
+_SEH_FILTER(BaseExceptionFilter)
+{
+    EXCEPTION_POINTERS *ExceptionInfo = _SEH_GetExceptionPointers();
+    LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
 
-       if (lpEnvironmentW)
-       {
-               RtlFreeHeap(GetProcessHeap(), 0, lpEnvironmentW);
-       }
+    if (GlobalTopLevelExceptionFilter != NULL)
+    {
+        _SEH_TRY
+        {
+            ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo);
+        }
+        _SEH_HANDLE
+        {
+            ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
+        }
+        _SEH_END;
+    }
 
-       return Result;
+    return ExceptionDisposition;
 }
 
-static int _except_recursion_trap = 0;
-
-struct _CONTEXT;
-struct __EXCEPTION_RECORD;
-
-static
-EXCEPTION_DISPOSITION
-__cdecl
-_except_handler(
-    struct _EXCEPTION_RECORD *ExceptionRecord,
-    void * EstablisherFrame,
-    struct _CONTEXT *ContextRecord,
-    void * DispatcherContext )
+VOID
+STDCALL
+BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress)
 {
-       DPRINT("Process terminated abnormally...\n");
+    UINT uExitCode = 0;
 
-       if (++_except_recursion_trap > 3) {
-        DPRINT("_except_handler(...) appears to be recursing.\n");
-        DPRINT("Process HALTED.\n");
-               for (;;) {}
-       }
+    DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
 
-       if (/* FIXME: */ TRUE) /* Not a service */
-       {
-        DPRINT("  calling ExitProcess(0) no, lets try ExitThread . . .\n");
-               //ExitProcess(0);
-               ExitThread(0);
-       }
-       else
-       {
-        DPRINT("  calling ExitThread(0) . . .\n");
-               ExitThread(0);
-       }
+    _SEH_TRY
+    {
+        /* Set our Start Address */
+        NtSetInformationThread(NtCurrentThread(),
+                               ThreadQuerySetWin32StartAddress,
+                               &lpStartAddress,
+                               sizeof(PPROCESS_START_ROUTINE));
+        
+        /* Call the Start Routine */
+        uExitCode = (lpStartAddress)();
+    }
+    _SEH_EXCEPT(BaseExceptionFilter)
+    {
+        /* Get the SEH Error */
+        uExitCode = _SEH_GetExceptionCode();
+    }
+    _SEH_END;
 
-    DPRINT("  We should not get to here !!!\n");
-       /* We should not get to here */
-       return ExceptionContinueSearch;
+    /* Exit the Process with our error */
+    ExitProcess(uExitCode);
 }
 
-VOID STDCALL
-BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress,
-                DWORD lpParameter)
+/*
+ * Tells CSR that a new process was created
+ */
+NTSTATUS
+STDCALL
+BasepNotifyCsrOfCreation(ULONG dwCreationFlags,
+                         IN HANDLE ProcessId)
 {
-       UINT uExitCode = 0;
-
-    DPRINT("\nBaseProcessStart(..) - setting up exception frame.\n\n");
-
-       __try1(_except_handler)
-       {
-               uExitCode = (lpStartAddress)((PVOID)lpParameter);
-       } __except1
-       {
-       }
-
-    DPRINT("\nBaseProcessStart(..) - cleaned up exception frame.\n\n");
-
-       ExitThread(uExitCode);
+    ULONG Request = CREATE_PROCESS;
+    CSR_API_MESSAGE CsrRequest;
+    NTSTATUS Status;
+    
+    DPRINT1("BasepNotifyCsrOfCreation: Process: %lx, Flags %lx\n", 
+            ProcessId, dwCreationFlags);
+         
+    /* Fill out the request */
+    CsrRequest.Data.CreateProcessRequest.NewProcessId = ProcessId;
+    CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
+    
+    /* 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 process\n");
+        return CsrRequest.Status;
+    }
+    
+    /* REturn Success */
+    return STATUS_SUCCESS;
 }
 
-
-HANDLE STDCALL 
-KlCreateFirstThread(HANDLE ProcessHandle,
-                   LPSECURITY_ATTRIBUTES lpThreadAttributes,
-                   ULONG StackReserve,
-                   ULONG StackCommit,
-                   LPTHREAD_START_ROUTINE lpStartAddress,
-                   DWORD dwCreationFlags,
-                   LPDWORD lpThreadId)
+/*
+ * Creates the first Thread in a Proces
+ */
+HANDLE
+STDCALL
+BasepCreateFirstThread(HANDLE ProcessHandle,
+                       LPSECURITY_ATTRIBUTES lpThreadAttributes,
+                       PSECTION_IMAGE_INFORMATION SectionImageInfo,
+                       PCLIENT_ID ClientId)
 {
-  NTSTATUS Status;
-  HANDLE ThreadHandle;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  CLIENT_ID ClientId;
-  CONTEXT ThreadContext;
-  INITIAL_TEB InitialTeb;
-  BOOLEAN CreateSuspended = FALSE;
-  ULONG OldPageProtection;
-  ULONG ResultLength;
-  ULONG InitialStack[6];
-
-  ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
-  ObjectAttributes.RootDirectory = NULL;
-  ObjectAttributes.ObjectName = NULL;
-  ObjectAttributes.Attributes = 0;
-  if (lpThreadAttributes != NULL) 
-    {
-      if (lpThreadAttributes->bInheritHandle) 
-       ObjectAttributes.Attributes = OBJ_INHERIT;
-      ObjectAttributes.SecurityDescriptor = 
-       lpThreadAttributes->lpSecurityDescriptor;
-    }
-  ObjectAttributes.SecurityQualityOfService = NULL;
-
-  if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
-    CreateSuspended = TRUE;
-  else
-    CreateSuspended = FALSE;
+    OBJECT_ATTRIBUTES LocalObjectAttributes;
+    POBJECT_ATTRIBUTES ObjectAttributes;
+    CONTEXT Context;
+    INITIAL_TEB InitialTeb;
+    NTSTATUS Status;
+    HANDLE hThread;
+    
+    DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle);
+
+    /* Create the Thread's Stack */
+    BasepCreateStack(ProcessHandle,
+                     SectionImageInfo->MaximumStackSize,
+                     SectionImageInfo->CommittedStackSize,
+                     &InitialTeb);
+                     
+    /* Create the Thread's Context */
+    BasepInitializeContext(&Context,
+                           NtCurrentPeb(),
+                           SectionImageInfo->TransferAddress,
+                           InitialTeb.StackBase,
+                           0);
+    
+    /* Convert the thread attributes */
+    ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
+                                                    lpThreadAttributes,
+                                                    NULL);
+    
+    /* Create the Kernel Thread Object */
+    Status = NtCreateThread(&hThread,
+                            THREAD_ALL_ACCESS,
+                            ObjectAttributes,
+                            ProcessHandle,
+                            ClientId,
+                            &Context,
+                            &InitialTeb,
+                            TRUE);
+   
+    /* Success */
+    return hThread;
+}
 
-  InitialTeb.StackReserve = (StackReserve < 0x100000) ? 0x100000 : StackReserve;
-  /* FIXME: use correct commit size */
-#if 0
-  InitialTeb.StackCommit = (StackCommit < PAGE_SIZE) ? PAGE_SIZE : StackCommit;
-#endif
-  InitialTeb.StackCommit = InitialTeb.StackReserve - PAGE_SIZE;
+/*
+ * Converts ANSI to Unicode Environment
+ */
+PVOID
+STDCALL
+BasepConvertUnicodeEnvironment(IN PVOID lpEnvironment)
+{
+    PCHAR pcScan;
+    SIZE_T EnvSize = 0;
+    ANSI_STRING AnsiEnv;
+    UNICODE_STRING UnicodeEnv;
+    NTSTATUS Status;
+    
+    DPRINT("BasepConvertUnicodeEnvironment\n");
 
-  /* size of guard page */
-  InitialTeb.StackCommit += PAGE_SIZE;
+    /* Scan the environment to calculate its Unicode size */
+    AnsiEnv.Buffer = pcScan = lpEnvironment;
+    while (*pcScan) while (*pcScan++);
 
-  /* Reserve stack */
-  InitialTeb.StackAllocate = NULL;
-  Status = NtAllocateVirtualMemory(ProcessHandle,
-                                  &InitialTeb.StackAllocate,
-                                  0,
-                                  &InitialTeb.StackReserve,
-                                  MEM_RESERVE,
-                                  PAGE_READWRITE);
-  if (!NT_SUCCESS(Status))
-    {
-      DPRINT("Error reserving stack space!\n");
-      SetLastErrorByStatus(Status);
-      return(NULL);
+    /* Create our ANSI String */
+    AnsiEnv.Length = (ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + 1;
+    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);
+        return NULL;
     }
+        
+    /* Use the allocated size */
+    UnicodeEnv.MaximumLength = EnvSize;
+    
+    /* Convert */
+    RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
+    return UnicodeEnv.Buffer;
+}
 
-  DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
-        InitialTeb.StackAllocate, InitialTeb.StackReserve);
-
-  InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
-  InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
-
-  DPRINT("StackBase: %p StackCommit: %p\n",
-        InitialTeb.StackBase, InitialTeb.StackCommit);
-
-  /* Commit stack page(s) */
-  Status = NtAllocateVirtualMemory(ProcessHandle,
-                                  &InitialTeb.StackLimit,
-                                  0,
-                                  &InitialTeb.StackCommit,
-                                  MEM_COMMIT,
-                                  PAGE_READWRITE);
-  if (!NT_SUCCESS(Status))
-    {
-      /* release the stack space */
-      NtFreeVirtualMemory(ProcessHandle,
-                         InitialTeb.StackAllocate,
-                         &InitialTeb.StackReserve,
-                         MEM_RELEASE);
-
-      DPRINT("Error comitting stack page(s)!\n");
-      SetLastErrorByStatus(Status);
-      return(INVALID_HANDLE_VALUE);
+/*
+ * Converts a Win32 Priority Class to NT
+ */
+ULONG
+STDCALL
+BasepConvertPriorityClass(IN ULONG dwCreationFlags)
+{
+    ULONG ReturnClass;
+    
+    if(dwCreationFlags & IDLE_PRIORITY_CLASS)
+    {    
+        ReturnClass = PROCESS_PRIORITY_CLASS_IDLE;
     }
-
-  DPRINT("StackLimit: %p\n",
-        InitialTeb.StackLimit);
-
-  /* Protect guard page */
-  Status = NtProtectVirtualMemory(ProcessHandle,
-                                 InitialTeb.StackLimit,
-                                 PAGE_SIZE,
-                                 PAGE_GUARD | PAGE_READWRITE,
-                                 &OldPageProtection);
-  if (!NT_SUCCESS(Status))
-    {
-      /* release the stack space */
-      NtFreeVirtualMemory(ProcessHandle,
-                         InitialTeb.StackAllocate,
-                         &InitialTeb.StackReserve,
-                         MEM_RELEASE);
-
-      DPRINT("Error comitting guard page!\n");
-      SetLastErrorByStatus(Status);
-      return(INVALID_HANDLE_VALUE);
+    else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
+    {
+        ReturnClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
     }
-
-  memset(&ThreadContext,0,sizeof(CONTEXT));
-  ThreadContext.Eip = (ULONG)BaseProcessStart;
-  ThreadContext.SegGs = USER_DS;
-  ThreadContext.SegFs = USER_DS;
-  ThreadContext.SegEs = USER_DS;
-  ThreadContext.SegDs = USER_DS;
-  ThreadContext.SegCs = USER_CS;
-  ThreadContext.SegSs = USER_DS;
-  ThreadContext.Esp = (ULONG)InitialTeb.StackBase - 6*4;
-  ThreadContext.EFlags = (1<<1) + (1<<9);
-
-  DPRINT("ThreadContext.Eip %x\n",ThreadContext.Eip);
-
-  /*
-   * Write in the initial stack.
-   */
-  InitialStack[0] = 0;
-  InitialStack[1] = (DWORD)lpStartAddress;
-  InitialStack[2] = PEB_BASE;
-
-  Status = ZwWriteVirtualMemory(ProcessHandle,
-                               (PVOID)ThreadContext.Esp,
-                               InitialStack,
-                               sizeof(InitialStack),
-                               &ResultLength);
-  if (!NT_SUCCESS(Status))
+    else if(dwCreationFlags & NORMAL_PRIORITY_CLASS)
     {
-      DPRINT1("Failed to write initial stack.\n");
-      return(INVALID_HANDLE_VALUE);
+        ReturnClass = PROCESS_PRIORITY_CLASS_NORMAL;
     }
-
-  Status = NtCreateThread(&ThreadHandle,
-                         THREAD_ALL_ACCESS,
-                         &ObjectAttributes,
-                         ProcessHandle,
-                         &ClientId,
-                         &ThreadContext,
-                         &InitialTeb,
-                         CreateSuspended);
-  if (!NT_SUCCESS(Status))
-    {
-      NtFreeVirtualMemory(ProcessHandle,
-                         InitialTeb.StackAllocate,
-                         &InitialTeb.StackReserve,
-                         MEM_RELEASE);
-      SetLastErrorByStatus(Status);
-      return(INVALID_HANDLE_VALUE);
+    else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
+    {
+        ReturnClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
     }
-
-  if (lpThreadId != NULL)
+    else if(dwCreationFlags & HIGH_PRIORITY_CLASS)
     {
-      memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
+        ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
     }
-
-  return(ThreadHandle);
+    else if(dwCreationFlags & REALTIME_PRIORITY_CLASS)
+    {
+        /* Check for Privilege First */
+        if (BasepCheckRealTimePrivilege())
+        {
+            ReturnClass = PROCESS_PRIORITY_CLASS_REALTIME;
+        }
+        else
+        {
+            ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
+        }
+    }
+    else
+    {
+        ReturnClass = 0 /* FIXME */;
+    }
+    
+    return ReturnClass;
 }
 
-HANDLE 
-KlMapFile(LPCWSTR lpApplicationName)
+/*
+ * Duplicates a standard handle and writes it where requested.
+ */
+VOID
+STDCALL
+BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle,
+                             IN HANDLE StandardHandle,
+                             IN PHANDLE Address)
 {
-   HANDLE hFile;
-   IO_STATUS_BLOCK IoStatusBlock;
-   UNICODE_STRING ApplicationNameString;
-   OBJECT_ATTRIBUTES ObjectAttributes;
-   PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
-   NTSTATUS Status;
-   HANDLE hSection;
-
-   hFile = NULL;
-
-   /*
-    * Find the application name
-    */
-
-   if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName,
-                                      &ApplicationNameString,
-                                      NULL,
-                                      NULL))
-       return NULL;
-
-   DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
-
-   InitializeObjectAttributes(&ObjectAttributes,
-                             &ApplicationNameString,
-                             OBJ_CASE_INSENSITIVE,
-                             NULL,
-                             SecurityDescriptor);
-
-   /*
-    * Try to open the executable
-    */
-
-   Status = NtOpenFile(&hFile,
-                       SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
-                       &ObjectAttributes,
-                       &IoStatusBlock,
-                       FILE_SHARE_DELETE|FILE_SHARE_READ,
-                       FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
-
-   RtlFreeUnicodeString (&ApplicationNameString);
-
-   if (!NT_SUCCESS(Status))
-     {
-       DPRINT("Failed to open file\n");
-       SetLastErrorByStatus (Status);
-       return(NULL);
-     }
-
-   Status = NtCreateSection(&hSection,
-                           SECTION_ALL_ACCESS,
-                           NULL,
-                           NULL,
-                           PAGE_EXECUTE,
-                           SEC_IMAGE,
-                           hFile);
-   NtClose(hFile);
-
-   if (!NT_SUCCESS(Status))
-     {
-       DPRINT("Failed to create section\n");
-       SetLastErrorByStatus (Status);
-       return(NULL);
-     }
-
-   return(hSection);
+    NTSTATUS Status;
+    HANDLE DuplicatedHandle;
+    ULONG Dummy;
+    
+    DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
+           "Address: %p\n", ProcessHandle, StandardHandle, Address);
+            
+    /* Don't touch Console Handles */
+    if (IsConsoleHandle(StandardHandle)) return;
+    
+    /* Duplicate the handle */
+    Status = NtDuplicateObject(NtCurrentProcess(),
+                               StandardHandle,
+                               ProcessHandle,
+                               &DuplicatedHandle,
+                               DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES,
+                               0,
+                               0);
+    if (NT_SUCCESS(Status))
+    {
+        /* Write it */
+        NtWriteVirtualMemory(ProcessHandle,
+                             Address,
+                             &DuplicatedHandle,
+                             sizeof(HANDLE),
+                             &Dummy);
+    }
 }
 
-static NTSTATUS 
-KlInitPeb (HANDLE ProcessHandle,
-          PRTL_USER_PROCESS_PARAMETERS Ppb,
-          PVOID* ImageBaseAddress)
+LPWSTR
+STDCALL
+BasepGetDllPath(LPWSTR FullPath,
+                PVOID Environment)
 {
-   NTSTATUS Status;
-   PVOID PpbBase;
-   ULONG PpbSize;
-   ULONG BytesWritten;
-   ULONG Offset;
-   PVOID ParentEnv = NULL;
-   PVOID EnvPtr = NULL;
-   PWCHAR ptr;
-   ULONG EnvSize = 0, EnvSize1 = 0;
-
-   /* create the Environment */
-   if (Ppb->Environment != NULL)
-   {
-      ParentEnv = Ppb->Environment;
-      ptr = ParentEnv;
-      while (*ptr)
-      {
-         while(*ptr++);
-      }
-      ptr++;
-      EnvSize = (PVOID)ptr - ParentEnv;
-   }
-   else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
-   {
-      MEMORY_BASIC_INFORMATION MemInfo;
-      ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
-
-       Status = NtQueryVirtualMemory (NtCurrentProcess (),
-                                      ParentEnv,
-                                      MemoryBasicInformation,
-                                      &MemInfo,
-                                      sizeof(MEMORY_BASIC_INFORMATION),
-                                      NULL);
-       if (!NT_SUCCESS(Status))
-         {
-            return Status;
-         }
-       EnvSize = MemInfo.RegionSize;
-     }
-   DPRINT("EnvironmentSize %ld\n", EnvSize);
-
-   /* allocate and initialize new environment block */
-   if (EnvSize != 0)
-     {
-       EnvSize1 = EnvSize;
-       Status = NtAllocateVirtualMemory(ProcessHandle,
-                                        &EnvPtr,
-                                        0,
-                                        &EnvSize1,
-                                        MEM_RESERVE | MEM_COMMIT,
-                                        PAGE_READWRITE);
-       if (!NT_SUCCESS(Status))
-         {
-            return(Status);
-         }
-
-       NtWriteVirtualMemory(ProcessHandle,
-                            EnvPtr,
-                            ParentEnv,
-                            EnvSize,
-                            &BytesWritten);
-     }
-
-   /* create the PPB */
-   PpbBase = NULL;
-   PpbSize = Ppb->AllocationSize;
-   Status = NtAllocateVirtualMemory(ProcessHandle,
-                                   &PpbBase,
-                                   0,
-                                   &PpbSize,
-                                   MEM_RESERVE | MEM_COMMIT,
-                                   PAGE_READWRITE);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
+    /* FIXME: Not yet implemented */
+    return NULL;
+}
 
-   //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
-   NtWriteVirtualMemory(ProcessHandle,
-                       PpbBase,
-                       Ppb,
-                       Ppb->AllocationSize,
-                       &BytesWritten);
+VOID
+STDCALL
+BasepCopyHandles(IN PRTL_USER_PROCESS_PARAMETERS Params,
+                 IN PRTL_USER_PROCESS_PARAMETERS PebParams,
+                 IN BOOL 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;
+    }
+}
 
-   /* write pointer to environment */
-   Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
-   NtWriteVirtualMemory(ProcessHandle,
-                       (PVOID)(PpbBase + Offset),
-                       &EnvPtr,
-                       sizeof(EnvPtr),
-                       &BytesWritten);
+NTSTATUS
+STDCALL
+BasepInitializeEnvironment(HANDLE ProcessHandle,
+                           PPEB Peb,
+                           LPWSTR ApplicationPathName,
+                           LPWSTR lpCurrentDirectory,
+                           LPWSTR lpCommandLine,
+                           LPVOID Environment,
+                           LPSTARTUPINFOW StartupInfo,
+                           DWORD CreationFlags,
+                           BOOL InheritHandles)
+{
+    WCHAR FullPath[MAX_PATH];
+    LPWSTR Remaining;
+    LPWSTR DllPathString;
+    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
+    PRTL_USER_PROCESS_PARAMETERS RemoteParameters = NULL;
+    UNICODE_STRING DllPath, ImageName, CommandLine, CurrentDirectory;
+    UINT RetVal;
+    NTSTATUS Status;
+    PWCHAR ScanChar;
+    ULONG EnviroSize;
+    ULONG Size;
+    UNICODE_STRING Desktop, Shell, Runtime, Title;
+    PPEB OurPeb = NtCurrentPeb();
+    
+    DPRINT("BasepInitializeEnvironment\n");
+    
+    /* Get the full path name */
+    RetVal = GetFullPathNameW(ApplicationPathName,
+                              MAX_PATH,
+                              FullPath,
+                              &Remaining);
+    DPRINT("ApplicationPathName: %S, FullPath: %S\n", ApplicationPathName, 
+            FullPath);
+                                  
+    /* Get the DLL Path */
+    DllPathString = BasepGetDllPath(FullPath, Environment);
+    
+    /* Initialize Strings */
+    RtlInitUnicodeString(&DllPath, DllPathString);
+    RtlInitUnicodeString(&ImageName, FullPath);
+    RtlInitUnicodeString(&CommandLine, lpCommandLine);
+    RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory);
+   
+    /* Initialize more Strings from the Startup Info */
+    if (StartupInfo->lpDesktop)
+    {
+        RtlInitUnicodeString(&Desktop, StartupInfo->lpDesktop);
+    }
+    else
+    {
+        RtlInitUnicodeString(&Desktop, L"");
+    }
+    if (StartupInfo->lpReserved)
+    {
+        RtlInitUnicodeString(&Shell, StartupInfo->lpReserved);
+    }
+    else
+    {
+        RtlInitUnicodeString(&Shell, L"");
+    }
+    if (StartupInfo->lpTitle)
+    {
+        RtlInitUnicodeString(&Title, StartupInfo->lpTitle);
+    }
+    else
+    {
+        RtlInitUnicodeString(&Title, L"");
+    }
+    
+    /* This one is special because the length can differ */
+    Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2;
+    Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2;
+    
+    /* Create the Parameter Block */
+    DPRINT("Creating Process Parameters: %wZ %wZ %wZ %wZ %wZ %wZ %wZ\n",
+            &ImageName, &DllPath, &CommandLine, &Desktop, &Title, &Shell,
+            &Runtime);
+    Status = RtlCreateProcessParameters(&ProcessParameters,
+                                        &ImageName,
+                                        &DllPath,
+                                        lpCurrentDirectory ? 
+                                        &CurrentDirectory : NULL,
+                                        &CommandLine,
+                                        Environment,
+                                        &Title,
+                                        &Desktop,
+                                        &Shell,
+                                        &Runtime);
+                                        
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to create process parameters!\n");
+        return Status;
+    }
+    
+    /* Check if we got an environment. If not, use ours */
+    if (Environment)
+    {
+        /* Save pointer and start lookup */
+        Environment = ScanChar = ProcessParameters->Environment;
+    }
+    else
+    {
+        /* Save pointer and start lookup */
+        Environment = ScanChar = OurPeb->ProcessParameters->Environment;
+    }
+    
+    /* Find the environment size */
+    if (ScanChar)
+    {
+        while (*ScanChar) while (*ScanChar++);
+        
+        /* Calculate the size of the block */
+        EnviroSize = (ULONG)((ULONG_PTR)ScanChar - (ULONG_PTR)Environment);
+        DPRINT("EnvironmentSize %ld\n", EnviroSize);
+
+        /* Allocate and Initialize new Environment Block */
+        Size = EnviroSize;
+        ProcessParameters->Environment = NULL;
+        Status = ZwAllocateVirtualMemory(ProcessHandle,
+                                         (PVOID*)&ProcessParameters->Environment,
+                                         0,
+                                         &Size,
+                                         MEM_COMMIT,
+                                         PAGE_READWRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to allocate Environment Block\n");
+            return(Status);
+        }
+        
+        /* Write the Environment Block */
+        ZwWriteVirtualMemory(ProcessHandle,
+                             ProcessParameters->Environment,
+                             Environment,
+                             EnviroSize,
+                             NULL);
+    }
+    
+    /* Write new parameters */
+    ProcessParameters->StartingX = StartupInfo->dwX;
+    ProcessParameters->StartingY = StartupInfo->dwY;
+    ProcessParameters->CountX = StartupInfo->dwXSize;
+    ProcessParameters->CountY = StartupInfo->dwYSize;
+    ProcessParameters->CountCharsX = StartupInfo->dwXCountChars;
+    ProcessParameters->CountCharsY = StartupInfo->dwYCountChars;
+    ProcessParameters->FillAttribute = StartupInfo->dwFillAttribute;
+    ProcessParameters->WindowFlags = StartupInfo->dwFlags;
+    ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow;
+        
+    /* Write the handles only if we have to */
+    if (StartupInfo->dwFlags & STARTF_USESTDHANDLES)
+    {
+        ProcessParameters->StandardInput = StartupInfo->hStdInput;
+        ProcessParameters->StandardOutput = StartupInfo->hStdOutput;
+        ProcessParameters->StandardError = StartupInfo->hStdError;
+    }
+        
+    /* Use Special Flags for ConDllInitialize 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
+    {
+        /* Inherit our Console Handle */
+        ProcessParameters->ConsoleHandle = OurPeb->ProcessParameters->ConsoleHandle;
+        
+        /* Is the shell trampling on our Handles? */
+        if (!(StartupInfo->dwFlags & 
+              (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
+        {
+            /* Use handles from PEB, if inheriting or they are console */ 
+            BasepCopyHandles(ProcessParameters,
+                             OurPeb->ProcessParameters,
+                             InheritHandles);
+       }
+    }
+    
+    /* Also set the Console Flag */
+    if (CreationFlags & CREATE_NEW_PROCESS_GROUP)
+    {
+        ProcessParameters->ConsoleFlags = 1;
+    }
+    
+    /* Allocate memory for the parameter block */
+    Size = ProcessParameters->Length;
+    Status = NtAllocateVirtualMemory(ProcessHandle,
+                                     (PVOID*)&RemoteParameters,
+                                     0,
+                                     &Size,
+                                     MEM_COMMIT,
+                                     PAGE_READWRITE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to allocate Parameters Block\n");
+        return(Status);
+    }
+    
+    /* Set the allocated size */
+    ProcessParameters->MaximumLength = Size;
+    
+    /* Handle some Parameter Flags */
+    ProcessParameters->ConsoleFlags = (CreationFlags & CREATE_NEW_PROCESS_GROUP);
+    ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ?
+                                 PPF_PROFILE_USER : 0;
+    ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ? 
+                                 PPF_PROFILE_KERNEL : 0;    
+    ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ?
+                                 PPF_PROFILE_SERVER : 0;
+    ProcessParameters->Flags |= (NtCurrentPeb()->ProcessParameters->Flags &
+                                 PPF_DISABLE_HEAP_CHECKS);
+    
+    /* Write the Parameter Block */
+    Status = NtWriteVirtualMemory(ProcessHandle,
+                                  RemoteParameters,
+                                  ProcessParameters,
+                                  ProcessParameters->Length,
+                                  NULL);
+                                  
+    /* Write the PEB Pointer */
+    Status = NtWriteVirtualMemory(ProcessHandle,
+                                  &Peb->ProcessParameters,
+                                  &RemoteParameters,
+                                  sizeof(PVOID),
+                                  NULL);
+                                  
+    /* Cleanup */
+    RtlFreeHeap(GetProcessHeap(), 0, DllPath.Buffer);
+    RtlDestroyProcessParameters(ProcessParameters);
+
+    DPRINT("Completed\n");
+    return STATUS_SUCCESS;
+}
 
-   /* write pointer to process parameter block */
-   Offset = FIELD_OFFSET(PEB, ProcessParameters);
-   NtWriteVirtualMemory(ProcessHandle,
-                       (PVOID)(PEB_BASE + Offset),
-                       &PpbBase,
-                       sizeof(PpbBase),
-                       &BytesWritten);
+/* FUNCTIONS ****************************************************************/
 
-   /* Read image base address. */
-   Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
-   NtReadVirtualMemory(ProcessHandle,
-                      (PVOID)(PEB_BASE + Offset),
-                      ImageBaseAddress,
-                      sizeof(PVOID),
-                      &BytesWritten);
+/*
+ * FUNCTION: The CreateProcess function creates a new process and its
+ * primary thread. The new process executes the specified executable file
+ * ARGUMENTS:
+ *
+ *     lpApplicationName = Pointer to name of executable module
+ *     lpCommandLine = Pointer to command line string
+ *     lpProcessAttributes = Process security attributes
+ *     lpThreadAttributes = Thread security attributes
+ *     bInheritHandles = Handle inheritance flag
+ *     dwCreationFlags = Creation flags
+ *     lpEnvironment = Pointer to new environment block
+ *     lpCurrentDirectory = Pointer to current directory name
+ *     lpStartupInfo = Pointer to startup info
+ *     lpProcessInformation = Pointer to process information
+ *
+ * @implemented
+ */
+BOOL
+STDCALL
+CreateProcessA(LPCSTR lpApplicationName,
+               LPSTR lpCommandLine,
+               LPSECURITY_ATTRIBUTES lpProcessAttributes,
+               LPSECURITY_ATTRIBUTES lpThreadAttributes,
+               BOOL bInheritHandles,
+               DWORD dwCreationFlags,
+               LPVOID lpEnvironment,
+               LPCSTR lpCurrentDirectory,
+               LPSTARTUPINFOA lpStartupInfo,
+               LPPROCESS_INFORMATION lpProcessInformation)
+{    
+    PUNICODE_STRING CommandLine = NULL;
+    UNICODE_STRING DummyString;
+    UNICODE_STRING LiveCommandLine;
+    UNICODE_STRING ApplicationName;
+    UNICODE_STRING CurrentDirectory;
+    BOOL bRetVal;
+    STARTUPINFOW StartupInfo;
+
+    DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
+            "lpStartupInfo %x, lpProcessInformation %x\n",
+            dwCreationFlags, lpEnvironment, lpCurrentDirectory,
+            lpStartupInfo, lpProcessInformation);
+    
+    /* Copy Startup Info */
+    RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo));
+    
+    /* Initialize all strings to nothing */
+    LiveCommandLine.Buffer = NULL;
+    DummyString.Buffer = NULL;
+    ApplicationName.Buffer = NULL;
+    CurrentDirectory.Buffer = NULL;
+    StartupInfo.lpDesktop = NULL;
+    StartupInfo.lpReserved = NULL;
+    StartupInfo.lpTitle = NULL;
+    
+    /* Convert the Command line */
+    if (lpCommandLine)
+    {
+        /* If it's too long, then we'll have a problem */
+        if ((strlen(lpCommandLine) + 1) * sizeof(WCHAR) <
+            NtCurrentTeb()->StaticUnicodeString.MaximumLength)
+        {
+            /* Cache it in the TEB */
+            CommandLine = Basep8BitStringToCachedUnicodeString(lpCommandLine);
+        }
+        else
+        {
+            /* Use a dynamic version */
+            Basep8BitStringToHeapUnicodeString(&LiveCommandLine, 
+                                               lpCommandLine);
+        }
+    }
+    else
+    {
+        /* The logic below will use CommandLine, so we must make it valid */
+        CommandLine = &DummyString;
+    }
+    
+    /* Convert the Name and Directory */
+    if (lpApplicationName)
+    {
+        Basep8BitStringToHeapUnicodeString(&ApplicationName, 
+                                           lpApplicationName);
+    }
+    if (lpCurrentDirectory)
+    {
+        Basep8BitStringToHeapUnicodeString(&CurrentDirectory, 
+                                           lpCurrentDirectory);
+    }
+    
+    /* Now convert Startup Strings */
+    if (lpStartupInfo->lpReserved)
+    {
+        BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpReserved,
+                                           &StartupInfo.lpReserved);
+    }
+    if (lpStartupInfo->lpDesktop)
+    {
+        BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpDesktop,
+                                           &StartupInfo.lpDesktop);
+    }
+    if (lpStartupInfo->lpTitle)
+    {
+        BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpTitle,
+                                           &StartupInfo.lpTitle);
+    }
 
-   return(STATUS_SUCCESS);
+    /* Call the Unicode function */
+    bRetVal = CreateProcessW(ApplicationName.Buffer,
+                             LiveCommandLine.Buffer ? 
+                             LiveCommandLine.Buffer : CommandLine->Buffer,
+                             lpProcessAttributes,
+                             lpThreadAttributes,
+                             bInheritHandles,
+                             dwCreationFlags,
+                             lpEnvironment,
+                             CurrentDirectory.Buffer,
+                             &StartupInfo,
+                             lpProcessInformation);
+
+    /* Clean up */
+    RtlFreeUnicodeString(&ApplicationName);
+    RtlFreeUnicodeString(&LiveCommandLine);
+    RtlFreeUnicodeString(&CurrentDirectory);
+    RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpDesktop);
+    RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpReserved);
+    RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpTitle);
+
+    /* Return what Unicode did */
+    return bRetVal;
 }
 
-
-WINBOOL STDCALL 
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
 CreateProcessW(LPCWSTR lpApplicationName,
-              LPWSTR lpCommandLine,
-              LPSECURITY_ATTRIBUTES lpProcessAttributes,
-              LPSECURITY_ATTRIBUTES lpThreadAttributes,
-              WINBOOL bInheritHandles,
-              DWORD dwCreationFlags,
-              LPVOID lpEnvironment,
-              LPCWSTR lpCurrentDirectory,
-              LPSTARTUPINFOW lpStartupInfo,
-              LPPROCESS_INFORMATION lpProcessInformation)
+               LPWSTR lpCommandLine,
+               LPSECURITY_ATTRIBUTES lpProcessAttributes,
+               LPSECURITY_ATTRIBUTES lpThreadAttributes,
+               BOOL bInheritHandles,
+               DWORD dwCreationFlags,
+               LPVOID lpEnvironment,
+               LPCWSTR lpCurrentDirectory,
+               LPSTARTUPINFOW lpStartupInfo,
+               LPPROCESS_INFORMATION lpProcessInformation)
 {
-   HANDLE hSection, hProcess, hThread;
-   NTSTATUS Status;
-   LPTHREAD_START_ROUTINE  lpStartAddress = NULL;
-   WCHAR ImagePathName[256];
-   UNICODE_STRING ImagePathName_U;
-   PROCESS_BASIC_INFORMATION ProcessBasicInfo;
-   ULONG retlen;
-   PRTL_USER_PROCESS_PARAMETERS Ppb;
-   UNICODE_STRING CommandLine_U;
-   CSRSS_API_REQUEST CsrRequest;
-   CSRSS_API_REPLY CsrReply;
-   CHAR ImageFileName[8];
-   PWCHAR s, e;
-   ULONG i, len;
-   ANSI_STRING ProcedureName;
-   UNICODE_STRING CurrentDirectory_U;
-   SECTION_IMAGE_INFORMATION Sii;
-   WCHAR TempCurrentDirectoryW[256];
-   WCHAR TempApplicationNameW[256];
-   WCHAR TempCommandLineNameW[256];
-   UNICODE_STRING RuntimeInfo_U;
-   PVOID ImageBaseAddress;
-
-   DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
-          lpApplicationName, lpCommandLine);
-
-   if (lpApplicationName != NULL && lpApplicationName[0] != 0)
-   {
-      wcscpy (TempApplicationNameW, lpApplicationName);
-      i = wcslen(TempApplicationNameW);
-      if (TempApplicationNameW[i - 1] == L'.')
-      {
-         TempApplicationNameW[i - 1] = 0;
-      }
-      else
-      {
-         s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
-         if (s == NULL)
-         {
-            s = TempApplicationNameW;
-         }
-        else
-        {
-           s++;
-        }
-         e = wcsrchr(s, L'.');
-         if (e == NULL)
-         {
-            wcscat(s, L".exe");
-            e = wcsrchr(s, L'.');
-         }
-      }
-   }
-   else if (lpCommandLine != NULL && lpCommandLine[0] != 0)
-   {
-      if (lpCommandLine[0] == L'"')
-      {
-         wcscpy(TempApplicationNameW, &lpCommandLine[0]);
-         s = wcschr(TempApplicationNameW, L'"');
-         if (s == NULL)
-         {
-           return FALSE;
-         }
-         *s = 0;
-      }
-      else
-      {
-         wcscpy(TempApplicationNameW, lpCommandLine);
-         s = wcschr(TempApplicationNameW, L' ');
-         if (s != NULL)
-         {
-           *s = 0;
-         }
-      }
-      s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
-      if (s == NULL)
-      {
-         s = TempApplicationNameW;
-      }
-      s = wcsrchr(s, L'.');
-      if (s == NULL)
-        wcscat(TempApplicationNameW, L".exe");
-   }
-   else
-   {
-      return FALSE;
-   }
-
-   if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName), ImagePathName, &s))
-   {
-     return FALSE;
-   }
-
-   e = wcsrchr(s, L'.');
-   if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd")))
-   {
-       // the command is a batch file
-       if (lpApplicationName != NULL && lpApplicationName[0])
-       {
-         // FIXME: use COMSPEC for the command interpreter
-         wcscpy(TempCommandLineNameW, L"cmd /c ");
-         wcscat(TempCommandLineNameW, lpApplicationName);
-         lpCommandLine = TempCommandLineNameW;
-         wcscpy(TempApplicationNameW, L"cmd.exe");
-          if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName), ImagePathName, &s))
-         {
-            return FALSE;
-         }
-       }
-       else
-       {
-         return FALSE;
-       }
-   }
+    NTSTATUS Status;
+    PROCESS_PRIORITY_CLASS PriorityClass;
+    BOOLEAN FoundQuotes = FALSE;
+    BOOLEAN QuotesNeeded = FALSE;
+    BOOLEAN CmdLineIsAppName = FALSE;
+    UNICODE_STRING ApplicationName;
+    OBJECT_ATTRIBUTES LocalObjectAttributes;
+    POBJECT_ATTRIBUTES ObjectAttributes;
+    HANDLE hSection, hProcess, hThread;
+    SECTION_IMAGE_INFORMATION SectionImageInfo;
+    LPWSTR CurrentDirectory = NULL;
+    LPWSTR CurrentDirectoryPart;
+    PROCESS_BASIC_INFORMATION ProcessBasicInfo;
+    STARTUPINFOW StartupInfo;
+    ULONG Dummy;
+    LPWSTR BatchCommandLine;
+    ULONG CmdLineLength;
+    UNICODE_STRING CommandLineString;
+    LPWSTR TempBuffer;
+    PWCHAR Extension;
+    LPWSTR QuotedCmdLine = NULL;
+    LPWSTR ScanString;
+    LPWSTR NullBuffer = NULL;
+    LPWSTR NameBuffer = NULL;
+    WCHAR SaveChar = 0;
+    ULONG RetVal;
+    UINT Error = 0;
+    BOOLEAN SearchDone = FALSE;
+    CLIENT_ID ClientId;
+    PPEB OurPeb = NtCurrentPeb();
+    PPEB RemotePeb;
+    
+    DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
+           " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
+           lpApplicationName, lpCommandLine, lpEnvironment, lpCurrentDirectory,
+           dwCreationFlags);
+    
+    /* Flags we don't handle yet */
+    if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)
+    {
+        DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
+    }
+    if (dwCreationFlags & CREATE_SHARED_WOW_VDM)
+    {
+        DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
+    }
+    if (dwCreationFlags & CREATE_FORCEDOS)
+    {
+        DPRINT1("CREATE_FORCEDOS not handled\n");
+    }
+    
+    /* Fail on this flag, it's only valid with the WithLogonW function */
+    if (dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
+    {
+        DPRINT1("Invalid flag used\n");
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    
+    /* 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;
+    }
+    
+    /* Another illegal combo */
+    if ((dwCreationFlags & (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) ==
+        (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM))
+    {
+        DPRINT1("Invalid flag combo used\n");
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
 
-   /*
-    * Store the image file name for the process
-    */
-   e = wcschr(s, L'.');
-   if (e != NULL)
-     {
-       *e = 0;
-     }
-   for (i = 0; i < 8; i++)
-     {
-       ImageFileName[i] = (CHAR)(s[i]);
-     }
-   if (e != NULL)
-     {
-       *e = '.';
-     }
-   
-   /*
-    * Process the application name and command line
-    */
-   RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
-   RtlInitUnicodeString(&CommandLine_U, lpCommandLine);
+    /* 
+     * 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;
+    /* FIXME: Use default Separate/Shared VDM Flag */
+    
+    /* 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))
+        {
+            /* Remove the shared flag and add the separate flag. */
+            dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) | 
+                                                  CREATE_SEPARATE_WOW_VDM;
+        }
+    }
 
-   DPRINT("ImagePathName_U %S\n", ImagePathName_U.Buffer);
-   DPRINT("CommandLine_U %S\n", CommandLine_U.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
+     */
+    if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) && 
+        (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
+    {
+        StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
+    }
 
-   /* Initialize the current directory string */
-   if (lpCurrentDirectory != NULL)
-     {
-       RtlInitUnicodeString(&CurrentDirectory_U,
-                           lpCurrentDirectory);
-     }
-   else
-     {
-       GetCurrentDirectoryW(256, TempCurrentDirectoryW);
-       RtlInitUnicodeString(&CurrentDirectory_U,
-                           TempCurrentDirectoryW);
-     }
+    /* Start by zeroing out the fields */
+    RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION));
 
-   
-   /*
-    * Create a section for the executable
-    */
-   
-   hSection = KlMapFile (ImagePathName);
-   if (hSection == NULL)
-   {
-/////////////////////////////////////////
-        /*
-         * Inspect the image to determine executable flavour
-         */
-        IO_STATUS_BLOCK IoStatusBlock;
-        UNICODE_STRING ApplicationNameString;
-        OBJECT_ATTRIBUTES ObjectAttributes;
-        PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
-        IMAGE_DOS_HEADER DosHeader;
-        IO_STATUS_BLOCK Iosb;
-        LARGE_INTEGER Offset;
-        HANDLE hFile = NULL;
+    /* Easy stuff first, convert the process priority class */
+    PriorityClass.Foreground = FALSE;
+    PriorityClass.PriorityClass = BasepConvertPriorityClass(dwCreationFlags);
 
-        DPRINT("Inspecting Image Header for image type id\n");
+    /* Convert the environment */
+    if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+    {
+        lpEnvironment = BasepConvertUnicodeEnvironment(lpEnvironment);
+        if (!lpEnvironment) return FALSE;
+    }
 
-        // Find the application name
-        if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName,
-                &ApplicationNameString, NULL, 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!) */
+    if (!lpApplicationName)
+    {
+        /* The fun begins */
+        NameBuffer = RtlAllocateHeap(GetProcessHeap(), 
+                                     0,
+                                     MAX_PATH * sizeof(WCHAR));
+        
+        /* This is all we have to work with :( */
+        lpApplicationName = lpCommandLine;
+        
+        /* Initialize our friends at the beginning */
+        NullBuffer = (LPWSTR)lpApplicationName;
+        ScanString = (LPWSTR)lpApplicationName;
+        
+        /* We will start by looking for a quote */
+        if (*ScanString == L'\"')
+        {
+             /* That was quick */
+             SearchDone = TRUE;
+             
+             /* Advance past quote */
+             ScanString++;
+             lpApplicationName = ScanString;             
+
+             /* Find the closing quote */
+             while (*ScanString)
+             {
+                 if (*ScanString == L'\"')
+                 {
+                     /* Found it */
+                     NullBuffer = ScanString;
+                     FoundQuotes = TRUE;
+                     break;
+                 }
+
+                 /* Keep looking */
+                 ScanString++;
+                 NullBuffer = ScanString;
+             }
+        }
+        else
+        {
+            /* No quotes, so we'll be looking for white space */
+        WhiteScan:   
+            /* Reset the pointer */
+            lpApplicationName = lpCommandLine;
+
+            /* Find whitespace of Tab */
+            while (*ScanString)
+            {
+                if (*ScanString == ' ' || *ScanString == '\t')
+                {
+                    /* Found it */
+                    NullBuffer = ScanString;
+                    break;
+                }
+
+                /* Keep looking */
+                ScanString++;
+                NullBuffer = ScanString;
+            }
+        }
+                 
+        /* Set the Null Buffer */
+        SaveChar = *NullBuffer;
+        *NullBuffer = UNICODE_NULL;
+                
+        /* Do a search for the file */
+        DPRINT("Ready for SearchPathW: %S\n", lpApplicationName);
+        RetVal = SearchPathW(NULL,
+                             lpApplicationName,
+                             L".exe",
+                             MAX_PATH,
+                             NameBuffer,
+                             NULL) * sizeof(WCHAR);
+               
+        /* Did it find something? */
+        if (RetVal)
+        {
+            /* Get file attributes */
+            ULONG Attributes = GetFileAttributesW(NameBuffer);
+            if (Attributes & FILE_ATTRIBUTE_DIRECTORY)
+            {
+                /* Give it a length of 0 to fail, this was a directory. */
+                RetVal = 0;
+            }
+            else
+            {
+                /* It's a file! */
+                RetVal += sizeof(WCHAR);
+            }
+        }
+                
+        /* 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;
+            
+            /* We failed, try to get the Path Type */
+            DPRINT("SearchPathW failed. Retval: %ld\n", RetVal);
+            PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
+                    
+            /* If it's not relative, try to get the error */
+            if (PathType != RELATIVE_PATH)
+            {
+                /* 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)
+                {
+                    /* Fake the error */
+                    CloseHandle(hFile);
+                    SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
+                }
+            }
+            else
+            {
+                /* Immediately set the error */
+                SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
+            }
+                    
+            /* Did we already fail once? */
+            if (Error)
+            {
+                SetLastError(Error);
+            }
+            else
+            {
+                /* Not yet, cache it */
+                Error = 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)
+            {
+                /* Move in the buffer */
+                ScanString++;
+                NullBuffer = ScanString;
+                
+                /* We will have to add a quote, since there is a space*/
+                QuotesNeeded = TRUE;
+                    
+                /* And we will also fake the fact we found one */
+                FoundQuotes = TRUE;
+                    
+                /* Start over */
+                goto WhiteScan;
+            }
+                
+            /* We totally failed */
             return FALSE;
         }
-        DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
+                
+        /* Put back the command line */
+        *NullBuffer = SaveChar;
+        lpApplicationName = NameBuffer;
+        DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer);
+    }
+    else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL)
+    {
+        /* We have an app name (good!) but no command line */
+        CmdLineIsAppName = TRUE;
+        lpCommandLine = (LPWSTR)lpApplicationName;
+    }
+     
+    /* At this point the name has been toyed with enough to be openable */
+    Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName);
+    
+    /* Check for failure */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Could be a non-PE File */
+        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_NOT_MZ:
+            
+            /* If it's a DOS app, use VDM
+            if ((BasepCheckDosApp(&ApplicationName))) */
+            {
+                DPRINT1("Launching VDM...\n");
+                RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
+                RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+                return CreateProcessW(L"ntvdm.exe",
+                                      (LPWSTR)lpApplicationName,
+                                      lpProcessAttributes,
+                                      lpThreadAttributes,
+                                      bInheritHandles,
+                                      dwCreationFlags,
+                                      lpEnvironment,
+                                      lpCurrentDirectory,
+                                      lpStartupInfo,
+                                      lpProcessInformation);    
+            }
+            
+            /* 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))
+            {
+                SetLastError(ERROR_BAD_EXE_FORMAT);
+                return FALSE;
+            }
+            
+            /* Calculate the length of the command line */
+            CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1;
+            
+            /* If we found quotes, then add them into the length size */
+            if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2;
+            CmdLineLength *= sizeof(WCHAR);
+            
+            /* Allocate space for the new command line */
+            BatchCommandLine = RtlAllocateHeap(GetProcessHeap(),
+                                               0,
+                                               CmdLineLength);
+                                              
+            /* Build it */
+            wcscpy(BatchCommandLine, CMD_STRING);
+            if (CmdLineIsAppName || FoundQuotes)
+            {
+                wcscat(BatchCommandLine, L"\"");
+            }
+            wcscat(BatchCommandLine, lpCommandLine);
+            if (CmdLineIsAppName || FoundQuotes)
+            {
+                wcscat(BatchCommandLine, L"\"");
+            }
+            
+            /* Create it as a Unicode String */
+            RtlInitUnicodeString(&CommandLineString, BatchCommandLine);
+            
+            /* Set the command line to this */
+            lpCommandLine = CommandLineString.Buffer;
+            lpApplicationName = NULL;
+            
+            /* Free memory */
+            RtlFreeHeap(GetProcessHeap(), 0, TempBuffer);
+            RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+            ApplicationName.Buffer = NULL;
+            TempBuffer = NULL;
+            goto GetAppName;
+            break;
+            
+            case STATUS_INVALID_IMAGE_WIN_16:
+            
+                /* It's a Win16 Image, use VDM */
+                DPRINT1("Launching VDM...\n");
+                RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
+                RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+                return CreateProcessW(L"ntvdm.exe",
+                                      (LPWSTR)lpApplicationName,
+                                      lpProcessAttributes,
+                                      lpThreadAttributes,
+                                      bInheritHandles,
+                                      dwCreationFlags,
+                                      lpEnvironment,
+                                      lpCurrentDirectory,
+                                      lpStartupInfo,
+                                      lpProcessInformation);    
+
+            default:
+                /* Invalid Image Type */
+                SetLastError(ERROR_BAD_EXE_FORMAT);
+                return FALSE;
+        }
+    }
+    
+    /* Use our desktop if we didn't get any */
+    if (!StartupInfo.lpDesktop)
+    {
+        StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer;
+    }
+    
+    /* FIXME: Check if Application is allowed to run */
+    
+    /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
+    
+    /* Get some information about the executable */
+    Status = ZwQuerySection(hSection,
+                            SectionImageInformation,
+                            &SectionImageInfo,
+                            sizeof(SectionImageInfo),
+                            NULL);
+    if(!NT_SUCCESS(Status))
+    {
+        NtClose(hSection);
+        DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status);
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
 
-        InitializeObjectAttributes(&ObjectAttributes,
-                             &ApplicationNameString,
-                             OBJ_CASE_INSENSITIVE,
-                             NULL,
-                             SecurityDescriptor);
+    /* Don't execute DLLs */
+    if (SectionImageInfo.ImageCharacteristics & IMAGE_FILE_DLL)
+    {
+        NtClose(hSection);
+        DPRINT1("Can't execute a DLL\n");
+        SetLastError(ERROR_BAD_EXE_FORMAT);
+        return FALSE;
+    }
+    
+    /* FIXME: Check for Debugger */
+    
+    /* FIXME: Check if Machine Type and SubSys Version Match */
 
-        // Try to open the executable
-        Status = NtOpenFile(&hFile,
-                       SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
-                       &ObjectAttributes,
-                       &IoStatusBlock,
-                       FILE_SHARE_DELETE|FILE_SHARE_READ,
-                       FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
+    /* We don't support POSIX or anything else for now */
+    if (IMAGE_SUBSYSTEM_WINDOWS_GUI != SectionImageInfo.SubsystemType && 
+        IMAGE_SUBSYSTEM_WINDOWS_CUI != SectionImageInfo.SubsystemType)
+    {
+        NtClose(hSection);
+        DPRINT1("Invalid subsystem %d\n", SectionImageInfo.SubsystemType);
+        SetLastError(ERROR_BAD_EXE_FORMAT);
+        return FALSE;
+    }
 
-        RtlFreeUnicodeString(&ApplicationNameString);
+    /* Initialize the process object attributes */
+    ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes, 
+                                                    lpProcessAttributes,
+                                                    NULL);
+   
+    /* Create the Process */
+    Status = NtCreateProcess(&hProcess,
+                             PROCESS_ALL_ACCESS,
+                             ObjectAttributes,
+                             NtCurrentProcess(),
+                             bInheritHandles,
+                             hSection,
+                             NULL,
+                             NULL);
+    if(!NT_SUCCESS(Status))
+    {
+        NtClose(hSection);
+        DPRINT1("Unable to create process, status 0x%x\n", Status);
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+    
+    /* Set new class */
+    Status = NtSetInformationProcess(hProcess,
+                                     ProcessPriorityClass,
+                                     &PriorityClass,
+                                     sizeof(PROCESS_PRIORITY_CLASS));
+    if(!NT_SUCCESS(Status))
+    {
+        NtClose(hProcess);
+        NtClose(hSection);
+        DPRINT1("Unable to set new process priority, status 0x%x\n", Status);
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+    
+    /* Set Error Mode */
+    if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
+    {
+        ULONG ErrorMode = SEM_FAILCRITICALERRORS;
+        NtSetInformationProcess(hProcess,
+                                ProcessDefaultHardErrorMode,
+                                &ErrorMode,
+                                sizeof(ULONG));
+    }
 
-        if (!NT_SUCCESS(Status)) {
-            DPRINT("Failed to open file\n");
-            SetLastErrorByStatus(Status);
+    /* Convert the directory to a full path */
+    if (lpCurrentDirectory)
+    {
+        /* Allocate a buffer */
+        CurrentDirectory = RtlAllocateHeap(GetProcessHeap(),
+                                           0,
+                                           MAX_PATH * sizeof(WCHAR) + 2);
+                                           
+        /* Get the length */
+        if (GetFullPathNameW(lpCurrentDirectory,
+                             MAX_PATH,
+                             CurrentDirectory,
+                             &CurrentDirectoryPart) > MAX_PATH)
+        {
+            DPRINT1("Directory name too long\n");
+            SetLastError(ERROR_DIRECTORY);
             return FALSE;
         }
-
-        // Read the dos header
-        Offset.QuadPart = 0;
-        Status = ZwReadFile(hFile,
-                     NULL,
-                     NULL,
-                     NULL,
-                     &Iosb,
-                     &DosHeader,
-                     sizeof(DosHeader),
-                     &Offset,
-                     0);
-
-        if (!NT_SUCCESS(Status)) {
-            DPRINT("Failed to read from file\n");
-            SetLastErrorByStatus(Status);
-            return FALSE;
+    }
+    
+    /* Insert quotes if needed */
+    if (QuotesNeeded || CmdLineIsAppName)
+    {
+        /* Allocate a buffer */
+        QuotedCmdLine = RtlAllocateHeap(GetProcessHeap(), 
+                                        0,
+                                        (wcslen(lpCommandLine) + 2 + 1) * 
+                                        sizeof(WCHAR));
+                                        
+        /* Copy the first quote */
+        wcscpy(QuotedCmdLine, L"\"");
+        
+        /* Save a null char */
+        if (QuotesNeeded)
+        {
+            SaveChar = *NullBuffer;
+            *NullBuffer = UNICODE_NULL;
         }
-        if (Iosb.Information != sizeof(DosHeader)) {
-            DPRINT("Failed to read dos header from file\n");
-            SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
-            return FALSE;
+        
+        /* Add the command line and the finishing quote */
+        wcscat(QuotedCmdLine, lpCommandLine);
+        wcscat(QuotedCmdLine, L"\"");
+        
+        /* Add the null char */
+        if (QuotesNeeded)
+        {
+            *NullBuffer = SaveChar;
+            wcscat(QuotedCmdLine, NullBuffer);
         }
+        
+        DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine);
+    }
+    
+    /* Get the Process Information */
+    Status = NtQueryInformationProcess(hProcess,
+                                       ProcessBasicInformation,
+                                       &ProcessBasicInfo,
+                                       sizeof(ProcessBasicInfo),
+                                       NULL);
+    
+    /* Create Process Environment */
+    RemotePeb = ProcessBasicInfo.PebBaseAddress;
+    Status = BasepInitializeEnvironment(hProcess,
+                                        RemotePeb,
+                                        (LPWSTR)lpApplicationName,
+                                        CurrentDirectory,
+                                        (QuotesNeeded || CmdLineIsAppName) ?
+                                        QuotedCmdLine : lpCommandLine,
+                                        lpEnvironment,
+                                        lpStartupInfo,
+                                        dwCreationFlags,
+                                        bInheritHandles);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Could not initialize Process Environment\n");
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+    
+    /* Close the section */
+    NtClose(hSection);
+    hSection = NULL;
 
-        // Check the DOS signature
-        if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
-            DPRINT("Failed dos magic check\n");
-            SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
+    /* Duplicate the handles if needed */
+    if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
+        SectionImageInfo.SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
+    {
+        PRTL_USER_PROCESS_PARAMETERS RemoteParameters;
+        
+        /* Get the remote parameters */
+        Status = NtReadVirtualMemory(hProcess,
+                                     &RemotePeb->ProcessParameters,
+                                     &RemoteParameters,
+                                     sizeof(PVOID),
+                                     NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to read memory\n");
             return FALSE;
         }
-        NtClose(hFile);
-
-        DPRINT("Launching VDM...\n");
-        return CreateProcessW(L"ntvdm.exe",
-                lpApplicationName,
-                lpProcessAttributes,
-                lpThreadAttributes,
-                bInheritHandles,
-                dwCreationFlags,
-                lpEnvironment,
-                lpCurrentDirectory,
-                lpStartupInfo,
-                lpProcessInformation);
-   }
-/////////////////////////////////////////
-   /*
-    * Create a new process
-    */
-   Status = NtCreateProcess(&hProcess,
-                           PROCESS_ALL_ACCESS,
-                           NULL,
-                           NtCurrentProcess(),
-                           bInheritHandles,
-                           hSection,
-                           NULL,
-                           NULL);
-   if (lpStartupInfo)
-   {
-      if (lpStartupInfo->lpReserved2)
-      {
-         ULONG i, Count = *(ULONG*)lpStartupInfo->lpReserved2;
-         HANDLE * hFile;  
-        HANDLE hTemp;
-        PRTL_USER_PROCESS_PARAMETERS CurrPpb = NtCurrentPeb()->ProcessParameters;  
-
-
-         /* FIXME:
-         *    ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
-         *    the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
-         *    If is possible that this function overwrite the last information in runtimeinfo
-         *    with the null terminator for the unicode string.
-         */
-        RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = ROUND_UP(lpStartupInfo->cbReserved2, 2) + 2;
-        RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length);
-        memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2);
-      }
-   } 
-
-   /*
-    * Create the PPB
-    */
-   RtlCreateProcessParameters(&Ppb,
-                             &ImagePathName_U,
-                             NULL,
-                             lpCurrentDirectory ? &CurrentDirectory_U : NULL,
-                             &CommandLine_U,
-                             lpEnvironment,
-                             NULL,
-                             NULL,
-                             NULL,
-                             lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL);
-
-   if (lpStartupInfo && lpStartupInfo->lpReserved2)
-       RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer);
-  
-
-   /*
-    * Translate some handles for the new process
-    */
-   if (Ppb->CurrentDirectoryHandle)
-   {
-      Status = NtDuplicateObject (NtCurrentProcess(), 
-                        Ppb->CurrentDirectoryHandle,
-                        hProcess,
-                        &Ppb->CurrentDirectoryHandle,
-                        0,
-                        TRUE,
-                        DUPLICATE_SAME_ACCESS);
-   }
-
-   if (Ppb->hConsole)
-   {
-      Status = NtDuplicateObject (NtCurrentProcess(), 
-                        Ppb->hConsole,
-                        hProcess,
-                        &Ppb->hConsole,
-                        0,
-                        TRUE,
-                        DUPLICATE_SAME_ACCESS);
-   }
-
-   /*
-    * Get some information about the executable
-    */
-   Status = ZwQuerySection(hSection,
-                          SectionImageInformation,
-                          &Sii,
-                          sizeof(Sii),
-                          &i);
-   /*
-    * Close the section
-    */
-   NtClose(hSection);
-
-   /*
-    * Get some information about the process
-    */
-   ZwQueryInformationProcess(hProcess,
-                            ProcessBasicInformation,
-                            &ProcessBasicInfo,
-                            sizeof(ProcessBasicInfo),
-                            &retlen);
-   DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
-         ProcessBasicInfo.UniqueProcessId);
-   lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
-   
-   /*
-    * Tell the csrss server we are creating a new process
-    */
-   CsrRequest.Type = CSRSS_CREATE_PROCESS;
-   CsrRequest.Data.CreateProcessRequest.NewProcessId = 
-     ProcessBasicInfo.UniqueProcessId;
-   CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
-   Status = CsrClientCallServer(&CsrRequest, 
-                               &CsrReply,
-                               sizeof(CSRSS_API_REQUEST),
-                               sizeof(CSRSS_API_REPLY));
-   if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
-     {
-       DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
-     }
-
-   // Set the child console handles 
-   Ppb->hStdInput = NtCurrentPeb()->ProcessParameters->hStdInput;
-   Ppb->hStdOutput = NtCurrentPeb()->ProcessParameters->hStdOutput;
-   Ppb->hStdError = NtCurrentPeb()->ProcessParameters->hStdError;
-
-   if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
-   {
-      if (lpStartupInfo->hStdInput)
-        Ppb->hStdInput = lpStartupInfo->hStdInput;
-      if (lpStartupInfo->hStdOutput)
-        Ppb->hStdOutput = lpStartupInfo->hStdOutput;
-      if (lpStartupInfo->hStdError)
-        Ppb->hStdError = lpStartupInfo->hStdError;
-   }
-
-   if (IsConsoleHandle(Ppb->hStdInput))
-   {
-      Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
-   }
-   else
-   {
-      DPRINT("Duplicate input handle\n");
-      Status = NtDuplicateObject (NtCurrentProcess(), 
-                                 Ppb->hStdInput,
-                                 hProcess,
-                                 &Ppb->hStdInput,
-                                 0,
-                                 TRUE,
-                                 DUPLICATE_SAME_ACCESS);
-      if(!NT_SUCCESS(Status))
-      {
-        DPRINT("NtDuplicateObject failed, status %x\n", Status);
-      }
-   }
-
-   if (IsConsoleHandle(Ppb->hStdOutput))
-   {
-      Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
-   }
-   else
-   {
-      DPRINT("Duplicate output handle\n");
-      Status = NtDuplicateObject (NtCurrentProcess(), 
-                                 Ppb->hStdOutput,
-                                 hProcess,
-                                 &Ppb->hStdOutput,
-                                 0,
-                                 TRUE,
-                                 DUPLICATE_SAME_ACCESS);
-      if(!NT_SUCCESS(Status))
-      {
-        DPRINT("NtDuplicateObject failed, status %x\n", Status);
-      }
-   }
-   if (IsConsoleHandle(Ppb->hStdError))
-   {
-      Ppb->hStdError = CsrReply.Data.CreateProcessReply.OutputHandle;
-   }
-   else
-   {
-      DPRINT("Duplicate error handle\n");
-      Status = NtDuplicateObject (NtCurrentProcess(), 
-                                 Ppb->hStdError,
-                                 hProcess,
-                                 &Ppb->hStdError,
-                                 0,
-                                 TRUE,
-                                 DUPLICATE_SAME_ACCESS);
-      if(!NT_SUCCESS(Status))
-      {
-        DPRINT("NtDuplicateObject failed, status %x\n", Status);
-      }
-   }
-
-   /*
-    * Initialize some other fields in the PPB
-    */
-   if (lpStartupInfo)
-     {
-       Ppb->dwFlags = lpStartupInfo->dwFlags;
-       if (Ppb->dwFlags & STARTF_USESHOWWINDOW)
-        {
-          Ppb->wShowWindow = lpStartupInfo->wShowWindow;
-        }
-       else
-        {
-          Ppb->wShowWindow = SW_SHOWDEFAULT;
-        }
-       Ppb->dwX = lpStartupInfo->dwX;
-       Ppb->dwY = lpStartupInfo->dwY;
-       Ppb->dwXSize = lpStartupInfo->dwXSize;
-       Ppb->dwYSize = lpStartupInfo->dwYSize;
-       Ppb->dwFillAttribute = lpStartupInfo->dwFillAttribute;
-     }
-   else
-     {
-       Ppb->Flags = 0;
-     }
-   
-   /*
-    * Create Process Environment Block
-    */
-   DPRINT("Creating peb\n");
-
-   KlInitPeb(hProcess, Ppb, &ImageBaseAddress);
+        
+        /* 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);
+    }
+        
+    /* Create the first thread */
+    DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
+            SectionImageInfo.TransferAddress);
+    hThread = BasepCreateFirstThread(hProcess,
+                                     lpThreadAttributes,
+                                     &SectionImageInfo,
+                                     &ClientId);
+
+    if (hThread == NULL)
+    {
+        DPRINT1("Could not create Initial Thread\n");
+        return FALSE;
+    }
 
-   RtlDestroyProcessParameters (Ppb);
+    
+    /* Notify CSRSS */
+    Status = BasepNotifyCsrOfCreation(dwCreationFlags,
+                                      (HANDLE)ProcessBasicInfo.UniqueProcessId);
 
-   Status = NtSetInformationProcess(hProcess,
-                                   ProcessImageFileName,
-                                   ImageFileName,
-                                   8);
-   /*
-    * Create the thread for the kernel
-    */
-   DPRINT("Creating thread for process\n");
-   hThread =  KlCreateFirstThread(hProcess,
-                                 lpThreadAttributes,
-                                 Sii.StackReserve,
-                                 Sii.StackCommit,
-                                 ImageBaseAddress + (ULONG)Sii.EntryPoint,
-                                 dwCreationFlags,
-                                 &lpProcessInformation->dwThreadId);
-   if (hThread == INVALID_HANDLE_VALUE)
-     {
-       return FALSE;
-     }
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("CSR Notification Failed");
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+    
+    if (!(dwCreationFlags & CREATE_SUSPENDED))
+    {
+        NtResumeThread(hThread, &Dummy);
+    }
+    
+    /* Cleanup Environment */    
+    if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+    {
+        RtlDestroyEnvironment(lpEnvironment);
+    }
 
-   lpProcessInformation->hProcess = hProcess;
-   lpProcessInformation->hThread = hThread;
+    /* Return Data */        
+    lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess;
+    lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread;
+    lpProcessInformation->hProcess = hProcess;
+    lpProcessInformation->hThread = hThread;
+    DPRINT("hThread[%lx]: %lx inside hProcess[%lx]: %lx\n", hThread,
+            ClientId.UniqueThread, ClientId.UniqueProcess, hProcess);
+    hProcess = hThread = NULL;
+            
+    /* De-allocate heap strings */
+    if (NameBuffer) RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
+    if (ApplicationName.Buffer)
+        RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+    if (CurrentDirectory) RtlFreeHeap(GetProcessHeap(), 0, CurrentDirectory);
+    if (QuotedCmdLine) RtlFreeHeap(GetProcessHeap(), 0, QuotedCmdLine);
+
+    /* Kill any handles still alive */
+    if (hSection) NtClose(hSection);
+    if (hThread)
+    {
+        /* We don't know any more details then this */
+        NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL);
+        NtClose(hThread);
+    }
+    if (hProcess) NtClose(hProcess);
 
-   return TRUE;
+    /* Return Success */
+    return TRUE;
 }
 
 /* EOF */