RetVal is in bytes, so check against MAX_PATH in bytes
[reactos.git] / reactos / lib / kernel32 / process / create.c
index d47f706..23fd7d1 100644 (file)
-/* $Id$
- *
+/*
  * 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>
-#include <pseh/framebased.h>
 
 #define NDEBUG
 #include "../include/debug.h"
 
-/* FUNCTIONS ****************************************************************/
+#define CMD_STRING L"cmd /c "
 
 extern __declspec(noreturn)
-VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag);
+VOID
+CALLBACK 
+ConsoleControlDispatcher(DWORD CodeAndFlag);
 
-__declspec(dllimport)
-PRTL_BASE_PROCESS_START_ROUTINE RtlBaseProcessStartRoutine;
+/* INTERNAL FUNCTIONS *******************************************************/
 
-typedef NTSTATUS STDCALL (K32_MBSTR_TO_WCSTR)
-(
-   UNICODE_STRING *,
-   ANSI_STRING *,
-   BOOLEAN
-);
-
-NTSTATUS STDCALL K32MbStrToWcStr(IN K32_MBSTR_TO_WCSTR * True,
-                                UNICODE_STRING * DestStr,
-                                ANSI_STRING * SourceStr,
-                                BOOLEAN Allocate)
+_SEH_FILTER(BaseExceptionFilter)
 {
-   if(SourceStr->Buffer == NULL)
-   {
-      DestStr->Length = DestStr->MaximumLength = 0;
-      DestStr->Buffer = NULL;
-      return STATUS_SUCCESS;
-   }
-
-   return True(DestStr, SourceStr, Allocate);
+    EXCEPTION_POINTERS *ExceptionInfo = _SEH_GetExceptionPointers();
+    LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
+
+    if (GlobalTopLevelExceptionFilter != NULL)
+    {
+        _SEH_TRY
+        {
+            ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo);
+        }
+        _SEH_HANDLE
+        {
+        }
+        _SEH_END;
+    }
+    if ((ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH || ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER) &&
+        GlobalTopLevelExceptionFilter != UnhandledExceptionFilter)
+    {
+       ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
+    }
+
+    return ExceptionDisposition;
 }
 
-VOID STDCALL RtlRosR32AttribsToNativeAttribs(OUT OBJECT_ATTRIBUTES * NativeAttribs,
-                                            IN SECURITY_ATTRIBUTES * Ros32Attribs OPTIONAL)
+VOID
+STDCALL
+BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress)
 {
-   NativeAttribs->Length = sizeof(*NativeAttribs);
-   NativeAttribs->ObjectName = NULL;
-   NativeAttribs->RootDirectory = NULL;
-   NativeAttribs->Attributes = 0;
-   NativeAttribs->SecurityQualityOfService = NULL;
-
-
-   if(Ros32Attribs != NULL && Ros32Attribs->nLength >= sizeof(*Ros32Attribs))
-   {
-      NativeAttribs->SecurityDescriptor = Ros32Attribs->lpSecurityDescriptor;
-
-      if(Ros32Attribs->bInheritHandle)
-      {
-         NativeAttribs->Attributes |= OBJ_INHERIT;
-      }
-   }
-   else
-   {
-      NativeAttribs->SecurityDescriptor = NULL;
-   }
+    UINT uExitCode = 0;
+
+    DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
+
+    _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;
+
+    /* Exit the Process with our error */
+    ExitProcess(uExitCode);
 }
 
-VOID STDCALL RtlRosR32AttribsToNativeAttribsNamed(OUT OBJECT_ATTRIBUTES * NativeAttribs,
-                                                 IN SECURITY_ATTRIBUTES * Ros32Attribs OPTIONAL,
-                                                 OUT UNICODE_STRING * NativeName OPTIONAL,
-                                                 IN WCHAR * Ros32Name OPTIONAL,
-                                                 IN HANDLE Ros32NameRoot OPTIONAL)
+/*
+ * Tells CSR that a new process was created
+ */
+NTSTATUS
+STDCALL
+BasepNotifyCsrOfCreation(ULONG dwCreationFlags,
+                         IN HANDLE ProcessId,
+                         IN BOOL InheritHandles)
 {
-   if(!NativeAttribs) return;
-
-   RtlRosR32AttribsToNativeAttribs(NativeAttribs, Ros32Attribs);
-
-   if(Ros32Name != NULL && NativeName != NULL)
-   {
-      RtlInitUnicodeString(NativeName, Ros32Name);
-
-      NativeAttribs->ObjectName = NativeName;
-      NativeAttribs->RootDirectory = Ros32NameRoot;
-      NativeAttribs->Attributes |= OBJ_CASE_INSENSITIVE;
-   }
+    ULONG Request = CREATE_PROCESS;
+    CSR_API_MESSAGE CsrRequest;
+    NTSTATUS Status;
+    
+    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;
+    
+    /* 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;
 }
 
-
 /*
- * @implemented
+ * Creates the first Thread in a Proces
  */
-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)
+HANDLE
+STDCALL
+BasepCreateFirstThread(HANDLE ProcessHandle,
+                       LPSECURITY_ATTRIBUTES lpThreadAttributes,
+                       PSECTION_IMAGE_INFORMATION SectionImageInfo,
+                       PCLIENT_ID ClientId)
+{
+    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;
+}
+
 /*
- * 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
+ * Converts ANSI to Unicode Environment
  */
