Fixed some bugs in CreateProcessA which was introduced by r16730.
[reactos.git] / reactos / lib / kernel32 / process / create.c
index 8e6779a..d1b5047 100644 (file)
@@ -1,12 +1,10 @@
-/* $Id: create.c,v 1.73 2003/12/18 09:51:08 gvg Exp $
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/kernel32/process/create.c
  * PURPOSE:         Process functions
- * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
- * UPDATE HISTORY:
- *                  Created 01/11/98
+ * PROGRAMMER:      Alex Ionescu (alex@relsoft.net)
+ *                  Ariadne ( ariadne@xs4all.nl)
  */
 
 /* INCLUDES ****************************************************************/
 #include <k32.h>
 
 #define NDEBUG
-#include <kernel32/kernel32.h>
+#include "../include/debug.h"
 
-/* FUNCTIONS ****************************************************************/
+#define CMD_STRING L"cmd /c "
 
-extern __declspec(noreturn) 
-VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag);
+extern __declspec(noreturn)
+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;
 
-VOID STDCALL RtlRosR32AttribsToNativeAttribs
-(
- OUT OBJECT_ATTRIBUTES * NativeAttribs,
- IN SECURITY_ATTRIBUTES * Ros32Attribs OPTIONAL
-)
-{
- NativeAttribs->Length = sizeof(*NativeAttribs);
- NativeAttribs->ObjectName = NULL;
NativeAttribs->RootDirectory = NULL;
- NativeAttribs->Attributes = 0;
NativeAttribs->SecurityQualityOfService = NULL;
+    if (GlobalTopLevelExceptionFilter != NULL)
+    {
+        _SEH_TRY
+        {
+            ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo);
+        }
+        _SEH_HANDLE
+        {
           ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
+        }
       _SEH_END;
+    }
 
- if(Ros32Attribs != NULL && Ros32Attribs->nLength >= sizeof(*Ros32Attribs))
- {
-  NativeAttribs->SecurityDescriptor = Ros32Attribs->lpSecurityDescriptor;
-  
-  if(Ros32Attribs->bInheritHandle)
-   NativeAttribs->Attributes |= OBJ_INHERIT;
- }
- else
-  NativeAttribs->SecurityDescriptor = NULL;
+    return ExceptionDisposition;
 }
 
-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
-)
+VOID
+STDCALL
+BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress)
 {
if(!NativeAttribs) return;
   UINT uExitCode = 0;
 
RtlRosR32AttribsToNativeAttribs(NativeAttribs, Ros32Attribs);
   DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
 
- if(Ros32Name != NULL && NativeName != NULL)
- {
-  RtlInitUnicodeString(NativeName, Ros32Name);
+    _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;
 
-  NativeAttribs->ObjectName = NativeName;
-  NativeAttribs->RootDirectory = Ros32NameRoot;
-  NativeAttribs->Attributes |= OBJ_CASE_INSENSITIVE;
- }
+    /* Exit the Process with our error */
+    ExitProcess(uExitCode);
 }
 
-
 /*
- * @implemented
+ * Tells CSR that a new process was created
  */
-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
-)
+NTSTATUS
+STDCALL
+BasepNotifyCsrOfCreation(ULONG dwCreationFlags,
+                         IN HANDLE ProcessId)
+{
+    ULONG Request = CREATE_PROCESS;
+    CSR_API_MESSAGE CsrRequest;
+    NTSTATUS Status;
+    
+    DPRINT1("BasepNotifyCsrOfCreation: Process: %lx, Flags %lx\n", 
+            ProcessId, dwCreationFlags);
+         
+    /* Fill out the request */
+    CsrRequest.Data.CreateProcessRequest.NewProcessId = ProcessId;
+    CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
+    
+    /* Call CSR */
+    Status = CsrClientCallServer(&CsrRequest,
+                                 NULL,
+                                 MAKE_CSR_API(Request, CSR_NATIVE),
+                                 sizeof(CSR_API_MESSAGE));
+    if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
+    {
+        DPRINT1("Failed to tell csrss about new process\n");
+        return CsrRequest.Status;
+    }
+    
+    /* REturn Success */
+    return STATUS_SUCCESS;
+}
+
 /*
- * 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
+ * Creates the first Thread in a Proces
  */
