- Final ROSRTL removal patch. The next patch will remove the actual library and code.
- Changes:
    - CreateProcess
        * Cleanup creation of the initial thread using new utility functions and remove rosrtl
        * Almost entirely rewrote the function to support features such as:
            - SxS (locally only, patch will follow),
            - SFP (SAFER) (locally only, patch will follow),
            - DllPaths (locally only, patch will follow), 
            - Proper process environment/paramter block creation
            - Proper console handle management (needs more work in kernel32/csr),
            - Tokens/CreateProcessAsUser (locally only, patch will follow), 
            - Simpler code for path lookup, and more robust.
            - Support for "auto-correction" (see Raymond Chen's blog)
            - 16-bit/NE detection
            - A variety of creation flags are now properly supported
            - Added support for an undocumented-yet-known (see comment) shell flag
            - Alert for flags we don't support yet
            - Catch invalid flag combinations and other caller errors
            - Improve and correct path searcing to use documented behaviours
            - Created a multitude of helper functions to make the code easier to read
              and allow them to be used for other apis as time goes on.
    
    - BaseProcessStartup
        * Call NtSetThreadInformation to let the Kernel know of the Thread's Start Address.
        * Correct prototype of Thread Startup function for this case.

This fixes MANY things, some of which may not be evident, and possibly creates regressions which I have not yet seen but will try to correct. Some of these may be caused by the fact that I've seen code send CreateProcessW incorrect flags. Some things of note: DO NOT send partial names as "lpApplicationName". It's not supposed to work unless you're in the same current directory. Also, do NOT send CREATE_UNICODE_ENVIRONMENT if you don't have a unicode environement, and vice-versa. I've seen lots of code doing mistakes related to this. I hope you appreciate this patch and won't all jump on me for possbile regressions :(.
Modified: trunk/reactos/lib/kernel32/process/create.c
Modified: trunk/reactos/lib/kernel32/thread/i386/thread.S
Modified: trunk/reactos/lib/kernel32/thread/thread.c
Modified: trunk/reactos/ntoskrnl/mm/process.c

Modified: trunk/reactos/lib/kernel32/process/create.c
--- trunk/reactos/lib/kernel32/process/create.c	2005-07-26 00:50:17 UTC (rev 16729)
+++ trunk/reactos/lib/kernel32/process/create.c	2005-07-26 04:14:10 UTC (rev 16730)
@@ -1,1399 +1,1455 @@
-/* $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>
 
-/* FIXME */
-#include <rosrtl/thread.h>
-
 #define NDEBUG
-#include "../include/debug.h"
+#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;
-   }
+    EXCEPTION_POINTERS *ExceptionInfo = _SEH_GetExceptionPointers();
+    LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
 
-   return True(DestStr, SourceStr, Allocate);
+    if (GlobalTopLevelExceptionFilter != NULL)
+    {
+        _SEH_TRY
+        {
+            ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo);
+        }
+        _SEH_HANDLE
+        {
+            ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
+        }
+        _SEH_END;
+    }
+
+    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;
+    UINT uExitCode = 0;
 
+    DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
 
-   if(Ros32Attribs != NULL && Ros32Attribs->nLength >= sizeof(*Ros32Attribs))
-   {
-      NativeAttribs->SecurityDescriptor = Ros32Attribs->lpSecurityDescriptor;
+    _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;
 
-      if(Ros32Attribs->bInheritHandle)
-      {
-         NativeAttribs->Attributes |= OBJ_INHERIT;
-      }
-   }
-   else
-   {
-      NativeAttribs->SecurityDescriptor = NULL;
-   }
+    /* 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 ULONG SubsystemType,
+                         OUT PHANDLE ConsoleHandle,
+                         OUT PHANDLE InputHandle,
+                         OUT PHANDLE OutputHandle)
 {
-   if(!NativeAttribs) return;
+    ULONG Request = CREATE_PROCESS;
+    CSR_API_MESSAGE CsrRequest;
+    NTSTATUS Status;
+    
+    DPRINT("BasepNotifyCsrOfCreation\n");
+     
+    /* Some hacks (heck, this whole API is a hack) */
+    if (SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI)
+    {
+        dwCreationFlags = (dwCreationFlags &~ CREATE_NEW_CONSOLE) |
+                           DETACHED_PROCESS;
+    }
+    else if (SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
+    {
+        dwCreationFlags |= CREATE_NEW_CONSOLE;
+    }
+    
+    /* Fill out the request */
+    CsrRequest.Data.CreateProcessRequest.NewProcessId = ProcessId;
+    CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
+    CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher;
+    CsrRequest.Data.CreateProcessRequest.InputHandle = 0;
+    CsrRequest.Data.CreateProcessRequest.OutputHandle = 0;
+    CsrRequest.Data.CreateProcessRequest.Console = 0;
+    
+    /* 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 Handles */
+    *ConsoleHandle = CsrRequest.Data.CreateProcessRequest.Console;
+    *InputHandle = CsrRequest.Data.CreateProcessRequest.InputHandle;
+    *OutputHandle = CsrRequest.Data.CreateProcessRequest.OutputHandle;
+    DPRINT("CSR Created: %lx %lx\n", *InputHandle, *OutputHandle);
+    
+    /* REturn Success */
+    return STATUS_SUCCESS;
+}
 