+PVOID
+STDCALL
+BasepConvertUnicodeEnvironment(OUT SIZE_T* EnvSize,
+                               IN PVOID lpEnvironment)
 {
-   UNICODE_STRING wstrApplicationName;
-   UNICODE_STRING wstrCurrentDirectory;
-   UNICODE_STRING wstrCommandLine;
-   UNICODE_STRING wstrReserved;
-   UNICODE_STRING wstrDesktop;
-   UNICODE_STRING wstrTitle;
-   UNICODE_STRING wstrEnvVar;
-   ANSI_STRING strApplicationName;
-   ANSI_STRING strCurrentDirectory;
-   ANSI_STRING strCommandLine;
-   ANSI_STRING strReserved;
-   ANSI_STRING strDesktop;
-   ANSI_STRING strTitle;
-   BOOL bRetVal;
-   STARTUPINFOW wsiStartupInfo;
-
-   NTSTATUS STDCALL_FUNC (*pTrue)(UNICODE_STRING *,
-                                  ANSI_STRING *,
-                                 BOOLEAN);
-
-   ULONG STDCALL_FUNC (*pRtlMbStringToUnicodeSize)(ANSI_STRING *);
-
-   DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
-          "lpStartupInfo %x, lpProcessInformation %x\n",
-         dwCreationFlags, lpEnvironment, lpCurrentDirectory,
-          lpStartupInfo, lpProcessInformation);
-
-   /* multibyte strings are ANSI */
-   if(bIsFileApiAnsi)
-   {
-      pTrue = RtlAnsiStringToUnicodeString;
-      pRtlMbStringToUnicodeSize = RtlAnsiStringToUnicodeSize;
-   }
-   /* multibyte strings are OEM */
-   else
-   {
-      pTrue = RtlOemStringToUnicodeString;
-      pRtlMbStringToUnicodeSize = RtlOemStringToUnicodeSize;
-   }
-
-   /* invalid parameter */
-   if(lpStartupInfo == NULL)
-   {
-      SetLastError(ERROR_INVALID_PARAMETER);
-      return FALSE;
-   }
-
-   /* convert the environment */
-   if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
-   {
-      PCHAR pcScan;
-      SIZE_T nEnvLen = 0;
-      ANSI_STRING strEnvVar;
-      NTSTATUS Status;
-
-      /* scan the environment to calculate its Unicode size */
-      pcScan = lpEnvironment;
-      do
-      {
-         pcScan += strlen(pcScan) + 1;
-      }
-      while (*pcScan);
-
-      nEnvLen = (ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + 1;
-
-      /* environment too large */
-      if(nEnvLen > ~((USHORT)0))
-      {
-         SetLastError(ERROR_OUTOFMEMORY);
-         return FALSE;
-      }
-
-      strEnvVar.Buffer = lpEnvironment;
-      strEnvVar.MaximumLength = strEnvVar.Length = nEnvLen;
-
-      Status = K32MbStrToWcStr(pTrue, &wstrEnvVar, &strEnvVar, TRUE);
-
-      /* failure */
-      if (!NT_SUCCESS(Status))
-      {
-         SetLastError(ERROR_OUTOFMEMORY);
-         return FALSE;
-      }
-   }
-
-
-   /* convert the strings */
-   RtlInitAnsiString(&strCommandLine, lpCommandLine);
-   RtlInitAnsiString(&strApplicationName, (LPSTR)lpApplicationName);
-   RtlInitAnsiString(&strCurrentDirectory, (LPSTR)lpCurrentDirectory);
-   RtlInitAnsiString(&strReserved, (LPSTR)lpStartupInfo->lpReserved);
-   RtlInitAnsiString(&strDesktop, (LPSTR)lpStartupInfo->lpDesktop);
-   RtlInitAnsiString(&strTitle, (LPSTR)lpStartupInfo->lpTitle);
-
-   K32MbStrToWcStr(pTrue, &wstrCommandLine, &strCommandLine, TRUE);
-   K32MbStrToWcStr(pTrue, &wstrApplicationName, &strApplicationName, TRUE);
-   K32MbStrToWcStr(pTrue, &wstrCurrentDirectory, &strCurrentDirectory, TRUE);
-   K32MbStrToWcStr(pTrue, &wstrReserved, &strReserved, TRUE);
-   K32MbStrToWcStr(pTrue, &wstrDesktop, &strDesktop, TRUE);
-   K32MbStrToWcStr(pTrue, &wstrTitle, &strTitle, TRUE);
-
-   /* convert the startup information */
-   memcpy(&wsiStartupInfo, lpStartupInfo, sizeof(wsiStartupInfo));
-
-   wsiStartupInfo.lpReserved = wstrReserved.Buffer;
-   wsiStartupInfo.lpDesktop = wstrDesktop.Buffer;
-   wsiStartupInfo.lpTitle = wstrTitle.Buffer;
-
-   DPRINT("wstrApplicationName  %wZ\n", &wstrApplicationName);
-   DPRINT("wstrCommandLine      %wZ\n", &wstrCommandLine);
-   DPRINT("wstrCurrentDirectory %wZ\n", &wstrCurrentDirectory);
-   DPRINT("wstrReserved         %wZ\n", &wstrReserved);
-   DPRINT("wstrDesktop          %wZ\n", &wstrDesktop);
-   DPRINT("wstrTitle            %wZ\n", &wstrTitle);
-
-   DPRINT("wstrApplicationName.Buffer  %p\n", wstrApplicationName.Buffer);
-   DPRINT("wstrCommandLine.Buffer      %p\n", wstrCommandLine.Buffer);
-   DPRINT("wstrCurrentDirectory.Buffer %p\n", wstrCurrentDirectory.Buffer);
-   DPRINT("wstrReserved.Buffer         %p\n", wstrReserved.Buffer);
-   DPRINT("wstrDesktop.Buffer          %p\n", wstrDesktop.Buffer);
-   DPRINT("wstrTitle.Buffer            %p\n", wstrTitle.Buffer);
-
-   DPRINT("sizeof(STARTUPINFOA) %lu\n", sizeof(STARTUPINFOA));
-   DPRINT("sizeof(STARTUPINFOW) %lu\n", sizeof(STARTUPINFOW));
-
-   /* call the Unicode function */
-   bRetVal = CreateProcessW(wstrApplicationName.Buffer,
-                            wstrCommandLine.Buffer,
-                           lpProcessAttributes,
-                           lpThreadAttributes,
-                           bInheritHandles,
-                           dwCreationFlags,
-                           !lpEnvironment || (dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) ? lpEnvironment : wstrEnvVar.Buffer,
-                           wstrCurrentDirectory.Buffer,
-                           &wsiStartupInfo,
-                           lpProcessInformation);
-
-   RtlFreeUnicodeString(&wstrApplicationName);
-   RtlFreeUnicodeString(&wstrCommandLine);
-   RtlFreeUnicodeString(&wstrCurrentDirectory);
-   RtlFreeUnicodeString(&wstrReserved);
-   RtlFreeUnicodeString(&wstrDesktop);
-   RtlFreeUnicodeString(&wstrTitle);
-
-   if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
-   {
-      RtlFreeUnicodeString(&wstrEnvVar);
-   }
-
-   return bRetVal;
+    PCHAR pcScan;
+    ANSI_STRING AnsiEnv;
+    UNICODE_STRING UnicodeEnv;
+    NTSTATUS Status;
+    
+    DPRINT("BasepConvertUnicodeEnvironment\n");
+
+    /* Scan the environment to calculate its Unicode size */
+    AnsiEnv.Buffer = pcScan = (PCHAR)lpEnvironment;
+    while (*pcScan) 
+    {
+        pcScan += strlen(pcScan) + 1;
+    }
+
+    /* Create our ANSI String */
+    if (pcScan == (PCHAR)lpEnvironment)
+    {
+        AnsiEnv.Length = 2 * sizeof(CHAR);
+    }
+    else
+    {
+
+        AnsiEnv.Length = (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;
+    }
+        
+    /* Use the allocated size */
+    UnicodeEnv.MaximumLength = *EnvSize;
+    
+    /* Convert */
+    RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
+    return UnicodeEnv.Buffer;
 }
 
-
-static EXCEPTION_DISPOSITION __cdecl
-_except_handler(EXCEPTION_RECORD *ExceptionRecord,
-               void * EstablisherFrame,
-               CONTEXT *ContextRecord,
-               void * DispatcherContext)
+/*
+ * Converts a Win32 Priority Class to NT
+ */
+ULONG
+STDCALL
+BasepConvertPriorityClass(IN ULONG dwCreationFlags)
 {
-   EXCEPTION_POINTERS ExceptionInfo;
-   EXCEPTION_DISPOSITION ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
-
-   ExceptionInfo.ExceptionRecord = ExceptionRecord;
-   ExceptionInfo.ContextRecord = ContextRecord;
-
-   if (GlobalTopLevelExceptionFilter != NULL)
-   {
-      _SEH_TRY
-      {
-         ExceptionDisposition = GlobalTopLevelExceptionFilter(&ExceptionInfo);
-      }
-      _SEH_HANDLE
-      {
-         ExceptionDisposition = UnhandledExceptionFilter(&ExceptionInfo);
-      }
-      _SEH_END;
-   }
-
-   if (ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER)
-      ExitProcess(ExceptionRecord->ExceptionCode);
-
-   /* translate EXCEPTION_XXX defines into EXCEPTION_DISPOSITION enum values */
-   if (ExceptionDisposition == EXCEPTION_CONTINUE_EXECUTION)
-   {
-      return ExceptionContinueExecution;
-   }
-   else if (ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH)
-   {
-      return ExceptionContinueSearch;
-   }
-
-   return -1; /* unknown return from UnhandledExceptionFilter */
+    ULONG ReturnClass;
+    
+    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)
+    {
+        ReturnClass = PROCESS_PRIORITY_CLASS_NORMAL;
+    }
+    else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
+    {
+        ReturnClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
+    }
+    else if(dwCreationFlags & HIGH_PRIORITY_CLASS)
+    {
+        ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
+    }
+    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 = PROCESS_PRIORITY_CLASS_INVALID;
+    }
+    
+    return ReturnClass;
 }
 