+HANDLE
+STDCALL
+BasepCreateFirstThread(HANDLE ProcessHandle,
+                       LPSECURITY_ATTRIBUTES lpThreadAttributes,
+                       PSECTION_IMAGE_INFORMATION SectionImageInfo,
+                       PCLIENT_ID ClientId)
 {
- PWCHAR pwcEnv = NULL;
- UNICODE_STRING wstrApplicationName;
- UNICODE_STRING wstrCurrentDirectory;
- UNICODE_STRING wstrCommandLine;
- UNICODE_STRING wstrReserved;
- UNICODE_STRING wstrDesktop;
- UNICODE_STRING wstrTitle;
- ANSI_STRING strApplicationName;
- ANSI_STRING strCurrentDirectory;
- ANSI_STRING strCommandLine;
- ANSI_STRING strReserved;
- ANSI_STRING strDesktop;
- ANSI_STRING strTitle;
- BOOL bRetVal;
- STARTUPINFOW wsiStartupInfo;
-
- NTSTATUS STDCALL (*pTrue)
- (
-  UNICODE_STRING *,
-  ANSI_STRING *,
-  BOOLEAN
- );
-
- ULONG STDCALL (*pRtlMbStringToUnicodeSize)(ANSI_STRING *);
-
- DPRINT("CreateProcessA(%s)\n", lpApplicationName);
-
- DPRINT
- (
-   "dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
-   "lpStartupInfo %x, lpProcessInformation %x\n",
-  dwCreationFlags, 
-  lpEnvironment,
-  lpCurrentDirectory,
-  lpStartupInfo,
-  lpProcessInformation
- );
-
- /* invalid parameter */
- if(lpStartupInfo == NULL)
- {
-  SetLastError(ERROR_INVALID_PARAMETER);
-  return FALSE;
- }
-
- /* multibyte strings are ANSI */
- if(bIsFileApiAnsi)
- {
-  pTrue = RtlAnsiStringToUnicodeString;
-  pRtlMbStringToUnicodeSize = RtlAnsiStringToUnicodeSize;
- }
- /* multibyte strings are OEM */
- else
- {
-  pTrue = RtlOemStringToUnicodeString;
-  pRtlMbStringToUnicodeSize = RtlOemStringToUnicodeSize;
- }
-
- /* convert the environment */
- if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
- {
-  PCHAR pcScan;
-  SIZE_T nEnvLen = 0;
-  UNICODE_STRING wstrEnvVar;
-  ANSI_STRING strEnvVar;
-
-  /* scan the environment to calculate its Unicode size */
-  for(pcScan = lpEnvironment; *pcScan; pcScan += strEnvVar.Length + sizeof(char))
-  {
-   /* add the size of the current variable */
-   RtlInitAnsiString(&strEnvVar, pcScan);
-   nEnvLen += pRtlMbStringToUnicodeSize(&strEnvVar) + sizeof(WCHAR);
-  }
-
-  /* add the size of the final NUL character */
-  nEnvLen += sizeof(WCHAR);
-
-  /* environment too large */
-  if(nEnvLen > ~((USHORT)0))
-  {
-   SetLastError(ERROR_OUTOFMEMORY);
-   return FALSE;
-  }
-
-  /* allocate the Unicode environment */
-  pwcEnv = (PWCHAR)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, nEnvLen);
-
-  /* failure */
-  if(pwcEnv == NULL)
-  {
-   SetLastError(ERROR_OUTOFMEMORY);
-   return FALSE;
-  }
-
-  wstrEnvVar.Buffer = pwcEnv;
-  wstrEnvVar.Length = 0;
-  wstrEnvVar.MaximumLength = nEnvLen;
-
-  /* scan the environment to convert it */
-  for(pcScan = lpEnvironment; *pcScan; pcScan += strEnvVar.Length + sizeof(char))
-  {
-   /* convert the current variable */
-   RtlInitAnsiString(&strEnvVar, pcScan);
-   K32MbStrToWcStr(pTrue, &wstrEnvVar, &strEnvVar, FALSE);
-
-   /* advance the buffer to the next variable */
-   wstrEnvVar.Buffer += (wstrEnvVar.Length / sizeof(WCHAR) + 1);
-   wstrEnvVar.MaximumLength -= (wstrEnvVar.Length + sizeof(WCHAR));
-   wstrEnvVar.Length = 0;
-  }
-
-  /* final NUL character */
-  wstrEnvVar.Buffer[0] = 0;    
- }
-
- /* 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,
-  dwCreationFlags & CREATE_UNICODE_ENVIRONMENT ? lpEnvironment : pwcEnv,
-  wstrCurrentDirectory.Buffer,
-  &wsiStartupInfo,
-  lpProcessInformation
- );
-
- RtlFreeUnicodeString(&wstrApplicationName);
- RtlFreeUnicodeString(&wstrCommandLine);
- RtlFreeUnicodeString(&wstrCurrentDirectory);
- RtlFreeUnicodeString(&wstrReserved);
- RtlFreeUnicodeString(&wstrDesktop);
- RtlFreeUnicodeString(&wstrTitle);
-
- RtlFreeHeap(GetProcessHeap(), 0, pwcEnv);
-
- return bRetVal;
+    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;
 }
 
-static int _except_recursion_trap = 0;
-
-struct _CONTEXT;
-struct __EXCEPTION_RECORD;
-
-static
-EXCEPTION_DISPOSITION
-__cdecl
-_except_handler(
-    struct _EXCEPTION_RECORD *ExceptionRecord,
-    void * EstablisherFrame,
-    struct _CONTEXT *ContextRecord,
-    void * DispatcherContext )
+/*
+ * Converts ANSI to Unicode Environment
+ */
+PVOID
+STDCALL
+BasepConvertUnicodeEnvironment(IN PVOID lpEnvironment)
 {
- DPRINT1("Process terminated abnormally due to unhandled exception\n");
- DPRINT1("Address: %x\n", ExceptionRecord->ExceptionAddress);
-
-#ifdef _X86_
-  {
-    PULONG Frame;
-    DPRINT1("Frames:\n");
-    Frame = (PULONG)((CONTEXT *)ContextRecord)->Ebp;
-    while (Frame != NULL && Frame != (PULONG)0xdeadbeef)
-       {
-         DPRINT1("%x\n", (PVOID)Frame[1]);
-         Frame = (PULONG)Frame[0];
-       }
-  }
-#endif
-
- if (3 < ++_except_recursion_trap)
+    PCHAR pcScan;
+    SIZE_T EnvSize = 0;
+    ANSI_STRING AnsiEnv;
+    UNICODE_STRING UnicodeEnv;
+    NTSTATUS Status;
+    
+    DPRINT("BasepConvertUnicodeEnvironment\n");
+
+    /* Scan the environment to calculate its Unicode size */
+    AnsiEnv.Buffer = pcScan = lpEnvironment;
+    while (*pcScan) while (*pcScan++);
+
+    /* Create our ANSI String */
+    AnsiEnv.Length = (ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + 1;
+    AnsiEnv.MaximumLength = AnsiEnv.Length + 1;
+    
+    /* Allocate memory for the Unicode Environment */
+    UnicodeEnv.Buffer = NULL;
+    EnvSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
+    Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+                                     (PVOID)&UnicodeEnv.Buffer,
+                                     0,
+                                     &EnvSize,
+                                     MEM_COMMIT,
+                                     PAGE_READWRITE);
+    /* Failure */
+    if (!NT_SUCCESS(Status))
     {
-      DPRINT1("_except_handler(...) appears to be recursing.\n");
-      DPRINT1("Process HALTED.\n");
-      for (;;)
-       {
-       }
+        SetLastError(Status);
+        return NULL;
     }
+        
+    /* Use the allocated size */
+    UnicodeEnv.MaximumLength = EnvSize;
+    
+    /* Convert */
+    RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
+    return UnicodeEnv.Buffer;
+}
 