-   RtlRosR32AttribsToNativeAttribs(NativeAttribs, Ros32Attribs);
+/*
+ * Creates the first Thread in a Proces
+ */
+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);
 
-   if(Ros32Name != NULL && NativeName != NULL)
-   {
-      RtlInitUnicodeString(NativeName, Ros32Name);
-
-      NativeAttribs->ObjectName = NativeName;
-      NativeAttribs->RootDirectory = Ros32NameRoot;
-      NativeAttribs->Attributes |= OBJ_CASE_INSENSITIVE;
-   }
+    /* 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;
 }
 
-
 /*
- * @implemented
+ * Converts ANSI to Unicode Environment
  */
-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)
-/*
- * 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
- */
+PVOID
+STDCALL
+BasepConvertUnicodeEnvironment(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;
+    PCHAR pcScan;
+    SIZE_T EnvSize = 0;
+    ANSI_STRING AnsiEnv;
+    UNICODE_STRING UnicodeEnv;
+    NTSTATUS Status;
+    
+    DPRINT("BasepConvertUnicodeEnvironment\n");
 
-   NTSTATUS (STDCALL *pTrue)(UNICODE_STRING *,
-                                  ANSI_STRING *,
-				  BOOLEAN);
+    /* Scan the environment to calculate its Unicode size */
+    AnsiEnv.Buffer = pcScan = lpEnvironment;
+    while (*pcScan) while (*pcScan++);
 
-   ULONG (STDCALL *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 > (SIZE_T)((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;
+    /* Create our ANSI String */
+    AnsiEnv.Length = (ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + 1;
+    AnsiEnv.MaximumLength = AnsiEnv.Length + 1;
+    
+    /* Allocate memory for the Unicode Environment */
+    UnicodeEnv.Buffer = NULL;
+    EnvSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
+    Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+                                     (PVOID)&UnicodeEnv.Buffer,
+                                     0,
+                                     &EnvSize,
+                                     MEM_COMMIT,
+                                     PAGE_READWRITE);
+    /* Failure */
+    if (!NT_SUCCESS(Status))
+    {
+        SetLastError(Status);
+        return NULL;
+    }
+        
+    /* Use the allocated size */
+    UnicodeEnv.MaximumLength = EnvSize;
+    
+    /* Convert */
+    RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
+    return UnicodeEnv.Buffer;
 }
 
-
-_SEH_FILTER(BaseExceptionFilter)
+/*
+ * Converts a Win32 Priority Class to NT
+ */
+ULONG
+STDCALL
+BasepConvertPriorityClass(IN ULONG dwCreationFlags)
 {
-   EXCEPTION_POINTERS * ExceptionInfo = _SEH_GetExceptionPointers();
-   LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
-
-   if (GlobalTopLevelExceptionFilter != NULL)
-   {
-      _SEH_TRY
-      {
-         ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo);
-      }
-      _SEH_HANDLE
-      {
-         ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
-      }
-      _SEH_END;
-   }
-
-   return ExceptionDisposition;
+    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 = 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");
-
-   _SEH_TRY
-   {
-      uExitCode = (lpStartAddress)((PVOID)lpParameter);
-   }
-   _SEH_EXCEPT(BaseExceptionFilter)
-   {
-      uExitCode = _SEH_GetExceptionCode();
-   }
-   _SEH_END;
-
-   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->SubsystemType != 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->MaximumStackSize,
-	  Sii->CommittedStackSize,
-	  pTrueStartAddress,
-	  &hThread,
-	  &cidClientId,
-	  2,
-          lpStartAddress,
-	  PEB_BASE);
-
-   /* create the first thread */
-   nErrCode = RtlRosCreateUserThreadVa(ProcessHandle,
-                                       &oaThreadAttribs,
-				       dwCreationFlags & CREATE_SUSPENDED,
-				       0,
-				       &(Sii->MaximumStackSize),
-				       &(Sii->CommittedStackSize),
-				       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->MaximumStackSize,
-	  Sii->CommittedStackSize,
-	  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,
-			  ULONG ImageSubSystem)
+NTSTATUS
+STDCALL
+BasepInitializeEnvironment(HANDLE ProcessHandle,
+                           PPEB Peb,
+                           LPWSTR ApplicationPathName,
+                           LPWSTR lpCurrentDirectory,
+                           LPWSTR lpCommandLine,
+                           LPVOID Environment,
+                           LPSTARTUPINFOW StartupInfo,
+                           DWORD CreationFlags,
+                           BOOL InheritHandles,
+                           HANDLE hInput,
+                           HANDLE hOutput)
 {
-   NTSTATUS Status;
-   PVOID PpbBase;
-   ULONG PpbSize;
-   ULONG BytesWritten;
-   ULONG Offset;
-   PVOID ParentEnv = NULL;
-   PVOID EnvPtr = NULL;
-   PWCHAR ptr;
-   ULONG EnvSize = 0, EnvSize1 = 0;
+    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);
 
-   /* create the Environment */
-   if (Ppb->Environment != NULL)
-   {
-      ParentEnv = Ppb->Environment;
-      ptr = ParentEnv;
-      while (*ptr)
-      {
-         while(*ptr++);
-      }
-      ptr++;
-      EnvSize = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)ParentEnv);
-   }
-   else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
-   {
-      MEMORY_BASIC_INFORMATION MemInfo;
-      ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
+        /* 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,
[truncated at 1000 lines; 3251 more skipped]