-
-VOID STDCALL
-BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress,
-                DWORD lpParameter)
+/*
+ * Duplicates a standard handle and writes it where requested.
+ */
+VOID
+STDCALL
+BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle,
+                             IN HANDLE StandardHandle,
+                             IN PHANDLE Address)
 {
-   UINT uExitCode = 0;
-
-   DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
-
-   __try1(_except_handler)
-   {
-      uExitCode = (lpStartAddress)((PVOID)lpParameter);
-   } __except1
-
-   ExitProcess(uExitCode);
+    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);
+    }
 }
 
-
-HANDLE STDCALL KlCreateFirstThread(HANDLE ProcessHandle,
-                                  LPSECURITY_ATTRIBUTES lpThreadAttributes,
-                                  PSECTION_IMAGE_INFORMATION Sii,
-                                  LPTHREAD_START_ROUTINE lpStartAddress,
-                                  DWORD dwCreationFlags,
-                                  LPDWORD lpThreadId)
+LPWSTR
+STDCALL
+BasepGetDllPath(LPWSTR FullPath,
+                PVOID Environment)
 {
-   OBJECT_ATTRIBUTES oaThreadAttribs;
-   CLIENT_ID cidClientId;
-   PVOID pTrueStartAddress;
-   NTSTATUS nErrCode;
-   HANDLE hThread;
-
-   /* convert the thread attributes */
-   RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs, lpThreadAttributes);
-
-   /* native image */
-   if(Sii->Subsystem != IMAGE_SUBSYSTEM_NATIVE)
-   {
-      pTrueStartAddress = (PVOID)BaseProcessStart;
-   }
-   /* Win32 image */
-   else
-   {
-      pTrueStartAddress = (PVOID)RtlBaseProcessStartRoutine;
-   }
-
-   DPRINT("RtlRosCreateUserThreadVa\n"
-          "(\n"
-         " ProcessHandle    %p,\n"
-         " ObjectAttributes %p,\n"
-         " CreateSuspended  %d,\n"
-         " StackZeroBits    %d,\n"
-         " StackReserve     %lu,\n"
-         " StackCommit      %lu,\n"
-         " StartAddress     %p,\n"
-         " ThreadHandle     %p,\n"
-         " ClientId         %p,\n"
-         " ParameterCount   %u,\n"
-         " Parameters[0]    %p,\n"
-         " Parameters[1]    %p\n"
-         ")\n",
-         ProcessHandle,
-         &oaThreadAttribs,
-         dwCreationFlags & CREATE_SUSPENDED,
-         0,
-         Sii->StackReserve,
-         Sii->StackCommit,
-         pTrueStartAddress,
-         &hThread,
-         &cidClientId,
-         2,
-          lpStartAddress,
-         PEB_BASE);
-
-   /* create the first thread */
-   nErrCode = RtlRosCreateUserThreadVa(ProcessHandle,
-                                       &oaThreadAttribs,
-                                      dwCreationFlags & CREATE_SUSPENDED,
-                                      0,
-                                      &(Sii->StackReserve),
-                                      &(Sii->StackCommit),
-                                      pTrueStartAddress,
-                                      &hThread,
-                                      &cidClientId,
-                                      2,
-                                       (ULONG_PTR)lpStartAddress,
-                                      (ULONG_PTR)PEB_BASE);
-   /* failure */
-   if(!NT_SUCCESS(nErrCode))
-   {
-      SetLastErrorByStatus(nErrCode);
-      return NULL;
-   }
-
-   DPRINT("StackReserve          %p\n"
-          "StackCommit           %p\n"
-         "ThreadHandle          %p\n"
-         "ClientId.UniqueThread %p\n",
-         Sii->StackReserve,
-         Sii->StackCommit,
-         hThread,
-         cidClientId.UniqueThread);
-
-   /* success */
-   if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
-   return hThread;
+    /* FIXME: Not yet implemented */
+    return NULL;
 }
 
