Fix so reactos can boot to gui again Thx W3seek for his small patch
[reactos.git] / reactos / subsys / csrss / init.c
index 106ad69..cdffec5 100644 (file)
@@ -1,5 +1,5 @@
 /* $Id$
- * 
+ *
  * reactos/subsys/csrss/init.c
  *
  * Initialize the CSRSS subsystem server process.
 
 /* INCLUDES ******************************************************************/
 
-#include <csrss/csrss.h>
-#include <ddk/ntddk.h>
-#include <ntdll/csr.h>
-#include <ntdll/rtl.h>
-#include <ntdll/ldr.h>
-#include <win32k/win32k.h>
-#include <rosrtl/string.h>
-#include <sm/helper.h>
-
-#include "api.h"
-#include "csrplugin.h"
+#include <csrss.h>
 
 #define NDEBUG
 #include <debug.h>
 
 /* GLOBALS ******************************************************************/
 
-HANDLE CsrInitEvent = INVALID_HANDLE_VALUE;
-HANDLE CsrHeap = INVALID_HANDLE_VALUE;
+HANDLE CsrHeap = (HANDLE) 0;
 
-HANDLE CsrObjectDirectory = INVALID_HANDLE_VALUE;
+HANDLE CsrObjectDirectory = (HANDLE) 0;
 
 UNICODE_STRING CsrDirectoryName;
 
@@ -39,11 +28,24 @@ extern HANDLE CsrssApiHeap;
 static unsigned InitCompleteProcCount;
 static CSRPLUGIN_INIT_COMPLETE_PROC *InitCompleteProcs = NULL;
 
+HANDLE hSbApiPort = (HANDLE) 0;
+
+HANDLE hBootstrapOk = (HANDLE) 0;
+
+HANDLE hSmApiPort = (HANDLE) 0;
+
+HANDLE hApiPort = (HANDLE) 0;
+
+/**********************************************************************
+ * CsrpAddInitCompleteProc/1
+ */
 static NTSTATUS FASTCALL
-AddInitCompleteProc(CSRPLUGIN_INIT_COMPLETE_PROC Proc)
+CsrpAddInitCompleteProc(CSRPLUGIN_INIT_COMPLETE_PROC Proc)
 {
   CSRPLUGIN_INIT_COMPLETE_PROC *NewProcs;
 
+  DPRINT("CSR: %s called\n", __FUNCTION__);
+
   NewProcs = RtlAllocateHeap(CsrssApiHeap, 0,
                              (InitCompleteProcCount + 1)
                              * sizeof(CSRPLUGIN_INIT_COMPLETE_PROC));
@@ -64,12 +66,17 @@ AddInitCompleteProc(CSRPLUGIN_INIT_COMPLETE_PROC Proc)
   return STATUS_SUCCESS;
 }
 