-  if (/* FIXME: */ TRUE) /* Not a service */
+/*
+ * Converts a Win32 Priority Class to NT
+ */
+ULONG
+STDCALL
+BasepConvertPriorityClass(IN ULONG dwCreationFlags)
+{
+    ULONG ReturnClass;
+    
+    if(dwCreationFlags & IDLE_PRIORITY_CLASS)
+    {    
+        ReturnClass = PROCESS_PRIORITY_CLASS_IDLE;
+    }
+    else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
     {
-      DPRINT("  calling ExitProcess(0) no, lets try ExitThread . . .\n");
-      /* ExitProcess(0); */
-      ExitThread(0);
+        ReturnClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
     }
-  else
+    else if(dwCreationFlags & NORMAL_PRIORITY_CLASS)
     {
-    DPRINT("  calling ExitThread(0) . . .\n");
-    ExitThread(0);
+        ReturnClass = PROCESS_PRIORITY_CLASS_NORMAL;
     }
-
-  DPRINT1("  We should not get to here !!!\n");
-  /* We should not get to here */
-  return ExceptionContinueSearch;
+    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 = 0 /* FIXME */;
+    }
+    
+    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
-       {
-       }
-
-    DPRINT("BaseProcessStart(..) - cleaned up exception frame.\n");
-
-       ExitThread(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);
+    /* 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
-)
+NTSTATUS
+STDCALL
+BasepInitializeEnvironment(HANDLE ProcessHandle,
+                           PPEB Peb,
+                           LPWSTR ApplicationPathName,
+                           LPWSTR lpCurrentDirectory,
+                           LPWSTR lpCommandLine,
+                           LPVOID Environment,
+                           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);
+    WCHAR FullPath[MAX_PATH];
+    LPWSTR Remaining;
+    LPWSTR DllPathString;
+    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
+    PRTL_USER_PROCESS_PARAMETERS RemoteParameters = NULL;
+    UNICODE_STRING DllPath, ImageName, CommandLine, CurrentDirectory;
+    UINT RetVal;
+    NTSTATUS Status;
+    PWCHAR ScanChar;
+    ULONG EnviroSize;
+    ULONG Size;
+    UNICODE_STRING Desktop, Shell, Runtime, Title;
+    PPEB OurPeb = NtCurrentPeb();
+    
+    DPRINT("BasepInitializeEnvironment\n");
+    
+    /* Get the full path name */
+    RetVal = GetFullPathNameW(ApplicationPathName,
+                              MAX_PATH,
+                              FullPath,
+                              &Remaining);
+    DPRINT("ApplicationPathName: %S, FullPath: %S\n", ApplicationPathName, 
+            FullPath);
+                                  
+    /* Get the DLL Path */
+    DllPathString = BasepGetDllPath(FullPath, Environment);
+    
+    /* Initialize Strings */
+    RtlInitUnicodeString(&DllPath, DllPathString);
+    RtlInitUnicodeString(&ImageName, FullPath);
+    RtlInitUnicodeString(&CommandLine, lpCommandLine);
+    RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory);
+   
+    /* Initialize more Strings from the Startup Info */
+    if (StartupInfo->lpDesktop)
+    {
+        RtlInitUnicodeString(&Desktop, StartupInfo->lpDesktop);
+    }
+    else
+    {
+        RtlInitUnicodeString(&Desktop, L"");
+    }
+    if (StartupInfo->lpReserved)
+    {
+        RtlInitUnicodeString(&Shell, StartupInfo->lpReserved);
+    }
+    else
+    {
+        RtlInitUnicodeString(&Shell, L"");
+    }
+    if (StartupInfo->lpTitle)
+    {
+        RtlInitUnicodeString(&Title, StartupInfo->lpTitle);
+    }
+    else
+    {
+        RtlInitUnicodeString(&Title, L"");
+    }
+    
+    /* This one is special because the length can differ */
+    Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2;
+    Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2;
+    
+    /* Create the Parameter Block */
+    DPRINT("Creating Process Parameters: %wZ %wZ %wZ %wZ %wZ %wZ %wZ\n",
+            &ImageName, &DllPath, &CommandLine, &Desktop, &Title, &Shell,
+            &Runtime);
+    Status = RtlCreateProcessParameters(&ProcessParameters,
+                                        &ImageName,
+                                        &DllPath,
+                                        lpCurrentDirectory ? 
+                                        &CurrentDirectory : NULL,
+                                        &CommandLine,
+                                        Environment,
+                                        &Title,
+                                        &Desktop,
+                                        &Shell,
+                                        &Runtime);
+                                        
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to create process parameters!\n");
+        return Status;
+    }
+    
+    /* Check if we got an environment. If not, use ours */
+    if (Environment)
+    {
+        /* Save pointer and start lookup */
+        Environment = ScanChar = ProcessParameters->Environment;
+    }
+    else
+    {
+        /* Save pointer and start lookup */
+        Environment = ScanChar = OurPeb->ProcessParameters->Environment;
+    }
+    
+    /* Find the environment size */
+    if (ScanChar)
+    {
+        while (*ScanChar) while (*ScanChar++);
+        
+        /* Calculate the size of the block */
+        EnviroSize = (ULONG)((ULONG_PTR)ScanChar - (ULONG_PTR)Environment);
+        DPRINT("EnvironmentSize %ld\n", EnviroSize);
+
+        /* Allocate and Initialize new Environment Block */
+        Size = EnviroSize;
+        ProcessParameters->Environment = NULL;
+        Status = ZwAllocateVirtualMemory(ProcessHandle,
+                                         (PVOID*)&ProcessParameters->Environment,
+                                         0,
+                                         &Size,
+                                         MEM_COMMIT,
+                                         PAGE_READWRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to allocate Environment Block\n");
+            return(Status);
+        }
+        
+        /* Write the Environment Block */
+        ZwWriteVirtualMemory(ProcessHandle,
+                             ProcessParameters->Environment,
+                             Environment,
+                             EnviroSize,
+                             NULL);
+    }
+    
+    /* Write new parameters */
+    ProcessParameters->StartingX = StartupInfo->dwX;
+    ProcessParameters->StartingY = StartupInfo->dwY;
+    ProcessParameters->CountX = StartupInfo->dwXSize;
+    ProcessParameters->CountY = StartupInfo->dwYSize;
+    ProcessParameters->CountCharsX = StartupInfo->dwXCountChars;
+    ProcessParameters->CountCharsY = StartupInfo->dwYCountChars;
+    ProcessParameters->FillAttribute = StartupInfo->dwFillAttribute;
+    ProcessParameters->WindowFlags = StartupInfo->dwFlags;
+    ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow;
+        
+    /* Write the handles only if we have to */
+    if (StartupInfo->dwFlags & STARTF_USESTDHANDLES)
+    {
+        ProcessParameters->StandardInput = StartupInfo->hStdInput;
+        ProcessParameters->StandardOutput = StartupInfo->hStdOutput;
+        ProcessParameters->StandardError = StartupInfo->hStdError;
+    }
+        
+    /* Use Special Flags for ConDllInitialize in Kernel32 */
+    if (CreationFlags & DETACHED_PROCESS)
+    {
+        ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS;
+    }
+    else if (CreationFlags & CREATE_NO_WINDOW)
+    {
+        ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW;
+    }
+    else if (CreationFlags & CREATE_NEW_CONSOLE)
+    {
+        ProcessParameters->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE;
+    }
+    else
+    {
+        /* Inherit our Console Handle */
+        ProcessParameters->ConsoleHandle = OurPeb->ProcessParameters->ConsoleHandle;
+        
+        /* Is the shell trampling on our Handles? */
+        if (!(StartupInfo->dwFlags & 
+              (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
+        {
+            /* Use handles from PEB, if inheriting or they are console */ 
+            BasepCopyHandles(ProcessParameters,
+                             OurPeb->ProcessParameters,
+                             InheritHandles);
+       }
+    }
+    
+    /* Also set the Console Flag */
+    if (CreationFlags & CREATE_NEW_PROCESS_GROUP)
+    {
+        ProcessParameters->ConsoleFlags = 1;
+    }
+    
+    /* Allocate memory for the parameter block */
+    Size = ProcessParameters->Length;
+    Status = NtAllocateVirtualMemory(ProcessHandle,
+                                     (PVOID*)&RemoteParameters,
+                                     0,
+                                     &Size,
+                                     MEM_COMMIT,
+                                     PAGE_READWRITE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to allocate Parameters Block\n");
+        return(Status);
+    }
+    
+    /* Set the allocated size */
+    ProcessParameters->MaximumLength = Size;
+    
+    /* Handle some Parameter Flags */
+    ProcessParameters->ConsoleFlags = (CreationFlags & CREATE_NEW_PROCESS_GROUP);
+    ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ?
+                                 PPF_PROFILE_USER : 0;
+    ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ? 
+                                 PPF_PROFILE_KERNEL : 0;    
+    ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ?
+                                 PPF_PROFILE_SERVER : 0;
+    ProcessParameters->Flags |= (NtCurrentPeb()->ProcessParameters->Flags &
+                                 PPF_DISABLE_HEAP_CHECKS);
+    
+    /* Write the Parameter Block */
+    Status = NtWriteVirtualMemory(ProcessHandle,
+                                  RemoteParameters,
+                                  ProcessParameters,
+                                  ProcessParameters->Length,
+                                  NULL);
+                                  
+    /* Write the PEB Pointer */
+    Status = NtWriteVirtualMemory(ProcessHandle,
+                                  &Peb->ProcessParameters,
+                                  &RemoteParameters,
+                                  sizeof(PVOID),
+                                  NULL);
+                                  
+    /* Cleanup */
+    RtlFreeHeap(GetProcessHeap(), 0, DllPath.Buffer);
+    RtlDestroyProcessParameters(ProcessParameters);
+
+    DPRINT("Completed\n");
+    return STATUS_SUCCESS;
+}
 
-   /* write pointer to process parameter block */
-   Offset = FIELD_OFFSET(PEB, ProcessParameters);
-   NtWriteVirtualMemory(ProcessHandle,
-                       (PVOID)(PEB_BASE + Offset),
-                       &PpbBase,
-                       sizeof(PpbBase),
-                       &BytesWritten);
+/* FUNCTIONS ****************************************************************/
 
-   /* Read image base address. */
-   Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
-   NtReadVirtualMemory(ProcessHandle,
-                      (PVOID)(PEB_BASE + Offset),
-                      ImageBaseAddress,
-                      sizeof(PVOID),
-                      &BytesWritten);
+/*
+ * FUNCTION: The CreateProcess function creates a new process and its
+ * primary thread. The new process executes the specified executable file
+ * ARGUMENTS:
+ *
+ *     lpApplicationName = Pointer to name of executable module
+ *     lpCommandLine = Pointer to command line string
+ *     lpProcessAttributes = Process security attributes
+ *     lpThreadAttributes = Thread security attributes
+ *     bInheritHandles = Handle inheritance flag
+ *     dwCreationFlags = Creation flags
+ *     lpEnvironment = Pointer to new environment block
+ *     lpCurrentDirectory = Pointer to current directory name
+ *     lpStartupInfo = Pointer to startup info
+ *     lpProcessInformation = Pointer to process information
+ *
+ * @implemented
+ */
+BOOL
+STDCALL
+CreateProcessA(LPCSTR lpApplicationName,
+               LPSTR lpCommandLine,
+               LPSECURITY_ATTRIBUTES lpProcessAttributes,
+               LPSECURITY_ATTRIBUTES lpThreadAttributes,
+               BOOL bInheritHandles,
+               DWORD dwCreationFlags,
+               LPVOID lpEnvironment,
+               LPCSTR lpCurrentDirectory,
+               LPSTARTUPINFOA lpStartupInfo,
+               LPPROCESS_INFORMATION lpProcessInformation)
+{    
+    PUNICODE_STRING CommandLine = NULL;
+    UNICODE_STRING DummyString;
+    UNICODE_STRING LiveCommandLine;
+    UNICODE_STRING ApplicationName;
+    UNICODE_STRING CurrentDirectory;
+    BOOL bRetVal;
+    STARTUPINFOW StartupInfo;
+
+    DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
+            "lpStartupInfo %x, lpProcessInformation %x\n",
+            dwCreationFlags, lpEnvironment, lpCurrentDirectory,
+            lpStartupInfo, lpProcessInformation);
+    
+    /* Copy Startup Info */
+    RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo));
+    
+    /* Initialize all strings to nothing */
+    LiveCommandLine.Buffer = NULL;
+    DummyString.Buffer = NULL;
+    ApplicationName.Buffer = NULL;
+    CurrentDirectory.Buffer = NULL;
+    StartupInfo.lpDesktop = NULL;
+    StartupInfo.lpReserved = NULL;
+    StartupInfo.lpTitle = NULL;
+    
+    /* Convert the Command line */
+    if (lpCommandLine)
+    {
+        /* If it's too long, then we'll have a problem */
+        if ((strlen(lpCommandLine) + 1) * sizeof(WCHAR) <
+            NtCurrentTeb()->StaticUnicodeString.MaximumLength)
+        {
+            /* Cache it in the TEB */
+            CommandLine = Basep8BitStringToCachedUnicodeString(lpCommandLine);
+        }
+        else
+        {
+            /* Use a dynamic version */
+            Basep8BitStringToHeapUnicodeString(&LiveCommandLine, 
+                                               lpCommandLine);
+        }
+    }
+    else
+    {
+        /* The logic below will use CommandLine, so we must make it valid */
+        CommandLine = &DummyString;
+    }
+    
+    /* Convert the Name and Directory */
+    if (lpApplicationName)
+    {
+        Basep8BitStringToHeapUnicodeString(&ApplicationName, 
+                                           lpApplicationName);
+    }
+    if (lpCurrentDirectory)
+    {
+        Basep8BitStringToHeapUnicodeString(&CurrentDirectory, 
+                                           lpCurrentDirectory);
+    }
+    
+    /* Now convert Startup Strings */
+    if (lpStartupInfo->lpReserved)
+    {
+        BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpReserved,
+                                           &StartupInfo.lpReserved);
+    }
+    if (lpStartupInfo->lpDesktop)
+    {
+        BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpDesktop,
+                                           &StartupInfo.lpDesktop);
+    }
+    if (lpStartupInfo->lpTitle)
+    {
+        BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpTitle,
+                                           &StartupInfo.lpTitle);
+    }
 