-HANDLE KlMapFile(LPCWSTR lpApplicationName)
+VOID
+STDCALL
+BasepCopyHandles(IN PRTL_USER_PROCESS_PARAMETERS Params,
+                 IN PRTL_USER_PROCESS_PARAMETERS PebParams,
+                 IN BOOL InheritHandles)
 {
-   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);
+    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;
+    }
 }
 
-static NTSTATUS KlInitPeb(HANDLE ProcessHandle,
-                         PRTL_USER_PROCESS_PARAMETERS Ppb,
-                         PVOID * ImageBaseAddress,
-                         ULONG ImageSubSystem)
+NTSTATUS
+STDCALL
+BasepInitializeEnvironment(HANDLE ProcessHandle,
+                           PPEB Peb,
+                           LPWSTR ApplicationPathName,
+                           LPWSTR lpCurrentDirectory,
+                           LPWSTR lpCommandLine,
+                           LPVOID lpEnvironment,
+                           SIZE_T EnvSize,
+                           LPSTARTUPINFOW StartupInfo,
+                           DWORD CreationFlags,
+                           BOOL InheritHandles)
 {
-   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);
-   }
-
-   //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
-   NtWriteVirtualMemory(ProcessHandle,
-                       PpbBase,
-                       Ppb,
-                       Ppb->AllocationSize,
-                       &BytesWritten);
-
-   /* write pointer to environment */
-   Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
-   NtWriteVirtualMemory(ProcessHandle,
-                       (PVOID)(PpbBase + Offset),
-                       &EnvPtr,
-                       sizeof(EnvPtr),
-                       &BytesWritten);
-
-   /* write pointer to process parameter block */
-   Offset = FIELD_OFFSET(PEB, ProcessParameters);
-   NtWriteVirtualMemory(ProcessHandle,
-                       (PVOID)(PEB_BASE + Offset),
-                       &PpbBase,
-                       sizeof(PpbBase),
-                       &BytesWritten);
-
-   /* Write image subsystem */
-   Offset = FIELD_OFFSET(PEB, ImageSubSystem);
-   NtWriteVirtualMemory(ProcessHandle,
-                       (PVOID)(PEB_BASE + Offset),
-                       &ImageSubSystem,
-                       sizeof(ImageSubSystem),
-                       &BytesWritten);
-
-   /* Read image base address. */
-   Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
-   NtReadVirtualMemory(ProcessHandle,
-                      (PVOID)(PEB_BASE + Offset),
-                      ImageBaseAddress,
-                      sizeof(PVOID),
-                      &BytesWritten);
-
-   return(STATUS_SUCCESS);
+    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();
+    LPVOID Environment = lpEnvironment;
+    
+    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)
+    {
+        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);
+
+        /* 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)
+    {
+        DPRINT("Using Standard Handles\n");
+        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 */ 
+            DPRINT("Copying handles from parent\n");
+            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;
 }
 