+/**********************************************************************
+ * CallInitComplete/0
+ */
 static BOOL FASTCALL
 CallInitComplete(void)
 {
   BOOL Ok;
   unsigned i;
 
+  DPRINT("CSR: %s called\n", __FUNCTION__);
+
   Ok = TRUE;
   if (0 != InitCompleteProcCount)
     {
@@ -86,21 +93,16 @@ CallInitComplete(void)
 ULONG
 InitializeVideoAddressSpace(VOID);
 
+/**********************************************************************
+ * CsrpCreateObjectDirectory/3
+ */
 static NTSTATUS
-CsrParseCommandLine (
-       ULONG ArgumentCount,
-       PWSTR *ArgumentArray
-       )
+CsrpCreateObjectDirectory (int argc, char ** argv, char ** envp)
 {
    NTSTATUS Status;
    OBJECT_ATTRIBUTES Attributes;
 
-
-   /*   DbgPrint ("Arguments: %ld\n", ArgumentCount);
-   for (i = 0; i < ArgumentCount; i++)
-     {
-       DbgPrint ("Argument %ld: %S\n", i, ArgumentArray[i]);
-       }*/
+  DPRINT("CSR: %s called\n", __FUNCTION__);
 
 
        /* create object directory ('\Windows') */
@@ -109,30 +111,35 @@ CsrParseCommandLine (
 
        InitializeObjectAttributes (&Attributes,
                                    &CsrDirectoryName,
-                                   0,
+                                   OBJ_OPENIF,
                                    NULL,
                                    NULL);
 
-       Status = NtCreateDirectoryObject(&CsrObjectDirectory,
-                                        0xF000F,
-                                        &Attributes);
-
+       Status = NtOpenDirectoryObject(&CsrObjectDirectory,
+                                      0xF000F, /* ea:??? */
+                                      &Attributes);
        return Status;
 }
 
-
-static VOID
-CsrInitVideo(VOID)
+/**********************************************************************
+ * CsrpInitVideo/3
+ *
+ * TODO: we need a virtual device for sessions other than
+ * TODO: the console one
+ */
+static NTSTATUS
+CsrpInitVideo (int argc, char ** argv, char ** envp)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING DeviceName;
+  UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\??\\DISPLAY1");
   IO_STATUS_BLOCK Iosb;
-  HANDLE VideoHandle;
-  NTSTATUS Status;
+  HANDLE VideoHandle = (HANDLE) 0;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+  DPRINT("CSR: %s called\n", __FUNCTION__);
 
   InitializeVideoAddressSpace();
 
-  RtlRosInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\DISPLAY1");
   InitializeObjectAttributes(&ObjectAttributes,
                             &DeviceName,
                             0,
@@ -148,10 +155,23 @@ CsrInitVideo(VOID)
     {
       NtClose(VideoHandle);
     }
+  return Status;
 }
 
-static NTSTATUS FASTCALL
-InitWin32Csr()
+/**********************************************************************
+ * CsrpInitWin32Csr/3
+ *
+ * TODO: this function should be turned more general to load an
+ * TODO: hosted server DLL as received from the command line;
+ * TODO: for instance: ServerDll=winsrv:ConServerDllInitialization,2
+ * TODO:               ^method   ^dll   ^api                       ^sid
+ * TODO:
+ * TODO: CsrpHostServerDll (LPWSTR DllName,
+ * TODO:                    LPWSTR ApiName,
+ * TODO:                    DWORD  ServerId)
+ */
+static NTSTATUS
+CsrpInitWin32Csr (int argc, char ** argv, char ** envp)
 {
   NTSTATUS Status;
   UNICODE_STRING DllName;
@@ -163,6 +183,8 @@ InitWin32Csr()
   PCSRSS_OBJECT_DEFINITION ObjectDefinitions;
   CSRPLUGIN_INIT_COMPLETE_PROC InitCompleteProc;
 
+  DPRINT("CSR: %s called\n", __FUNCTION__);
+
   RtlInitUnicodeString(&DllName, L"win32csr.dll");
   Status = LdrLoadDll(NULL, 0, &DllName, (PVOID *) &hInst);
   if (! NT_SUCCESS(Status))
@@ -196,7 +218,7 @@ InitWin32Csr()
     }
   if (NULL != InitCompleteProc)
     {
-      Status = AddInitCompleteProc(InitCompleteProc);
+      Status = CsrpAddInitCompleteProc(InitCompleteProc);
     }
 
   return Status;
@@ -204,172 +226,399 @@ InitWin32Csr()
 
 CSRSS_API_DEFINITION NativeDefinitions[] =
   {
-    CSRSS_DEFINE_API(CSRSS_CREATE_PROCESS,               CsrCreateProcess),
-    CSRSS_DEFINE_API(CSRSS_TERMINATE_PROCESS,            CsrTerminateProcess),
-    CSRSS_DEFINE_API(CSRSS_CONNECT_PROCESS,              CsrConnectProcess),
-    CSRSS_DEFINE_API(CSRSS_REGISTER_SERVICES_PROCESS,    CsrRegisterServicesProcess),
-    CSRSS_DEFINE_API(CSRSS_GET_SHUTDOWN_PARAMETERS,      CsrGetShutdownParameters),
-    CSRSS_DEFINE_API(CSRSS_SET_SHUTDOWN_PARAMETERS,      CsrSetShutdownParameters),
-    CSRSS_DEFINE_API(CSRSS_GET_INPUT_HANDLE,             CsrGetInputHandle),
-    CSRSS_DEFINE_API(CSRSS_GET_OUTPUT_HANDLE,            CsrGetOutputHandle),
-    CSRSS_DEFINE_API(CSRSS_CLOSE_HANDLE,                 CsrCloseHandle),
-    CSRSS_DEFINE_API(CSRSS_VERIFY_HANDLE,                CsrVerifyHandle),
-    CSRSS_DEFINE_API(CSRSS_DUPLICATE_HANDLE,             CsrDuplicateHandle),
-    CSRSS_DEFINE_API(CSRSS_GET_INPUT_WAIT_HANDLE,        CsrGetInputWaitHandle),
-    { 0, 0, 0, NULL }
+    CSRSS_DEFINE_API(CREATE_PROCESS,               CsrCreateProcess),
+    CSRSS_DEFINE_API(TERMINATE_PROCESS,            CsrTerminateProcess),
+    CSRSS_DEFINE_API(CONNECT_PROCESS,              CsrConnectProcess),
+    CSRSS_DEFINE_API(REGISTER_SERVICES_PROCESS,    CsrRegisterServicesProcess),
+    CSRSS_DEFINE_API(GET_SHUTDOWN_PARAMETERS,      CsrGetShutdownParameters),
+    CSRSS_DEFINE_API(SET_SHUTDOWN_PARAMETERS,      CsrSetShutdownParameters),
+    CSRSS_DEFINE_API(GET_INPUT_HANDLE,             CsrGetInputHandle),
+    CSRSS_DEFINE_API(GET_OUTPUT_HANDLE,            CsrGetOutputHandle),
+    CSRSS_DEFINE_API(CLOSE_HANDLE,                 CsrCloseHandle),
+    CSRSS_DEFINE_API(VERIFY_HANDLE,                CsrVerifyHandle),
+    CSRSS_DEFINE_API(DUPLICATE_HANDLE,             CsrDuplicateHandle),
+    CSRSS_DEFINE_API(GET_INPUT_WAIT_HANDLE,        CsrGetInputWaitHandle),
+    { 0, 0, NULL }
   };
 
+static NTSTATUS STDCALL
+CsrpCreateListenPort (IN     LPWSTR  Name,
+                     IN OUT PHANDLE Port,
+                     IN     PTHREAD_START_ROUTINE ListenThread)
+{
+       NTSTATUS           Status = STATUS_SUCCESS;
+       OBJECT_ATTRIBUTES  PortAttributes;
+       UNICODE_STRING     PortName;
+
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       RtlInitUnicodeString (& PortName, Name);
+       InitializeObjectAttributes (& PortAttributes,
+                                   & PortName,
+                                   0,
+                                   NULL,
+                                   NULL);
+       Status = NtCreatePort ( Port,
+                               & PortAttributes,
+                               LPC_MAX_DATA_LENGTH, /* TODO: make caller set it*/
+                               LPC_MAX_MESSAGE_LENGTH, /* TODO: make caller set it*/
+                               0); /* TODO: make caller set it*/
+       if(!NT_SUCCESS(Status))
+       {
+               DPRINT1("CSR: %s: NtCreatePort failed (Status=%08lx)\n",
+                       __FUNCTION__, Status);
+               return Status;
+       }
+       Status = RtlCreateUserThread(NtCurrentProcess(),
+                               NULL,
+                               FALSE,
+                               0,
+                               0,
+                               0,
+                               (PTHREAD_START_ROUTINE) ListenThread,
+                               Port,
+                               NULL,
+                               NULL);
+       return Status;
+}
+
+/* === INIT ROUTINES === */
+
 /**********************************************************************
- * NAME
- *     CsrpRegisterSubsystem/0
- *
- * DESCRIPTION
- *     Register CSRSS in the SM to manage IMAGE_SUBSYSTEM_WINDOWS_CUI 
- *     processes (environment subsystem server).
- *
- * RETURN VALUE
- *     STATUS_SUCCESS on success.
+ * CsrpCreateHeap/3
  */
-static NTSTATUS FASTCALL
-CsrpRegisterSubsystem(PHANDLE hSmApiPort)
+static NTSTATUS
+CsrpCreateHeap (int argc, char ** argv, char ** envp)
+{
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       CsrssApiHeap = RtlCreateHeap(HEAP_GROWABLE,
+                                      NULL,
+                                      65536,
+                                      65536,
+                                      NULL,
+                                      NULL);
+       if (CsrssApiHeap == NULL)
+       {
+               return STATUS_UNSUCCESSFUL;
+       }
+       return STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ * CsrpCreateCallbackPort/3
+ */
+static NTSTATUS
+CsrpCreateCallbackPort (int argc, char ** argv, char ** envp)
 {
-       NTSTATUS Status = STATUS_SUCCESS;
-       UNICODE_STRING SbApiPortName;
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       return CsrpCreateListenPort (L"\\Windows\\SbApiPort",
+                                    & hSbApiPort,
+                                    ServerSbApiPortThread);
+}
 
-       RtlInitUnicodeString (& SbApiPortName, L"\\Windows\\SbApiPort");
-       Status = SmConnectApiPort (& SbApiPortName,
-                                  (HANDLE)-1, //unused
+/**********************************************************************
+ * CsrpRegisterSubsystem/3
+ */
+static NTSTATUS
+CsrpRegisterSubsystem (int argc, char ** argv, char ** envp)
+{
+       NTSTATUS           Status = STATUS_SUCCESS;
+       OBJECT_ATTRIBUTES  BootstrapOkAttributes;
+       UNICODE_STRING     Name;
+
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       /*
+        * Create the event object the callback port
+        * thread will signal *if* the SM will
+        * authorize us to bootstrap.
+        */
+       RtlInitUnicodeString (& Name, L"\\CsrssBooting");
+       InitializeObjectAttributes(& BootstrapOkAttributes,
+                                  & Name,
+                                  0, NULL, NULL);
+       Status = NtCreateEvent (& hBootstrapOk,
+                               EVENT_ALL_ACCESS,
+                               & BootstrapOkAttributes,
+                               SynchronizationEvent,
+                               FALSE);
+       if(!NT_SUCCESS(Status))
+       {
+               DPRINT("CSR: %s: NtCreateEvent failed (Status=0x%08lx)\n",
+                       __FUNCTION__, Status);
+               return Status;
+       }
+       /*
+        * Let's tell the SM a new environment
+        * subsystem server is in the system.
+        */
+       RtlInitUnicodeString (& Name, L"\\Windows\\SbApiPort");
+       DPRINT("CSR: %s: registering with SM for\n  IMAGE_SUBSYSTEM_WINDOWS_CUI == 3\n", __FUNCTION__);
+       Status = SmConnectApiPort (& Name,
+                                  hSbApiPort,
                                   IMAGE_SUBSYSTEM_WINDOWS_CUI,
-                                  hSmApiPort);
+                                  hSmApiPort);
        if(!NT_SUCCESS(Status))
        {
-               DPRINT("CSR: unable to connect to the SM (Status=0x%lx)\n", Status);
+               DPRINT("CSR: %s unable to connect to the SM (Status=0x%08lx)\n",
+                       __FUNCTION__, Status);
+               NtClose (hBootstrapOk);
                return Status;
        }
-       DisplayString(L"CSR: registered with SM\n");
-       return Status;  
+       /*
+        *  Wait for SM to reply OK... If the SM
+        *  won't answer, we hang here forever!
+        */
+       DPRINT("CSR: %s: waiting for SM to OK boot...\n", __FUNCTION__);
+       Status = NtWaitForSingleObject (hBootstrapOk,
+                                       FALSE,
+                                       NULL);
+       NtClose (hBootstrapOk);
+       return Status;
 }
 
+/**********************************************************************
+ *     EnvpToUnicodeString/2
+ */
+static ULONG FASTCALL
+EnvpToUnicodeString (char ** envp, PUNICODE_STRING UnicodeEnv)
+{
+       ULONG        CharCount = 0;
+       ULONG        Index = 0;
+       ANSI_STRING  AnsiEnv;
+
+       UnicodeEnv->Buffer = NULL;
+       
+       for (Index=0; NULL != envp[Index]; Index++)
+       {
+               CharCount += strlen (envp[Index]);
+               ++ CharCount;
+       }
+       ++ CharCount;
+       
+       AnsiEnv.Buffer = RtlAllocateHeap (RtlGetProcessHeap(), 0, CharCount);
+       if (NULL != AnsiEnv.Buffer)
+       {
+
+               PCHAR WritePos = AnsiEnv.Buffer;
+               
+               for (Index=0; NULL != envp[Index]; Index++)
+               {
+                       strcpy (WritePos, envp[Index]);
+                       WritePos += strlen (envp[Index]) + 1;
+               }
+
+      /* FIXME: the last (double) nullterm should perhaps not be included in Length
+       * but only in MaximumLength. -Gunnar */
+               AnsiEnv.Buffer [CharCount-1] = '\0';
+               AnsiEnv.Length             = CharCount;
+               AnsiEnv.MaximumLength      = CharCount;
+      
+               RtlAnsiStringToUnicodeString (UnicodeEnv, & AnsiEnv, TRUE);
+               RtlFreeHeap (RtlGetProcessHeap(), 0, AnsiEnv.Buffer);
+       }
+       return CharCount;
+}
+/**********************************************************************
+ *     CsrpLoadKernelModeDriver/3
+ */
+static NTSTATUS
+CsrpLoadKernelModeDriver (int argc, char ** argv, char ** envp)
+{
+       NTSTATUS        Status = STATUS_SUCCESS;
+       WCHAR           Data [MAX_PATH + 1];
+       ULONG           DataLength = sizeof Data;
+       ULONG           DataType = 0;
+       UNICODE_STRING  Environment;
+
+
+       DPRINT("SM: %s called\n", __FUNCTION__);
+
+
+       EnvpToUnicodeString (envp, & Environment);      
+       Status = SmLookupSubsystem (L"Kmode",
+                                   Data,
+                                   & DataLength,
+                                   & DataType,
+                                   Environment.Buffer);
+       RtlFreeUnicodeString (& Environment);
+       if((STATUS_SUCCESS == Status) && (DataLength > sizeof Data[0]))
+       {
+               WCHAR                      ImagePath [MAX_PATH + 1] = {0};
+               UNICODE_STRING             ModuleName;
+
+               wcscpy (ImagePath, L"\\??\\");
+               wcscat (ImagePath, Data);
+               RtlInitUnicodeString (& ModuleName, ImagePath);
+               Status = NtSetSystemInformation(/* FIXME: SystemLoadAndCallImage */
+                                               SystemExtendServiceTableInformation,
+                                               & ModuleName,
+                                               sizeof ModuleName);
+               if(!NT_SUCCESS(Status))
+               {
+                       DPRINT("WIN: %s: loading Kmode failed (Status=0x%08lx)\n",
+                               __FUNCTION__, Status);
+               }
+       }
+       return Status;
+}
+
+/**********************************************************************
+ * CsrpCreateApiPort/2
+ */
+static NTSTATUS
+CsrpCreateApiPort (int argc, char ** argv, char ** envp)
+{
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       return CsrpCreateListenPort (L"\\Windows\\ApiPort",
+                                    & hApiPort,
+                                    ServerApiPortThread);
+}
+
+/**********************************************************************
+ * CsrpApiRegisterDef/0
+ */
+static NTSTATUS
+CsrpApiRegisterDef (int argc, char ** argv, char ** envp)
+{
+       return CsrApiRegisterDefinitions(NativeDefinitions);
+}
+
+/**********************************************************************
+ * CsrpCCTS/2
+ */
+static NTSTATUS
+CsrpCCTS (int argc, char ** argv, char ** envp)
+{
+    ULONG Dummy;
+    ULONG DummyLength = sizeof(Dummy);
+       return CsrClientConnectToServer(L"\\Windows",
+                       0, &Dummy, &DummyLength, NULL);
+}
+
+/**********************************************************************
+ * CsrpRunWinlogon/0
+ *
+ * Start the logon process (winlogon.exe).
+ *
+ * TODO: this should be moved in CsrpCreateSession/x (one per session)
+ * TODO: in its own desktop (one logon desktop per winstation).
+ */
+static NTSTATUS
+CsrpRunWinlogon (int argc, char ** argv, char ** envp)
+{
+       NTSTATUS                      Status = STATUS_SUCCESS;
+       UNICODE_STRING                ImagePath;
+       UNICODE_STRING                CommandLine;
+       PRTL_USER_PROCESS_PARAMETERS  ProcessParameters = NULL;
+       RTL_USER_PROCESS_INFORMATION  ProcessInfo;
+
+
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       /* initialize the process parameters */
+       RtlInitUnicodeString (& ImagePath, L"\\SystemRoot\\system32\\winlogon.exe");
+       RtlInitUnicodeString (& CommandLine, L"");
+       RtlCreateProcessParameters(& ProcessParameters,
+                                  & ImagePath,
+                                  NULL,
+                                  NULL,
+                                  & CommandLine,
+                                  NULL,
+                                  NULL,
+                                  NULL,
+                                  NULL,
+                                  NULL);
+       /* Create the winlogon process */
+       Status = RtlCreateUserProcess (& ImagePath,
+                                      OBJ_CASE_INSENSITIVE,
+                                      ProcessParameters,
+                                      NULL,
+                                      NULL,
+                                      NULL,
+                                      FALSE,
+                                      NULL,
+                                      NULL,
+                                      & ProcessInfo);
+       /* Cleanup */
+       RtlDestroyProcessParameters (ProcessParameters);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT1("SM: %s: loading winlogon.exe failed (Status=%08lx)\n",
+                               __FUNCTION__, Status);
+       }
+   ZwResumeThread(ProcessInfo.ThreadHandle, NULL);
+       return Status;
+}
+
+
+
+typedef NTSTATUS (* CSR_INIT_ROUTINE)(int,char**,char**);
+
+struct {
+       BOOL Required;
+       CSR_INIT_ROUTINE EntryPoint;
+       PCHAR ErrorMessage;
+} InitRoutine [] = {
+       {TRUE, CsrpCreateCallbackPort,   "create the callback port \\Windows\\SbApiPort"},
+       {TRUE, CsrpRegisterSubsystem,    "register with SM"},
+       {TRUE, CsrpCreateHeap,           "create the CSR heap"},
+       {TRUE, CsrpCreateApiPort,        "create the api port \\Windows\\ApiPort"},
+       {TRUE, CsrpCreateObjectDirectory,"create the object directory \\Windows"},
+       {TRUE, CsrpLoadKernelModeDriver, "load Kmode driver"},
+       {TRUE, CsrpInitVideo,            "initialize video"},
+       {TRUE, CsrpApiRegisterDef,       "initialize api definitions"},
+       {TRUE, CsrpCCTS,                 "connect client to server"},
+       {TRUE, CsrpInitWin32Csr,         "load usermode dll"},
+       {TRUE, CsrpRunWinlogon,          "run WinLogon"},
+};
 
 /**********************************************************************
  * NAME
  *     CsrServerInitialization
  *
  * DESCRIPTION
- *     Create a directory object (\windows) and a named LPC port
- *     (\windows\ApiPort)
+ *     Initialize the Win32 environment subsystem server.
  *
  * RETURN VALUE
  *     TRUE: Initialization OK; otherwise FALSE.
  */
-BOOL
-STDCALL
+BOOL STDCALL
 CsrServerInitialization (
-       ULONG ArgumentCount,
-       PWSTR *ArgumentArray
+       int argc,
+       char ** argv,
+       char ** envp
        )
 {
-  NTSTATUS Status;
-  HANDLE hSmApiPort = (HANDLE) 0;
-  OBJECT_ATTRIBUTES ObAttributes;
-  UNICODE_STRING PortName;
-  HANDLE ApiPortHandle;
-//  HANDLE hSbApiPort = (HANDLE) 0;
+       UINT       i = 0;
+       NTSTATUS  Status = STATUS_SUCCESS;
 
-DisplayString(L"CSR: CsrServerInitialization\n");
+       DPRINT("CSR: %s called\n", __FUNCTION__);
 
-  Status = CsrpRegisterSubsystem(& hSmApiPort);
-  if (! NT_SUCCESS(Status))
-    {
-      DPRINT1("CSR: Unable to register subsystem (Status: %x)\n", Status);
-      return FALSE;
-    }
-
-  Status = CsrParseCommandLine (ArgumentCount, ArgumentArray);
-  if (! NT_SUCCESS(Status))
-    {
-      DPRINT1("CSR: Unable to parse the command line (Status: %x)\n", Status);
-      return FALSE;
-    }
-
-  CsrInitVideo();
-
-  CsrssApiHeap = RtlCreateHeap(HEAP_GROWABLE,
-                               NULL,
-                               65536,
-                               65536,
-                               NULL,
-                               NULL);
-  if (CsrssApiHeap == NULL)
-    {
-      DPRINT1("CSR: Failed to create private heap, aborting\n");
-      return FALSE;
-    }
-
-  Status = CsrApiRegisterDefinitions(NativeDefinitions);
-  if (! NT_SUCCESS(Status))
-    {
-      return Status;
-    }
-
-  /* NEW NAMED PORT: \Windows\ApiPort */
-  RtlRosInitUnicodeStringFromLiteral(&PortName, L"\\Windows\\ApiPort");
-  InitializeObjectAttributes(&ObAttributes,
-                             &PortName,
-                             0,
-                             NULL,
-                             NULL);
-  Status = NtCreatePort(&ApiPortHandle,
-                        &ObAttributes,
-                        260,
-                        328,
-                        0);
-  if (! NT_SUCCESS(Status))
-    {
-      DPRINT1("CSR: Unable to create \\Windows\\ApiPort (Status %x)\n", Status);
-      return FALSE;
-    }
-  Status = RtlCreateUserThread(NtCurrentProcess(),
-                               NULL,
-                               FALSE,
-                               0,
-                               NULL,
-                               NULL,
-                               (PTHREAD_START_ROUTINE)ServerApiPortThread,
-                               ApiPortHandle,
-                               NULL,
-                               NULL);
-  if (! NT_SUCCESS(Status))
-    {
-      DPRINT1("CSR: Unable to create server thread\n");
-      NtClose(ApiPortHandle);
-      return FALSE;
-    }
-
-  /* TODO: create \Windows\SbApiPort */
-  
-  Status = CsrClientConnectToServer();
-  if (!NT_SUCCESS(Status))
-    {
-      DPRINT1("CsrClientConnectToServer() failed (Status %x)\n", Status);
-      return FALSE;
-    }
-  Status = InitWin32Csr();
-  if (! NT_SUCCESS(Status))
-    {
-      DPRINT1("CSR: Unable to load usermode dll (Status %x)\n", Status);
-      return FALSE;
-    }
-
-  if (CallInitComplete())
-  {
-#if 0
-         Status = SmCompleteSession (hSmApiPort,hSbApiPort,ApiPortHandle);
-#endif
-         NtClose (hSmApiPort);
-         return TRUE;
-  }
-  return FALSE;
+       for (i=0; i < (sizeof InitRoutine / sizeof InitRoutine[0]); i++)
+       {
+               Status = InitRoutine[i].EntryPoint(argc,argv,envp);
+               if(!NT_SUCCESS(Status))
+               {
+                       DPRINT1("CSR: %s: failed to %s (Status=%08lx)\n",
+                               __FUNCTION__,
+                               InitRoutine[i].ErrorMessage,
+                               Status);
+                       if (InitRoutine[i].Required)
+                       {
+                               return FALSE;
+                       }
+               }
+       }
+       if (CallInitComplete())
+       {
+               Status = SmCompleteSession (hSmApiPort,hSbApiPort,hApiPort);
+               return TRUE;
+       }
+       return FALSE;
 }
 
 /* EOF */