-   return(STATUS_SUCCESS);
+    /* Call the Unicode function */
+    bRetVal = CreateProcessW(ApplicationName.Buffer,
+                             LiveCommandLine.Buffer ? 
+                             LiveCommandLine.Buffer : CommandLine->Buffer,
+                             lpProcessAttributes,
+                             lpThreadAttributes,
+                             bInheritHandles,
+                             dwCreationFlags,
+                             lpEnvironment,
+                             CurrentDirectory.Buffer,
+                             &StartupInfo,
+                             lpProcessInformation);
+
+    /* Clean up */
+    RtlFreeUnicodeString(&ApplicationName);
+    RtlFreeUnicodeString(&LiveCommandLine);
+    RtlFreeUnicodeString(&CurrentDirectory);
+    RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpDesktop);
+    RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpReserved);
+    RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpTitle);
+
+    /* Return what Unicode did */
+    return bRetVal;
 }
 
-
 /*
  * @implemented
  */
-WINBOOL STDCALL 
-CreateProcessW
-(
- LPCWSTR lpApplicationName,
- LPWSTR lpCommandLine,
- LPSECURITY_ATTRIBUTES lpProcessAttributes,
- LPSECURITY_ATTRIBUTES lpThreadAttributes,
- WINBOOL bInheritHandles,
- DWORD dwCreationFlags,
- LPVOID lpEnvironment,
- LPCWSTR lpCurrentDirectory,
- LPSTARTUPINFOW lpStartupInfo,
- LPPROCESS_INFORMATION lpProcessInformation
-)
+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)
 {
-   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;
-   CHAR ImageFileName[8];
-   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, OutputDup, ErrorDup;
-
-   DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
-          lpApplicationName, lpCommandLine);
-
-   if (lpApplicationName != NULL && lpApplicationName[0] != 0)
-   {
-      wcscpy (TempApplicationNameW, lpApplicationName);
-      i = wcslen(TempApplicationNameW);
-      if (TempApplicationNameW[i - 1] == L'.')
-      {
-         TempApplicationNameW[i - 1] = 0;
-      }
-      else
-      {
-         s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
-         if (s == NULL)
-         {
-            s = TempApplicationNameW;
-         }
-        else
-        {
-           s++;
-        }
-         e = wcsrchr(s, L'.');
-         if (e == NULL)
-         {
-            wcscat(s, L".exe");
-            e = wcsrchr(s, L'.');
-         }
-      }
-   }
-   else if (lpCommandLine != NULL && lpCommandLine[0] != 0)
-   {
-      if (lpCommandLine[0] == L'"')
-      {
-         wcscpy(TempApplicationNameW, lpCommandLine + 1);
-         s = wcschr(TempApplicationNameW, L'"');
-         if (s == NULL)
-         {
-           return FALSE;
-         }
-         *s = 0;
-      }
-      else
-      {
-         wcscpy(TempApplicationNameW, lpCommandLine);
-         s = wcschr(TempApplicationNameW, L' ');
-         if (s != NULL)
-         {
-           *s = 0;
-         }
-      }
-      s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
-      if (s == NULL)
-      {
-         s = TempApplicationNameW;
-      }
-      s = wcsrchr(s, L'.');
-      if (s == NULL)
-        wcscat(TempApplicationNameW, L".exe");
-   }
-   else
-   {
-      return FALSE;
-   }
-
-   DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
-          lpApplicationName, lpCommandLine);
-
-   if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
-   {
-     return FALSE;
-   }
+    NTSTATUS Status;
+    PROCESS_PRIORITY_CLASS PriorityClass;
+    BOOLEAN FoundQuotes = FALSE;
+    BOOLEAN QuotesNeeded = FALSE;
+    BOOLEAN CmdLineIsAppName = FALSE;
+    UNICODE_STRING ApplicationName;
+    OBJECT_ATTRIBUTES LocalObjectAttributes;
+    POBJECT_ATTRIBUTES ObjectAttributes;
+    HANDLE hSection, hProcess, hThread;
+    SECTION_IMAGE_INFORMATION SectionImageInfo;
+    LPWSTR CurrentDirectory = NULL;
+    LPWSTR CurrentDirectoryPart;
+    PROCESS_BASIC_INFORMATION ProcessBasicInfo;
+    STARTUPINFOW StartupInfo;
+    ULONG Dummy;
+    LPWSTR BatchCommandLine;
+    ULONG CmdLineLength;
+    UNICODE_STRING CommandLineString;
+    LPWSTR TempBuffer;
+    PWCHAR Extension;
+    LPWSTR QuotedCmdLine = NULL;
+    LPWSTR ScanString;
+    LPWSTR NullBuffer = NULL;
+    LPWSTR NameBuffer = NULL;
+    WCHAR SaveChar = 0;
+    ULONG RetVal;
+    UINT Error = 0;
+    BOOLEAN SearchDone = FALSE;
+    CLIENT_ID ClientId;
+    PPEB OurPeb = NtCurrentPeb();
+    PPEB RemotePeb;
+    
+    DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
+           " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
+           lpApplicationName, lpCommandLine, lpEnvironment, lpCurrentDirectory,
+           dwCreationFlags);
+    
+    /* Flags we don't handle yet */
+    if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)
+    {
+        DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
+    }
+    if (dwCreationFlags & CREATE_SHARED_WOW_VDM)
+    {
+        DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
+    }
+    if (dwCreationFlags & CREATE_FORCEDOS)
+    {
+        DPRINT1("CREATE_FORCEDOS not handled\n");
+    }
+    
+    /* Fail on this flag, it's only valid with the WithLogonW function */
+    if (dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
+    {
+        DPRINT1("Invalid flag used\n");
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    
+    /* This combination is illegal (see MSDN) */
+    if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
+        (DETACHED_PROCESS | CREATE_NEW_CONSOLE))
+    {
+        DPRINT1("Invalid flag combo used\n");
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    
+    /* Another illegal combo */
+    if ((dwCreationFlags & (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) ==
+        (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM))
+    {
+        DPRINT1("Invalid flag combo used\n");
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
 
-   e = wcsrchr(s, L'.');
-   if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd")))
-   {
-       // the command is a batch file
-       if (lpApplicationName != NULL && lpApplicationName[0])
-       {
-         // FIXME: use COMSPEC for the command interpreter
-         wcscpy(TempCommandLineNameW, L"cmd /c ");
-         wcscat(TempCommandLineNameW, lpApplicationName);
-         lpCommandLine = TempCommandLineNameW;
-         wcscpy(TempApplicationNameW, L"cmd.exe");
-          if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
-         {
-            return FALSE;
-         }
-       }
-       else
-       {
-         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;
+        }
+    }
 
-   /*
-    * Store the image file name for the process
-    */
-   e = wcschr(s, L'.');
-   if (e != NULL)
-     {
-       *e = 0;
-     }
-   for (i = 0; i < 8; i++)
-     {
-       ImageFileName[i] = (CHAR)(s[i]);
-     }
-   if (e != NULL)
-     {
-       *e = '.';
-     }
-   
-   /*
-    * Process the application name and command line
-    */
-   RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
-   RtlInitUnicodeString(&CommandLine_U, lpCommandLine);
+    /* 
+     * 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;
+    }
 
-   DPRINT("ImagePathName_U %S\n", ImagePathName_U.Buffer);
-   DPRINT("CommandLine_U %S\n", CommandLine_U.Buffer);
+    /* Start by zeroing out the fields */
+    RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION));
 
-   /* Initialize the current directory string */
-   if (lpCurrentDirectory != NULL)
-     {
-       RtlInitUnicodeString(&CurrentDirectory_U,
-                           lpCurrentDirectory);
-     }
-   else
-     {
-       GetCurrentDirectoryW(256, TempCurrentDirectoryW);
-       RtlInitUnicodeString(&CurrentDirectory_U,
-                           TempCurrentDirectoryW);
-     }
+    /* Easy stuff first, convert the process priority class */
+    PriorityClass.Foreground = FALSE;
+    PriorityClass.PriorityClass = BasepConvertPriorityClass(dwCreationFlags);
 
-   /*
-    * 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");
+    /* Convert the environment */
+    if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+    {
+        lpEnvironment = BasepConvertUnicodeEnvironment(lpEnvironment);
+        if (!lpEnvironment) return FALSE;
+    }
 
-        // Find the application name
-        if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName,
-                &ApplicationNameString, NULL, NULL)) {
+    /* Get the application name and do all the proper formating necessary */
+GetAppName:
+    /* See if we have an application name (oh please let us have one!) */
+    if (!lpApplicationName)
+    {
+        /* The fun begins */
+        NameBuffer = RtlAllocateHeap(GetProcessHeap(), 
+                                     0,
+                                     MAX_PATH * sizeof(WCHAR));
+        
+        /* This is all we have to work with :( */
+        lpApplicationName = lpCommandLine;
+        
+        /* Initialize our friends at the beginning */
+        NullBuffer = (LPWSTR)lpApplicationName;
+        ScanString = (LPWSTR)lpApplicationName;
+        
+        /* We will start by looking for a quote */
+        if (*ScanString == L'\"')
+        {
+             /* That was quick */
+             SearchDone = TRUE;
+             
+             /* Advance past quote */
+             ScanString++;
+             lpApplicationName = ScanString;             
+
+             /* Find the closing quote */
+             while (*ScanString)
+             {
+                 if (*ScanString == L'\"')
+                 {
+                     /* Found it */
+                     NullBuffer = ScanString;
+                     FoundQuotes = TRUE;
+                     break;
+                 }
+
+                 /* Keep looking */
+                 ScanString++;
+                 NullBuffer = ScanString;
+             }
+        }
+        else
+        {
+            /* No quotes, so we'll be looking for white space */
+        WhiteScan:   
+            /* Reset the pointer */
+            lpApplicationName = lpCommandLine;
+
+            /* Find whitespace of Tab */
+            while (*ScanString)
+            {
+                if (*ScanString == ' ' || *ScanString == '\t')
+                {
+                    /* Found it */
+                    NullBuffer = ScanString;
+                    break;
+                }
+
+                /* Keep looking */
+                ScanString++;
+                NullBuffer = ScanString;
+            }
+        }
+                 
+        /* Set the Null Buffer */
+        SaveChar = *NullBuffer;
+        *NullBuffer = UNICODE_NULL;
+                
+        /* Do a search for the file */
+        DPRINT("Ready for SearchPathW: %S\n", lpApplicationName);
+        RetVal = SearchPathW(NULL,
+                             lpApplicationName,
+                             L".exe",
+                             MAX_PATH,
+                             NameBuffer,
+                             NULL) * sizeof(WCHAR);
+               
+        /* Did it find something? */
+        if (RetVal)
+        {
+            /* Get file attributes */
+            ULONG Attributes = GetFileAttributesW(NameBuffer);
+            if (Attributes & FILE_ATTRIBUTE_DIRECTORY)
+            {
+                /* Give it a length of 0 to fail, this was a directory. */
+                RetVal = 0;
+            }
+            else
+            {
+                /* It's a file! */
+                RetVal += sizeof(WCHAR);
+            }
+        }
+                
+        /* Now check if we have a file, and if the path size is OK */
+        if (!RetVal || RetVal >= (MAX_PATH / sizeof(WCHAR)))
+        {
+            ULONG PathType;
+            HANDLE hFile;
+            
+            /* We failed, try to get the Path Type */
+            DPRINT("SearchPathW failed. Retval: %ld\n", RetVal);
+            PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
+                    
+            /* If it's not relative, try to get the error */
+            if (PathType != RELATIVE_PATH)
+            {
+                /* This should fail, and give us a detailed LastError */
+                hFile = CreateFileW(lpApplicationName,
+                                    GENERIC_READ,
+                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                    NULL,
+                                    OPEN_EXISTING,
+                                    FILE_ATTRIBUTE_NORMAL,
+                                    NULL);
+                                        
+                /* Did it actually NOT fail? */
+                if (hFile != INVALID_HANDLE_VALUE)
+                {
+                    /* Fake the error */
+                    CloseHandle(hFile);
+                    SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
+                }
+            }
+            else
+            {
+                /* Immediately set the error */
+                SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
+            }
+                    
+            /* Did we already fail once? */
+            if (Error)
+            {
+                SetLastError(Error);
+            }
+            else
+            {
+                /* Not yet, cache it */
+                Error = GetLastError();
+            }
+                    
+            /* Put back the command line */
+            *NullBuffer = SaveChar;
+            lpApplicationName = NameBuffer;
+                    
+            /* 
+             * If the search isn't done and we still have cmdline
+             * then start over. Ex: c:\ha ha ha\haha.exe
+             */
+            if (*ScanString && !SearchDone)
+            {
+                /* Move in the buffer */
+                ScanString++;
+                NullBuffer = ScanString;
+                
+                /* We will have to add a quote, since there is a space*/
+                QuotesNeeded = TRUE;
+                    
+                /* And we will also fake the fact we found one */
+                FoundQuotes = TRUE;
+                    
+                /* Start over */
+                goto WhiteScan;
+            }
+                
+            /* We totally failed */
             return FALSE;
         }
-        DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
-
-        InitializeObjectAttributes(&ObjectAttributes,
-                             &ApplicationNameString,
-                             OBJ_CASE_INSENSITIVE,
-                             NULL,
-                             SecurityDescriptor);
+                
+        /* Put back the command line */
+        *NullBuffer = SaveChar;
+        lpApplicationName = NameBuffer;
+        DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer);
+    }
+    else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL)
+    {
+        /* We have an app name (good!) but no command line */
+        CmdLineIsAppName = TRUE;
+        lpCommandLine = (LPWSTR)lpApplicationName;
+    }
+     
+    /* At this point the name has been toyed with enough to be openable */
+    Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName);
+    
+    /* Check for failure */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Could be a non-PE File */
+        switch (Status)
+        {
+            /* Check if the Kernel tells us it's not even valid MZ */
+            case STATUS_INVALID_IMAGE_NE_FORMAT:
+            case STATUS_INVALID_IMAGE_PROTECT:
+            case STATUS_INVALID_IMAGE_NOT_MZ:
+            
+            /* If it's a DOS app, use VDM
+            if ((BasepCheckDosApp(&ApplicationName))) */
+            {
+                DPRINT1("Launching VDM...\n");
+                RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
+                RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+                return CreateProcessW(L"ntvdm.exe",
+                                      (LPWSTR)lpApplicationName,
+                                      lpProcessAttributes,
+                                      lpThreadAttributes,
+                                      bInheritHandles,
+                                      dwCreationFlags,
+                                      lpEnvironment,
+                                      lpCurrentDirectory,
+                                      lpStartupInfo,
+                                      lpProcessInformation);    
+            }
+            
+            /* It's a batch file */
+            Extension = &ApplicationName.Buffer[ApplicationName.Length / 
+                                                sizeof(WCHAR) - 4];
+            
+            /* Make sure the extensions are correct */
+            if (_wcsnicmp(Extension, L".bat", 4) && _wcsnicmp(Extension, L".cmd", 4))
+            {
+                SetLastError(ERROR_BAD_EXE_FORMAT);
+                return FALSE;
+            }
+            
+            /* Calculate the length of the command line */
+            CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1;
+            
+            /* If we found quotes, then add them into the length size */
+            if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2;
+            CmdLineLength *= sizeof(WCHAR);
+            
+            /* Allocate space for the new command line */
+            BatchCommandLine = RtlAllocateHeap(GetProcessHeap(),
+                                               0,
+                                               CmdLineLength);
+                                              
+            /* Build it */
+            wcscpy(BatchCommandLine, CMD_STRING);
+            if (CmdLineIsAppName || FoundQuotes)
+            {
+                wcscat(BatchCommandLine, L"\"");
+            }
+            wcscat(BatchCommandLine, lpCommandLine);
+            if (CmdLineIsAppName || FoundQuotes)
+            {
+                wcscat(BatchCommandLine, L"\"");
+            }
+            
+            /* Create it as a Unicode String */
+            RtlInitUnicodeString(&CommandLineString, BatchCommandLine);
+            
+            /* Set the command line to this */
+            lpCommandLine = CommandLineString.Buffer;
+            lpApplicationName = NULL;
+            
+            /* Free memory */
+            RtlFreeHeap(GetProcessHeap(), 0, TempBuffer);
+            RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+            ApplicationName.Buffer = NULL;
+            TempBuffer = NULL;
+            goto GetAppName;
+            break;
+            
+            case STATUS_INVALID_IMAGE_WIN_16:
+            
+                /* It's a Win16 Image, use VDM */
+                DPRINT1("Launching VDM...\n");
+                RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
+                RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+                return CreateProcessW(L"ntvdm.exe",
+                                      (LPWSTR)lpApplicationName,
+                                      lpProcessAttributes,
+                                      lpThreadAttributes,
+                                      bInheritHandles,
+                                      dwCreationFlags,
+                                      lpEnvironment,
+                                      lpCurrentDirectory,
+                                      lpStartupInfo,
+                                      lpProcessInformation);    
+
+            default:
+                /* Invalid Image Type */
+                SetLastError(ERROR_BAD_EXE_FORMAT);
+                return FALSE;
+        }
+    }
+    
+    /* Use our desktop if we didn't get any */
+    if (!StartupInfo.lpDesktop)
+    {
+        StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer;
+    }
+    
+    /* FIXME: Check if Application is allowed to run */
+    
+    /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
+    
+    /* Get some information about the executable */
+    Status = ZwQuerySection(hSection,
+                            SectionImageInformation,
+                            &SectionImageInfo,
+                            sizeof(SectionImageInfo),
+                            NULL);
+    if(!NT_SUCCESS(Status))
+    {
+        NtClose(hSection);
+        DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status);
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
 