+/* FUNCTIONS ****************************************************************/
 
-/*************************************************************************
- *               GetFileName
+/*
+ * FUNCTION: The CreateProcess function creates a new process and its
+ * primary thread. The new process executes the specified executable file
+ * ARGUMENTS:
  *
- * Helper for CreateProcessW: retrieve the file name to load from the
- * app name and command line. Store the file name in buffer, and
- * return a possibly modified command line.
+ *     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
  *
- * FIXME: use CurDir to search for the executable file in the new working directory
+ * @implemented
  */
-static LPWSTR FASTCALL
-GetFileName(LPCWSTR CurDir, LPCWSTR AppName, LPWSTR CmdLine, LPWSTR Buffer,
-            unsigned BufLen)
-{
-   WCHAR *Name, *Pos, *Ret = NULL;
-   const WCHAR *p;
-
-   /* if we have an app name, everything is easy */
-
-   if (NULL != AppName)
-   {
-      /* use the unmodified app name as file name */
-      wcsncpy(Buffer, AppName, BufLen );
-      Ret = CmdLine;
-      if (NULL == Ret || L'\0' == CmdLine[0])
-      {
-         /* no command-line, create one */
-         Ret = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(AppName) + 3) * sizeof(WCHAR));
-         if (NULL != Ret)
-         {
-            Ret[0] = L'"';
-            wcscpy(Ret + 1, AppName);
-            wcscat(Ret, L"\"");
-         }
-      }
-      return Ret;
-   }
-
-   if (NULL == CmdLine)
-   {
-      SetLastError(ERROR_INVALID_PARAMETER);
-      return NULL;
-   }
-
-   /* first check for a quoted file name */
-   if (L'"' == CmdLine[0] && NULL != (p = wcschr(CmdLine + 1, L'"')))
-   {
-      int Len = p - CmdLine - 1;
-      /* extract the quoted portion as file name */
-      Name = RtlAllocateHeap(GetProcessHeap(), 0, (Len + 1) * sizeof(WCHAR));
-      if (NULL == Name)
-      {
-         return NULL;
-      }
-      memcpy(Name, CmdLine + 1, Len * sizeof(WCHAR));
-      Name[Len] = L'\0';
-
-      if (SearchPathW(NULL, Name, L".exe", BufLen, Buffer, NULL))
-      {
-         Ret = CmdLine;  /* no change necessary */
-      }
-
-      RtlFreeHeap(GetProcessHeap(), 0, Name);
-      return Ret;
-   }
-
-   /* now try the command-line word by word */
-   Name = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine) + 1) * sizeof(WCHAR));
-   if (NULL == Name)
-   {
-      return NULL;
-   }
-   Pos = Name;
-   p = CmdLine;
-
-   while (L'\0' != *p)
-   {
-      do
-      {
-         *Pos++ = *p++;
-      }
-      while (L'\0' != *p && L' ' != *p);
-      *Pos = 0;
-      if (SearchPathW(NULL, Name, L".exe", BufLen, Buffer, NULL))
-      {
-         Ret = CmdLine;
-         break;
-      }
-   }
-
-   if (NULL == Ret || NULL == wcschr(Name, L' '))
-   {
-      RtlFreeHeap(GetProcessHeap(), 0, Name); /* no change necessary */
-      return Ret;
-   }
-
-   /* now build a new command-line with quotes */
-   Ret = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine) + 3) * sizeof(WCHAR));
-   if (NULL == Ret)
-   {
-      RtlFreeHeap(GetProcessHeap(), 0, Name); /* no change necessary */
-      return NULL;
-   }
-   Ret[0] = L'"';
-   wcscpy(Ret + 1, Name);
-   wcscat(Ret, L"\"");
-   wcscat(Ret, p);
-
-   RtlFreeHeap(GetProcessHeap(), 0, Name);
-   return Ret;
+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);
+    }
+
+    /* 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;
 }
 
-
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL
+STDCALL
 CreateProcessW(LPCWSTR lpApplicationName,
-              LPWSTR lpCommandLine,
-              LPSECURITY_ATTRIBUTES lpProcessAttributes,
-              LPSECURITY_ATTRIBUTES lpThreadAttributes,
-              BOOL 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;
-   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;
-   PWCHAR s, e;
-   ULONG i;
-   UNICODE_STRING CurrentDirectory_U;
-   SECTION_IMAGE_INFORMATION Sii;
-   WCHAR TempCurrentDirectoryW[256];
-   WCHAR TempApplicationNameW[256];
-   WCHAR TempCommandLineNameW[256];
-   UNICODE_STRING RuntimeInfo_U;
-   PVOID ImageBaseAddress;
-   BOOL InputSet, OutputSet, ErrorSet;
-   BOOL InputDup = FALSE, OutputDup = FALSE, ErrorDup = FALSE;
-   WCHAR Name[MAX_PATH];
-   WCHAR *TidyCmdLine;
-   BOOL IsBatchFile = FALSE;
-   PROCESS_PRIORITY_CLASS PriorityClass;
-   OBJECT_ATTRIBUTES ProcObjectAttributes;
-   ULONG ProcAttributes = 0;
-   PVOID ProcSecurity = NULL;
-
-   DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
-         lpApplicationName, lpCommandLine);
-
-   TidyCmdLine = GetFileName(lpCurrentDirectory, lpApplicationName, lpCommandLine, Name,
-                             sizeof(Name) / sizeof(WCHAR));
-   if (NULL == TidyCmdLine)
-   {
-      return FALSE;
-   }
-   DPRINT("TidyCmdLine '%S'\n", TidyCmdLine);
-
-   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 (L'"' == TidyCmdLine[0])
-   {
-      wcscpy(TempApplicationNameW, TidyCmdLine + 1);
-      s = wcschr(TempApplicationNameW, L'"');
-      if (NULL == s)
-      {
-         return FALSE;
-      }
-      *s = L'\0';
-   }
-   else
-   {
-      wcscpy(TempApplicationNameW, TidyCmdLine);
-      s = wcschr(TempApplicationNameW, L' ');
-      if (NULL != s)
-      {
-         *s = L'\0';
-      }
-   }
-   s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
-   if (NULL == s)
-   {
-      s = TempApplicationNameW;
-   }
-   s = wcsrchr(s, L'.');
-   if (NULL == s)
-   {
-      wcscat(TempApplicationNameW, L".exe");
-   }
-
-   if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), 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
-      IsBatchFile = TRUE;
-      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)/sizeof(WCHAR), ImagePathName, &s))
-        {
-           return FALSE;
-        }
-      }
-      else
-      {
-        return FALSE;
-      }
-   }
-
-   /*
-    * Process the application name and command line
-    */
-   RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
-   RtlInitUnicodeString(&CommandLine_U, IsBatchFile ? lpCommandLine : TidyCmdLine);
-
-   DPRINT("ImagePathName_U '%S'\n", ImagePathName_U.Buffer);
-   DPRINT("lpCommandLine '%S'\n", lpCommandLine);
-   DPRINT("TidyCmdLine '%S'\n", TidyCmdLine);
-
-   /* Initialize the current directory string */
-   if (lpCurrentDirectory != NULL)
-   {
-      RtlInitUnicodeString(&CurrentDirectory_U,
-                          lpCurrentDirectory);
-   }
-   else
-   {
-      GetCurrentDirectoryW(256, TempCurrentDirectoryW);
-      RtlInitUnicodeString(&CurrentDirectory_U,
-                          TempCurrentDirectoryW);
-   }
-
-   /*
-    * 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;
-      DPRINT("Inspecting Image Header for image type id\n");
-
-      // Find the application name
-      if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName,
-                                        &ApplicationNameString, NULL, NULL))
-      {
-         return FALSE;
-      }
-      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 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;
-      }
-      if (Iosb.Information != sizeof(DosHeader))
-      {
-         DPRINT("Failed to read dos header from file\n");
-                SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
-         return FALSE;
-      }
-
-      // Check the DOS signature
-      if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
-      {
-         DPRINT("Failed dos magic check\n");
-         SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
-         return FALSE;
-      }
-      NtClose(hFile);
-
-      DPRINT("Launching VDM...\n");
-      return CreateProcessW(L"ntvdm.exe",
-                           (LPWSTR)lpApplicationName,
-                           lpProcessAttributes,
-                           lpThreadAttributes,
-                           bInheritHandles,
-                           dwCreationFlags,
-                           lpEnvironment,
-                           lpCurrentDirectory,
-                           lpStartupInfo,
-                           lpProcessInformation);
-   }
-/////////////////////////////////////////
-
-   /*
-    * Get some information about the executable
-    */
-   Status = ZwQuerySection(hSection,
-                          SectionImageInformation,
-                          &Sii,
-                          sizeof(Sii),
-                          &i);
-   if (! NT_SUCCESS(Status))
-   {
-      NtClose(hSection);
-      DPRINT("Unable to get SectionImageInformation, status 0x%x\n", Status);
-      SetLastErrorByStatus(Status);
-      return FALSE;
-   }
-
-   if (0 != (Sii.Characteristics & IMAGE_FILE_DLL))
-   {
-      NtClose(hSection);
-      DPRINT("Can't execute a DLL\n");
-      SetLastError(ERROR_BAD_EXE_FORMAT);
-      return FALSE;
-   }
-
-   if (IMAGE_SUBSYSTEM_WINDOWS_GUI != Sii.Subsystem
-       && IMAGE_SUBSYSTEM_WINDOWS_CUI != Sii.Subsystem)
-   {
-      NtClose(hSection);
-      DPRINT("Invalid subsystem %d\n", Sii.Subsystem);
-      SetLastError(ERROR_CHILD_NOT_COMPLETE);
-      return FALSE;
-   }
-
-   /*
-    * Initialize the process object attributes
-    */
-
-   if(lpProcessAttributes != NULL)
-   {
-      if(lpProcessAttributes->bInheritHandle)
-      {
-         ProcAttributes |= OBJ_INHERIT;
-      }
-      ProcSecurity = lpProcessAttributes->lpSecurityDescriptor;
-   }
-
-   InitializeObjectAttributes(&ProcObjectAttributes,
-                             NULL,
-                             ProcAttributes,
-                             NULL,
-                             ProcSecurity);
-   /*
-    * initialize the process priority class structure
-    */
-   PriorityClass.Foreground = FALSE;
-
-   if(dwCreationFlags & IDLE_PRIORITY_CLASS)
-   {
-      PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE;
-   }
-   else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
-   {
-      PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
-   }
-   else if(dwCreationFlags & NORMAL_PRIORITY_CLASS)
-   {
-      PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
-   }
-   else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
-   {
-      PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
-   }
-   else if(dwCreationFlags & HIGH_PRIORITY_CLASS)
-   {
-      PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
-   }
-   else if(dwCreationFlags & REALTIME_PRIORITY_CLASS)
-   {
-      /* FIXME - This is a privileged operation. If we don't have the privilege we should
-                rather use PROCESS_PRIORITY_CLASS_HIGH. */
-      PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME;
-   }
-   else
-   {
-      /* FIXME - what to do in this case? */
-      PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
-   }
-
-   /*
-    * Create a new process
-    */
-   Status = NtCreateProcess(&hProcess,
-                           PROCESS_ALL_ACCESS,
-                           &ProcObjectAttributes,
-                           NtCurrentProcess(),
-                           bInheritHandles,
-                           hSection,
-                           NULL,
-                           NULL);
-   /* FIXME - handle failure!!!!! */
-
-   Status = NtSetInformationProcess(hProcess,
-                                    ProcessPriorityClass,
-                                    &PriorityClass,
-                                    sizeof(PROCESS_PRIORITY_CLASS));
-   /* FIXME - handle failure!!!!! */
-
-   if (lpStartupInfo)
-   {
-      if (lpStartupInfo->lpReserved2)
-      {
-         /* 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 = (lpStartupInfo->cbReserved2 + 1) & ~1;
-        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);
-      /* FIXME - handle failure!!!!! */
-   }
-
-   /*
-    * Close the section
-    */
-   NtClose(hSection);
-
-   /*
-    * Get some information about the process
-    */
-   NtQueryInformationProcess(hProcess,
-                            ProcessBasicInformation,
-                            &ProcessBasicInfo,
-                            sizeof(ProcessBasicInfo),
-                            &retlen);
-   DPRINT("ProcessBasicInfo.UniqueProcessId 0x%x\n",
-         ProcessBasicInfo.UniqueProcessId);
-   lpProcessInformation->dwProcessId = (DWORD)ProcessBasicInfo.UniqueProcessId;
-
-   /*
-    * Tell the csrss server we are creating a new process
-    */
-   CsrRequest.Type = CSRSS_CREATE_PROCESS;
-   CsrRequest.Data.CreateProcessRequest.NewProcessId =
-      ProcessBasicInfo.UniqueProcessId;
-   if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
-   {
-      /* Do not create a console for GUI applications */
-      dwCreationFlags &= ~CREATE_NEW_CONSOLE;
-      dwCreationFlags |= DETACHED_PROCESS;
-   }
-   else if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
-   {
-      if (NULL == Ppb->hConsole)
-      {
-         dwCreationFlags |= CREATE_NEW_CONSOLE;
-      }
-   }
-   CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
-   CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher;
-   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");
-   }
-
-   Ppb->hConsole = CsrReply.Data.CreateProcessReply.Console;
-
-   InputSet = FALSE;
-   OutputSet = FALSE;
-   ErrorSet = FALSE;
-
-   /* Set the child console handles */
-
-   /* First check if handles were passed in startup info */
-   if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
-   {
-      if (lpStartupInfo->hStdInput)
-      {
-        Ppb->hStdInput = lpStartupInfo->hStdInput;
-         InputSet = TRUE;
-         InputDup = TRUE;
-      }
-      if (lpStartupInfo->hStdOutput)
-      {
-        Ppb->hStdOutput = lpStartupInfo->hStdOutput;
-         OutputSet = TRUE;
-         OutputDup = TRUE;
-      }
-      if (lpStartupInfo->hStdError)
-      {
-        Ppb->hStdError = lpStartupInfo->hStdError;
-         ErrorSet = TRUE;
-         ErrorDup = TRUE;
-      }
-   }
-
-   /* Check if new console was created, use it for input and output if
-      not overridden */
-   if (0 != (dwCreationFlags & CREATE_NEW_CONSOLE)
-       && NT_SUCCESS(Status) && NT_SUCCESS(CsrReply.Status))
-   {
-      if (! InputSet)
-      {
-         Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
-         InputSet = TRUE;
-         InputDup = FALSE;
-      }
-      if (! OutputSet)
-      {
-         Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
-         OutputSet = TRUE;
-         OutputDup = FALSE;
-      }
-      if (! ErrorSet)
-      {
-         Ppb->hStdError = CsrReply.Data.CreateProcessReply.OutputHandle;
-         ErrorSet = TRUE;
-         ErrorDup = FALSE;
-      }
-   }
-
-   /* Use existing handles otherwise */
-   if (! InputSet)
-   {
-      Ppb->hStdInput = NtCurrentPeb()->ProcessParameters->hStdInput;
-      InputDup = TRUE;
-   }
-   if (! OutputSet)
-   {
-      Ppb->hStdOutput = NtCurrentPeb()->ProcessParameters->hStdOutput;
-      OutputDup = TRUE;
-   }
-   if (! ErrorSet)
-   {
-      Ppb->hStdError = NtCurrentPeb()->ProcessParameters->hStdError;
-      ErrorDup = TRUE;
-   }
-
-   /* Now duplicate handles if required */
-   if (InputDup && Ppb->hStdInput != NULL)
-   {
-      if (IsConsoleHandle(Ppb->hStdInput))
-      {
-         Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
-      }
-      else
-      {
-         DPRINT("Duplicate input handle\n");
-         Status = NtDuplicateObject (NtCurrentProcess(),
-                                     Ppb->hStdInput,
-                                     hProcess,
-                                     &Ppb->hStdInput,
+    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;
+    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;
+    SIZE_T EnvSize = 0;
+    
+    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;
+    }
+
+    /* 
+     * 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;
+        }
+    }
+
+    /* 
+     * 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;
+    }
+
+    /* Start by zeroing out the fields */
+    RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION));
+
+    /* Easy stuff first, convert the process priority class */
+    PriorityClass.Foreground = FALSE;
+    PriorityClass.PriorityClass = BasepConvertPriorityClass(dwCreationFlags);
+
+    /* 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,
-                                     TRUE,
-                                     DUPLICATE_SAME_ACCESS);
-         if(!NT_SUCCESS(Status))
-         {
-           DPRINT("NtDuplicateObject failed, status %x\n", Status);
-         }
-      }
-   }
-
-   if (OutputDup && Ppb->hStdOutput != NULL)
-   {
-      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 (ErrorDup && Ppb->hStdError != NULL)
-   {
-      if (IsConsoleHandle(Ppb->hStdError))
-      {
-         CsrRequest.Type = CSRSS_DUPLICATE_HANDLE;
-         CsrRequest.Data.DuplicateHandleRequest.ProcessId = ProcessBasicInfo.UniqueProcessId;
-         CsrRequest.Data.DuplicateHandleRequest.Handle = CsrReply.Data.CreateProcessReply.OutputHandle;
-         Status = CsrClientCallServer(&CsrRequest,
-                                      &CsrReply,
-                                      sizeof(CSRSS_API_REQUEST),
-                                      sizeof(CSRSS_API_REPLY));
-         if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
-         {
-            Ppb->hStdError = INVALID_HANDLE_VALUE;
-         }
-         else
-         {
-            Ppb->hStdError = CsrReply.Data.DuplicateHandleReply.Handle;
-         }
-      }
-      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, Sii.Subsystem);
-
-   RtlDestroyProcessParameters (Ppb);
-
-   /*
-    * Create the thread for the kernel
-    */
-   DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
-          (PVOID)((ULONG_PTR)ImageBaseAddress + Sii.EntryPoint));
-   hThread =  KlCreateFirstThread(hProcess,
-                                 lpThreadAttributes,
-                                 &Sii,
-                                 (PVOID)((ULONG_PTR)ImageBaseAddress + Sii.EntryPoint),
-                                 dwCreationFlags,
-                                 &lpProcessInformation->dwThreadId);
-   if (hThread == NULL)
-   {
-      return FALSE;
-   }
-
-   lpProcessInformation->hProcess = hProcess;
-   lpProcessInformation->hThread = hThread;
-
-   return TRUE;
+                                     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;
+        }
+                
+        /* 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 0
+            /* 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);    
+            } 
+#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))
+            {
+                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, ApplicationName.Buffer);
+            ApplicationName.Buffer = 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;
+    }
+
+    /* 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 */
+
+    /* 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;
+    }
+
+    /* 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));
+    }
+
+    /* 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;
+        }
+    }
+    
+    /* 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;
+        }
+        
+        /* 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);
+    
+    /* Convert the environment */
+    if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+    {
+        lpEnvironment = BasepConvertUnicodeEnvironment(&EnvSize, lpEnvironment);
+        if (!lpEnvironment) return FALSE;
+    }
+
+    /* Create Process Environment */
+    RemotePeb = ProcessBasicInfo.PebBaseAddress;
+    Status = BasepInitializeEnvironment(hProcess,
+                                        RemotePeb,
+                                        (LPWSTR)lpApplicationName,
+                                        CurrentDirectory,
+                                        (QuotesNeeded || CmdLineIsAppName) ?
+                                        QuotedCmdLine : lpCommandLine,
+                                        lpEnvironment,
+                                        EnvSize,
+                                        lpStartupInfo,
+                                        dwCreationFlags,
+                                        bInheritHandles);
+
+    /* Cleanup Environment */    
+    if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+    {
+        RtlDestroyEnvironment(lpEnvironment);
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Could not initialize Process Environment\n");
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+    
+    /* Close the section */
+    NtClose(hSection);
+    hSection = NULL;
+
+    /* 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;
+        }
+        
+        /* 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;
+    }
+
+    
+    /* Notify CSRSS */
+    Status = BasepNotifyCsrOfCreation(dwCreationFlags,
+                                      (HANDLE)ProcessBasicInfo.UniqueProcessId,
+                                      bInheritHandles);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("CSR Notification Failed");
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+    
+    if (!(dwCreationFlags & CREATE_SUSPENDED))
+    {
+        NtResumeThread(hThread, &Dummy);
+    }
+    
+    /* 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 Success */
+    return TRUE;
 }
 
 /* EOF */