-        // 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);
+    /* 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;
+    }
 
-        RtlFreeUnicodeString(&ApplicationNameString);
+    /* Initialize the process object attributes */
+    ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes, 
+                                                    lpProcessAttributes,
+                                                    NULL);
+   
+    /* Create the Process */
+    Status = NtCreateProcess(&hProcess,
+                             PROCESS_ALL_ACCESS,
+                             ObjectAttributes,
+                             NtCurrentProcess(),
+                             bInheritHandles,
+                             hSection,
+                             NULL,
+                             NULL);
+    if(!NT_SUCCESS(Status))
+    {
+        NtClose(hSection);
+        DPRINT1("Unable to create process, status 0x%x\n", Status);
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+    
+    /* Set new class */
+    Status = NtSetInformationProcess(hProcess,
+                                     ProcessPriorityClass,
+                                     &PriorityClass,
+                                     sizeof(PROCESS_PRIORITY_CLASS));
+    if(!NT_SUCCESS(Status))
+    {
+        NtClose(hProcess);
+        NtClose(hSection);
+        DPRINT1("Unable to set new process priority, status 0x%x\n", Status);
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+    
+    /* Set Error Mode */
+    if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
+    {
+        ULONG ErrorMode = SEM_FAILCRITICALERRORS;
+        NtSetInformationProcess(hProcess,
+                                ProcessDefaultHardErrorMode,
+                                &ErrorMode,
+                                sizeof(ULONG));
+    }
 
-        if (!NT_SUCCESS(Status)) {
-            DPRINT("Failed to open file\n");
-            SetLastErrorByStatus(Status);
+    /* Convert the directory to a full path */
+    if (lpCurrentDirectory)
+    {
+        /* Allocate a buffer */
+        CurrentDirectory = RtlAllocateHeap(GetProcessHeap(),
+                                           0,
+                                           MAX_PATH * sizeof(WCHAR) + 2);
+                                           
+        /* Get the length */
+        if (GetFullPathNameW(lpCurrentDirectory,
+                             MAX_PATH,
+                             CurrentDirectory,
+                             &CurrentDirectoryPart) > MAX_PATH)
+        {
+            DPRINT1("Directory name too long\n");
+            SetLastError(ERROR_DIRECTORY);
             return FALSE;
         }
-
-        // Read the dos header
-        Offset.QuadPart = 0;
-        Status = ZwReadFile(hFile,
-                     NULL,
-                     NULL,
-                     NULL,
-                     &Iosb,
-                     &DosHeader,
-                     sizeof(DosHeader),
-                     &Offset,
-                     0);
-
-        if (!NT_SUCCESS(Status)) {
-            DPRINT("Failed to read from file\n");
-            SetLastErrorByStatus(Status);
-            return FALSE;
+    }
+    
+    /* Insert quotes if needed */
+    if (QuotesNeeded || CmdLineIsAppName)
+    {
+        /* Allocate a buffer */
+        QuotedCmdLine = RtlAllocateHeap(GetProcessHeap(), 
+                                        0,
+                                        (wcslen(lpCommandLine) + 2 + 1) * 
+                                        sizeof(WCHAR));
+                                        
+        /* Copy the first quote */
+        wcscpy(QuotedCmdLine, L"\"");
+        
+        /* Save a null char */
+        if (QuotesNeeded)
+        {
+            SaveChar = *NullBuffer;
+            *NullBuffer = UNICODE_NULL;
         }
-        if (Iosb.Information != sizeof(DosHeader)) {
-            DPRINT("Failed to read dos header from file\n");
-            SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
-            return FALSE;
+        
+        /* Add the command line and the finishing quote */
+        wcscat(QuotedCmdLine, lpCommandLine);
+        wcscat(QuotedCmdLine, L"\"");
+        
+        /* Add the null char */
+        if (QuotesNeeded)
+        {
+            *NullBuffer = SaveChar;
+            wcscat(QuotedCmdLine, NullBuffer);
         }
-
-        // Check the DOS signature
-        if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
-            DPRINT("Failed dos magic check\n");
-            SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
+        
+        DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine);
+    }
+    
+    /* Get the Process Information */
+    Status = NtQueryInformationProcess(hProcess,
+                                       ProcessBasicInformation,
+                                       &ProcessBasicInfo,
+                                       sizeof(ProcessBasicInfo),
+                                       NULL);
+    
+    /* Create Process Environment */
+    RemotePeb = ProcessBasicInfo.PebBaseAddress;
+    Status = BasepInitializeEnvironment(hProcess,
+                                        RemotePeb,
+                                        (LPWSTR)lpApplicationName,
+                                        CurrentDirectory,
+                                        (QuotesNeeded || CmdLineIsAppName) ?
+                                        QuotedCmdLine : lpCommandLine,
+                                        lpEnvironment,
+                                        lpStartupInfo,
+                                        dwCreationFlags,
+                                        bInheritHandles);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Could not initialize Process Environment\n");
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+    
+    /* Close the section */
+    NtClose(hSection);
+    hSection = NULL;
+
+    /* Duplicate the handles if needed */
+    if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
+        SectionImageInfo.SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
+    {
+        PRTL_USER_PROCESS_PARAMETERS RemoteParameters;
+        
+        /* Get the remote parameters */
+        Status = NtReadVirtualMemory(hProcess,
+                                     &RemotePeb->ProcessParameters,
+                                     &RemoteParameters,
+                                     sizeof(PVOID),
+                                     NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to read memory\n");
             return FALSE;
         }
-        NtClose(hFile);
-
-        DPRINT("Launching VDM...\n");
-        return CreateProcessW(L"ntvdm.exe",
-                (LPWSTR)lpApplicationName,
-                lpProcessAttributes,
-                lpThreadAttributes,
-                bInheritHandles,
-                dwCreationFlags,
-                lpEnvironment,
-                lpCurrentDirectory,
-                lpStartupInfo,
-                lpProcessInformation);
-   }
-/////////////////////////////////////////
-   /*
-    * Create a new process
-    */
-   Status = NtCreateProcess(&hProcess,
-                           PROCESS_ALL_ACCESS,
-                           NULL,
-                           NtCurrentProcess(),
-                           bInheritHandles,
-                           hSection,
-                           NULL,
-                           NULL);
-   if (lpStartupInfo)
-   {
-      if (lpStartupInfo->lpReserved2)
-      {
-         /* FIXME:
-         *    ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
-         *    the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
-         *    If is possible that this function overwrite the last information in runtimeinfo
-         *    with the null terminator for the unicode string.
-         */
-        RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = ROUND_UP(lpStartupInfo->cbReserved2, 2) + 2;
-        RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length);
-        memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2);
-      }
-   }
-
-   /*
-    * Create the PPB
-    */
-   RtlCreateProcessParameters(&Ppb,
-                             &ImagePathName_U,
-                             NULL,
-                             lpCurrentDirectory ? &CurrentDirectory_U : NULL,
-                             &CommandLine_U,
-                             lpEnvironment,
-                             NULL,
-                             NULL,
-                             NULL,
-                             lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL);
-
-   if (lpStartupInfo && lpStartupInfo->lpReserved2)
-       RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer);
-
-
-   /*
-    * Translate some handles for the new process
-    */
-   if (Ppb->CurrentDirectoryHandle)
-   {
-      Status = NtDuplicateObject (NtCurrentProcess(),
-                        Ppb->CurrentDirectoryHandle,
-                        hProcess,
-                        &Ppb->CurrentDirectoryHandle,
-                        0,
-                        TRUE,
-                        DUPLICATE_SAME_ACCESS);
-   }
-
-   if (Ppb->hConsole)
-   {
-      Status = NtDuplicateObject (NtCurrentProcess(), 
-                        Ppb->hConsole,
-                        hProcess,
-                        &Ppb->hConsole,
-                        0,
-                        TRUE,
-                        DUPLICATE_SAME_ACCESS);
-   }
-
-   /*
-    * Get some information about the executable
-    */
-   Status = ZwQuerySection(hSection,
-                          SectionImageInformation,
-                          &Sii,
-                          sizeof(Sii),
-                          &i);
-   /*
-    * Close the section
-    */
-   NtClose(hSection);
-
-   /*
-    * Get some information about the process
-    */
-   NtQueryInformationProcess(hProcess,
-                            ProcessBasicInformation,
-                            &ProcessBasicInfo,
-                            sizeof(ProcessBasicInfo),
-                            &retlen);
-   DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
-         ProcessBasicInfo.UniqueProcessId);
-   lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
-
-   /*
-    * Tell the csrss server we are creating a new process
-    */
-   CsrRequest.Type = CSRSS_CREATE_PROCESS;
-   CsrRequest.Data.CreateProcessRequest.NewProcessId = 
-     ProcessBasicInfo.UniqueProcessId;
-   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");
-     }
-   else if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
-     {
-       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)
-   {
-      if (IsConsoleHandle(Ppb->hStdInput))
-      {
-         Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
-      }
-      else
-      {
-         DPRINT("Duplicate input handle\n");
-         Status = NtDuplicateObject (NtCurrentProcess(), 
-                                     Ppb->hStdInput,
-                                     hProcess,
-                                     &Ppb->hStdInput,
-                                     0,
-                                     TRUE,
-                                     DUPLICATE_SAME_ACCESS);
-         if(!NT_SUCCESS(Status))
-         {
-           DPRINT("NtDuplicateObject failed, status %x\n", Status);
-         }
-      }
-   }
-
-   if (OutputDup)
-   {
-      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)
-   {
-      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);
+        
+        /* Duplicate and write the handles */
+        BasepDuplicateAndWriteHandle(hProcess,
+                                     OurPeb->ProcessParameters->StandardInput,
+                                     &RemoteParameters->StandardInput);
+        BasepDuplicateAndWriteHandle(hProcess,
+                                     OurPeb->ProcessParameters->StandardOutput,
+                                     &RemoteParameters->StandardOutput);
+        BasepDuplicateAndWriteHandle(hProcess,
+                                     OurPeb->ProcessParameters->StandardError,
+                                     &RemoteParameters->StandardError);
+    }
+        
+    /* Create the first thread */
+    DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
+            SectionImageInfo.TransferAddress);
+    hThread = BasepCreateFirstThread(hProcess,
+                                     lpThreadAttributes,
+                                     &SectionImageInfo,
+                                     &ClientId);
+
+    if (hThread == NULL)
+    {
+        DPRINT1("Could not create Initial Thread\n");
+        return FALSE;
+    }
 
-   RtlDestroyProcessParameters (Ppb);
+    
+    /* Notify CSRSS */
+    Status = BasepNotifyCsrOfCreation(dwCreationFlags,
+                                      (HANDLE)ProcessBasicInfo.UniqueProcessId);
 
-   Status = NtSetInformationProcess(hProcess,
-                                   ProcessImageFileName,
-                                   ImageFileName,
-                                   8);
-   /*
-    * Create the thread for the kernel
-    */
-   DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
-    ImageBaseAddress + (ULONG)Sii.EntryPoint);
-   hThread =  KlCreateFirstThread(hProcess,
-                                 lpThreadAttributes,
-          &Sii,
-          ImageBaseAddress + (ULONG)Sii.EntryPoint,
-                                 dwCreationFlags,
-                                 &lpProcessInformation->dwThreadId);
-   if (hThread == INVALID_HANDLE_VALUE)
-     {
-       return FALSE;
-     }
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("CSR Notification Failed");
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+    
+    if (!(dwCreationFlags & CREATE_SUSPENDED))
+    {
+        NtResumeThread(hThread, &Dummy);
+    }
+    
+    /* Cleanup Environment */    
+    if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+    {
+        RtlDestroyEnvironment(lpEnvironment);
+    }
 
-   lpProcessInformation->hProcess = hProcess;
-   lpProcessInformation->hThread = hThread;
+    /* Return Data */        
+    lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess;
+    lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread;
+    lpProcessInformation->hProcess = hProcess;
+    lpProcessInformation->hThread = hThread;
+    DPRINT("hThread[%lx]: %lx inside hProcess[%lx]: %lx\n", hThread,
+            ClientId.UniqueThread, ClientId.UniqueProcess, hProcess);
+    hProcess = hThread = NULL;
+            
+    /* De-allocate heap strings */
+    if (NameBuffer) RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
+    if (ApplicationName.Buffer)
+        RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+    if (CurrentDirectory) RtlFreeHeap(GetProcessHeap(), 0, CurrentDirectory);
+    if (QuotedCmdLine) RtlFreeHeap(GetProcessHeap(), 0, QuotedCmdLine);
+
+    /* Kill any handles still alive */
+    if (hSection) NtClose(hSection);
+    if (hThread)
+    {
+        /* We don't know any more details then this */
+        NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL);
+        NtClose(hThread);
+    }
+    if (hProcess) NtClose(hProcess);
 
-   return TRUE;
+    /* Return Success */
+    return TRUE;
 }
 
 /* EOF */