Whole new win32 console support, with multiple virtual consoles and scrollback support
authorPhillip Susi <phreak@iag.net>
Sun, 23 Apr 2000 17:44:53 +0000 (17:44 +0000)
committerPhillip Susi <phreak@iag.net>
Sun, 23 Apr 2000 17:44:53 +0000 (17:44 +0000)
svn path=/trunk/; revision=1128

reactos/subsys/csrss/api.h
reactos/subsys/csrss/api/conio.c
reactos/subsys/csrss/api/handle.c
reactos/subsys/csrss/api/process.c
reactos/subsys/csrss/api/wapi.c
reactos/subsys/csrss/csrss.c
reactos/subsys/csrss/init.c

index 6954fae..86745fb 100644 (file)
@@ -1,24 +1,49 @@
 #include <ddk/ntddk.h>
 
 #include <csrss/csrss.h>
+#include <defines.h>
+#include <structs.h>
 
-typedef struct
+/* Object type magic numbers */
+
+#define CSRSS_CONSOLE_MAGIC 1
+
+typedef struct Object_tt
+{
+   DWORD Type;
+   DWORD ReferenceCount;
+   CRITICAL_SECTION Lock;
+} Object_t;
+
+typedef struct ConsoleInput_t
+{
+  LIST_ENTRY ListEntry;
+  INPUT_RECORD InputEvent;
+} ConsoleInput;
+
+typedef struct CSRSS_CONSOLE_t
 {
-   BOOL TopLevel;
+   DWORD Type;
+   DWORD ReferenceCount;              /* Inherited from Object_t */
+   CRITICAL_SECTION Lock;
+   struct CSRSS_CONSOLE_t *Prev, *Next; /* Next and Prev consoles in console wheel */
    HANDLE ActiveEvent;
-   BYTE Screen[80*25*2];
-   ULONG ReferenceCount;
-   HANDLE LockMutant;
+   BYTE *Buffer;
+   USHORT MaxX, MaxY;          /* size of the entire scrollback buffer */
+   USHORT ShowX, ShowY;        /* beginning offset for the actual display area */
    ULONG CurrentX;
    ULONG CurrentY;
+   BYTE DefaultAttrib;        /* default char attribute */
+   LIST_ENTRY InputEvents;    /* List head for input event queue */
 } CSRSS_CONSOLE, *PCSRSS_CONSOLE;
 
 typedef struct
 {
    PCSRSS_CONSOLE Console;
    ULONG HandleTableSize;
-   PVOID* HandleTable;
+   Object_t ** HandleTable;
    ULONG ProcessId;
+   HANDLE ConsoleEvent;
 } CSRSS_PROCESS_DATA, *PCSRSS_PROCESS_DATA;
 
 VOID CsrInitProcessData(VOID);
@@ -57,24 +82,29 @@ VOID PrintString (char* fmt, ...);
 
 /* api/wapi.c */
 VOID Thread_Api(PVOID PortHandle);
+VOID Console_Api( DWORD Ignored );
 
 extern HANDLE CsrssApiHeap;
 
 /* api/conio.c */
-VOID CsrInitConsole(PCSRSS_PROCESS_DATA ProcessData,
+NTSTATUS CsrInitConsole(PCSRSS_PROCESS_DATA ProcessData,
                    PCSRSS_CONSOLE Console);
+VOID CsrDeleteConsole( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_CONSOLE Console );
 VOID CsrInitConsoleSupport(VOID);
 
 /* api/process.c */
 PCSRSS_PROCESS_DATA CsrGetProcessData(ULONG ProcessId);
-
+NTSTATUS CsrFreeProcessData( ULONG Pid );
 /* api/handle.c */
-NTSTATUS CsrInsertObject(PCSRSS_PROCESS_DATA ProcessData,
-                        PHANDLE Handle,
-                        PVOID Object);
-NTSTATUS CsrGetObject(PCSRSS_PROCESS_DATA ProcessData,
-                     HANDLE Handle,
-                     PVOID* Object);
+NTSTATUS CsrInsertObject( PCSRSS_PROCESS_DATA ProcessData, PHANDLE Handle, Object_t *Object );
+NTSTATUS CsrGetObject( PCSRSS_PROCESS_DATA ProcessData, HANDLE Handle, Object_t **Object );
 
 BOOL STDCALL CsrServerInitialization (ULONG ArgumentCount,
                                      PWSTR *ArgumentArray);
+NTSTATUS CsrReleaseObject( PCSRSS_PROCESS_DATA ProcessData, HANDLE Object );
+VOID CsrUnlockObject( Object_t *Object );
+VOID CsrDrawConsole( PCSRSS_CONSOLE Console );
+
+
+
+
index 03edb3b..659f975 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: conio.c,v 1.4 2000/04/03 21:54:41 dwelch Exp $
+/* $Id: conio.c,v 1.5 2000/04/23 17:44:53 phreak Exp $
  *
  * reactos/subsys/csrss/api/conio.c
  *
 
 #include <csrss/csrss.h>
 #include "api.h"
+#include <ntdll/rtl.h>
+#include <ddk/ntddblue.h>
 
 /* GLOBALS *******************************************************************/
 
 static HANDLE ConsoleDeviceHandle;
 static HANDLE KeyboardDeviceHandle;
+static PCSRSS_CONSOLE ActiveConsole;
+CRITICAL_SECTION ActiveConsoleLock;
+static COORD PhysicalConsoleSize;
 
 /* FUNCTIONS *****************************************************************/
 
@@ -25,13 +30,59 @@ NTSTATUS CsrAllocConsole(PCSRSS_PROCESS_DATA ProcessData,
                         PCSRSS_API_REQUEST LpcMessage,
                         PCSRSS_API_REPLY LpcReply)
 {
+   PCSRSS_CONSOLE Console;
+   HANDLE Process;
+   NTSTATUS Status;
+   CLIENT_ID ClientId;
+
    LpcReply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
    LpcReply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
      sizeof(LPC_MESSAGE_HEADER);
-
-   LpcReply->Status = STATUS_NOT_IMPLEMENTED;
-   
-   return(STATUS_NOT_IMPLEMENTED);
+   if( ProcessData->Console )
+      {
+        LpcReply->Status = STATUS_INVALID_PARAMETER;
+        return STATUS_INVALID_PARAMETER;
+      }
+   LpcReply->Status = STATUS_SUCCESS;
+   Console = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_CONSOLE ) );
+   if( Console == 0 )
+      {
+       LpcReply->Status = STATUS_INSUFFICIENT_RESOURCES;
+       return STATUS_INSUFFICIENT_RESOURCES;
+      }
+   LpcReply->Status = CsrInitConsole( ProcessData, Console );
+   if( !NT_SUCCESS( LpcReply->Status ) )
+     {
+       RtlFreeHeap( CsrssApiHeap, 0, Console );
+       return LpcReply->Status;
+     }
+   ProcessData->Console = Console;
+   Console->ReferenceCount++;
+   CsrInsertObject( ProcessData, &LpcReply->Data.AllocConsoleReply.ConsoleHandle, (Object_t *)Console );
+   ClientId.UniqueProcess = (HANDLE)ProcessData->ProcessId;
+   Status = NtOpenProcess( &Process, PROCESS_DUP_HANDLE, 0, &ClientId );
+   if( !NT_SUCCESS( Status ) )
+     {
+       DbgPrint( "CSR: NtOpenProcess() failed for handle duplication\n" );
+       Console->ReferenceCount--;
+       ProcessData->Console = 0;
+       CsrReleaseObject( ProcessData, LpcReply->Data.AllocConsoleReply.ConsoleHandle );
+       LpcReply->Status = Status;
+       return Status;
+     }
+   Status = NtDuplicateObject( NtCurrentProcess(), &ProcessData->Console->ActiveEvent, Process, &ProcessData->ConsoleEvent, SYNCHRONIZE, FALSE, 0 );
+   if( !NT_SUCCESS( Status ) )
+     {
+       DbgPrint( "CSR: NtDuplicateObject() failed\n" );
+       NtClose( Process );
+       Console->ReferenceCount--;
+       CsrReleaseObject( ProcessData, LpcReply->Data.AllocConsoleReply.ConsoleHandle );
+       ProcessData->Console = 0;
+       LpcReply->Status = Status;
+       return Status;
+     }
+   NtClose( Process );
+   return STATUS_SUCCESS;
 }
 
 NTSTATUS CsrFreeConsole(PCSRSS_PROCESS_DATA ProcessData,
@@ -51,14 +102,12 @@ NTSTATUS CsrReadConsole(PCSRSS_PROCESS_DATA ProcessData,
                        PCSRSS_API_REQUEST LpcMessage,
                        PCSRSS_API_REPLY LpcReply)
 {
-   KEY_EVENT_RECORD KeyEventRecord;
+   PINPUT_RECORD Input;
    PCHAR Buffer;
    int   i;
    ULONG nNumberOfCharsToRead;
+   PCSRSS_CONSOLE Console;
    NTSTATUS Status;
-   IO_STATUS_BLOCK Iosb;
-   
-//   DbgPrint("CSR: CsrReadConsole()\n");
    
    nNumberOfCharsToRead = 
      LpcMessage->Data.ReadConsoleRequest.NrCharactersToRead;
@@ -70,79 +119,296 @@ NTSTATUS CsrReadConsole(PCSRSS_PROCESS_DATA ProcessData,
    LpcReply->Header.DataSize = LpcReply->Header.MessageSize -
      sizeof(LPC_MESSAGE_HEADER);
    Buffer = LpcReply->Data.ReadConsoleReply.Buffer;
+   LpcReply->Data.ReadConsoleReply.EventHandle = ProcessData->ConsoleEvent;
    
-   Status = STATUS_SUCCESS;
-   
-   for (i=0; (NT_SUCCESS(Status) && i<nNumberOfCharsToRead);)     
+   Status = CsrGetObject( ProcessData, LpcMessage->Data.ReadConsoleRequest.ConsoleHandle, (Object_t **)&Console );
+   if( !NT_SUCCESS( Status ) )
+      {
+        LpcReply->Status = Status;
+        return Status;
+      }
+   for (i=0; i<nNumberOfCharsToRead && Console->InputEvents.Flink != &Console->InputEvents; i++ )     
      {
-//     DbgPrint("CSR: Doing read file (KeyboardDeviceHandle %x)\n",
-//              KeyboardDeviceHandle);
-       Status = NtReadFile(KeyboardDeviceHandle,
-                           NULL,
-                           NULL,
-                           NULL,
-                           &Iosb,
-                           &KeyEventRecord,
-                           sizeof(KEY_EVENT_RECORD),
-                           NULL,
-                           0);
-       if (!NT_SUCCESS(Status))
-         {
-//          DbgPrint("CSR: Read failed, bailing\n");
-         }
-        if (KeyEventRecord.bKeyDown && KeyEventRecord.uChar.AsciiChar != 0)
-         {
-            Buffer[i] = KeyEventRecord.uChar.AsciiChar;
-//          DbgPrint("CSR: Read '%c'\n", Buffer[i]);
-            i++;
-         }
+       Input = &((ConsoleInput *)Console->InputEvents.Flink)->InputEvent;
+       Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
+       Console->InputEvents.Flink->Blink = &Console->InputEvents;
+       Buffer[i] = Input->Event.KeyEvent.uChar.AsciiChar;
+       RtlFreeHeap( CsrssApiHeap, 0, Input );
      }
+   CsrUnlockObject( (Object_t *)Console );
    LpcReply->Data.ReadConsoleReply.NrCharactersRead = i;
-   LpcReply->Status = Status;
+   LpcReply->Status = i ? STATUS_SUCCESS : STATUS_PENDING;
    return(Status);
 }
 
 
+
 NTSTATUS CsrWriteConsole(PCSRSS_PROCESS_DATA ProcessData,
                         PCSRSS_API_REQUEST Message,
                         PCSRSS_API_REPLY LpcReply)
 {
    IO_STATUS_BLOCK Iosb;
    NTSTATUS Status;
+   int i;
+   BYTE *Buffer = Message->Data.WriteConsoleRequest.Buffer;
+   PCSRSS_CONSOLE Console;
    
    LpcReply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
    LpcReply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
      sizeof(LPC_MESSAGE_HEADER);
 
-//   DbgPrint("CSR: CsrWriteConsole()\n");
-//   DbgPrint("CSR: ConsoleDeviceHandle %x\n", ConsoleDeviceHandle);
-//   DbgPrint("CSR: NrCharactersToWrite %d\n",
-//         Message->Data.WriteConsoleRequest.NrCharactersToWrite);
-//   DbgPrint("CSR: Buffer %s\n",
-//         Message->Data.WriteConsoleRequest.Buffer);
-   
-   Status = NtWriteFile(ConsoleDeviceHandle,
-                       NULL,
-                       NULL,
-                       NULL,
-                       &Iosb,
-                       Message->Data.WriteConsoleRequest.Buffer,
-                       Message->Data.WriteConsoleRequest.NrCharactersToWrite,
-                       NULL,
-                       0);
-   if (!NT_SUCCESS(Status))
-     {
-//     DbgPrint("CSR: Write failed\n");
-       return(Status);
-     }
-   LpcReply->Data.WriteConsoleReply.NrCharactersWritten = Iosb.Information;
+   if( !NT_SUCCESS( CsrGetObject( ProcessData, Message->Data.WriteConsoleRequest.ConsoleHandle, (Object_t **)&Console ) ) )
+     return LpcReply->Status = STATUS_INVALID_HANDLE;
+   for( i = 0; i < Message->Data.WriteConsoleRequest.NrCharactersToWrite; i++ )
+      {
+        switch( Buffer[ i ] )
+           {
+           case '\n': {
+              int c;
+              Console->CurrentX = 0;
+              /* slide the viewable screen */
+              if( ((PhysicalConsoleSize.Y + Console->ShowY) % Console->MaxY) == (Console->CurrentY + 1) )
+                if( ++Console->ShowY == (Console->MaxY - 1) )
+                  Console->ShowY = 0;
+              if( ++Console->CurrentY == Console->MaxY )
+                 {
+                    Console->CurrentY = 0;
+                    for( c = 0; c < Console->MaxX; c++ )
+                       {
+                          /* clear new line */
+                          Console->Buffer[ c * 2 ] = ' ';
+                          Console->Buffer[ (c * 2) + 1 ] = Console->DefaultAttrib;
+                       }
+                 }
+              else for( c = 0; c < Console->MaxX; c++ )
+                 {
+                    /* clear new line */
+                    Console->Buffer[ 2 * ((Console->CurrentY * Console->MaxX) + c) ] = ' ';
+                    Console->Buffer[ (2 * ((Console->CurrentY * Console->MaxX) + c)) + 1 ] = Console->DefaultAttrib;
+                 }
+              break;
+           }
+           case '\b': {
+             if( Console->CurrentX == 0 )
+               {
+                 /* slide viewable screen up */
+                 if( Console->ShowY == Console->CurrentY )
+                   if( Console->ShowY == 0 )
+                     Console->ShowY = Console->MaxY;
+                   else Console->ShowY--;
+                 /* slide virtual position up */
+                 Console->CurrentX = Console->MaxX;
+                 if( Console->CurrentY == 0 )
+                   Console->CurrentY = Console->MaxY;
+                 else Console->CurrentY--;
+               }
+             else Console->CurrentX--;
+             Console->Buffer[ 2 * ((Console->CurrentY * Console->MaxX) + Console->CurrentX) ] = ' ';
+             Console->Buffer[ (2 * ((Console->CurrentY * Console->MaxX) + Console->CurrentX)) + 1 ] = Console->DefaultAttrib;
+             break;
+           }
+           default: {
+              int c;
+              Console->Buffer[ 2 * (((Console->CurrentY * Console->MaxX)) + Console->CurrentX) ] = Buffer[ i ];
+              Console->Buffer[ (2 * ((Console->CurrentY * Console->MaxX) + Console->CurrentX)) + 1 ] = Console->DefaultAttrib;
+              Console->CurrentX++;
+              if( Console->CurrentX == Console->MaxX )
+                 {
+                    /* if end of line, go to next */
+                    Console->CurrentX = 0;
+                    if( ++Console->CurrentY == Console->MaxY )
+                       {
+                          /* if end of buffer, wrap back to beginning */
+                          Console->CurrentY = 0;
+                          /* clear new line */
+                          for( c = 0; c < Console->MaxX; c++ )
+                             {
+                                Console->Buffer[ 2 * ((Console->CurrentY * Console->MaxX) + c) ] = ' ';
+                                Console->Buffer[ (2 * ((Console->CurrentY * Console->MaxX) + c)) + 1 ] = Console->DefaultAttrib;
+                             }
+                       }
+                    else {
+                       /* clear new line */
+                       for( c = 0; c < Console->MaxX; c += 2 )
+                          {
+                             Console->Buffer[ 2 * ((Console->CurrentY * Console->MaxX) + c) ] = ' ';
+                             Console->Buffer[ (2 * ((Console->CurrentY * Console->MaxX) + c)) + 1 ] = Console->DefaultAttrib;
+                          }
+                    }
+                    /* slide the viewable screen */
+                    if( (Console->CurrentY - Console->ShowY) == PhysicalConsoleSize.Y )
+                      if( ++Console->ShowY == Console->MaxY )
+                        Console->ShowY = 0;
+                 }
+           }
+           }
+      }
+   CsrUnlockObject( (Object_t *)Console );
+   RtlEnterCriticalSection( &ActiveConsoleLock );
+   if( Console == ActiveConsole )
+     {    /* only write to screen if Console is Active, and not scrolled up */
+        Status = NtWriteFile(ConsoleDeviceHandle,
+                             NULL,
+                             NULL,
+                             NULL,
+                             &Iosb,
+                             Message->Data.WriteConsoleRequest.Buffer,
+                             Message->Data.WriteConsoleRequest.NrCharactersToWrite,
+                             NULL,
+                             0);
+        if (!NT_SUCCESS(Status))
+              DbgPrint("CSR: Write failed\n");
+      }
+   RtlLeaveCriticalSection( &ActiveConsoleLock );
+   LpcReply->Data.WriteConsoleReply.NrCharactersWritten = i;
    LpcReply->Status = STATUS_SUCCESS;
    return(STATUS_SUCCESS);
 }
 
-VOID CsrInitConsole(PCSRSS_PROCESS_DATA ProcessData,
+NTSTATUS CsrInitConsole(PCSRSS_PROCESS_DATA ProcessData,
                    PCSRSS_CONSOLE Console)
 {
+  NTSTATUS Status;
+  
+  Console->MaxX = PhysicalConsoleSize.X;
+  Console->MaxY = PhysicalConsoleSize.Y * 2;
+  Console->ShowX = 0;
+  Console->ShowY = 0;
+  Console->CurrentX = 0;
+  Console->CurrentY = 0;
+  Console->ReferenceCount = 0;
+  Console->Type = CSRSS_CONSOLE_MAGIC;
+  RtlInitializeCriticalSection( &Console->Lock );
+  Console->Buffer = RtlAllocateHeap( CsrssApiHeap, 0, Console->MaxX * Console->MaxY * 2 );
+  if( Console->Buffer == 0 )
+    return STATUS_INSUFFICIENT_RESOURCES;
+  Console->InputEvents.Flink = Console->InputEvents.Blink = &Console->InputEvents;
+  Status = NtCreateEvent( &Console->ActiveEvent, STANDARD_RIGHTS_ALL, 0, FALSE, FALSE );
+  if( !NT_SUCCESS( Status ) )
+    {
+      RtlFreeHeap( CsrssApiHeap, 0, Console->Buffer );
+      return Status;
+    }
+  Console->DefaultAttrib = 0x17;
+  /* initialize buffer to be empty with default attributes */
+  for( ; Console->CurrentY < Console->MaxY; Console->CurrentY++ )
+    {
+      for( ; Console->CurrentX < Console->MaxX; Console->CurrentX++ )
+       {
+         Console->Buffer[ (Console->CurrentX * 2) + (Console->CurrentY * Console->MaxX * 2) ] = ' ';
+         Console->Buffer[ (Console->CurrentX * 2) + (Console->CurrentY * Console->MaxX * 2)+ 1 ] = Console->DefaultAttrib;
+       }
+      Console->CurrentX = 0;
+    }
+  /* make console active, and insert into console list */
+  RtlEnterCriticalSection( &ActiveConsoleLock );
+  if( ActiveConsole )
+     {
+       Console->Prev = ActiveConsole;
+       Console->Next = ActiveConsole->Next;
+       ActiveConsole->Next->Prev = Console;
+       ActiveConsole->Next = Console;
+     }
+  else {
+     Console->Prev = Console;
+     Console->Next = Console;
+  }
+  Console->CurrentX = 0;
+  Console->CurrentY = 0;
+  ActiveConsole = Console;
+  /* copy buffer contents to screen */
+  CsrDrawConsole( Console );
+  RtlLeaveCriticalSection( &ActiveConsoleLock );
+  return STATUS_SUCCESS;
+}
+
+/***************************************************************
+ *  CsrDrawConsole blasts the console buffer onto the screen   *
+ *  must be called while holding the active console lock       *
+ **************************************************************/
+VOID CsrDrawConsole( PCSRSS_CONSOLE Console )
+{
+   IO_STATUS_BLOCK Iosb;
+   NTSTATUS Status;
+   CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
+   CONSOLE_MODE Mode;
+   int i, y;
+
+   /* first set position to 0,0 */
+   ScrInfo.dwCursorPosition.X = 0;
+   ScrInfo.dwCursorPosition.Y = 0;
+   ScrInfo.wAttributes = Console->DefaultAttrib;
+   Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
+   if( !NT_SUCCESS( Status ) )
+     {
+       DbgPrint( "CSR: Failed to set console info\n" );
+       return;
+     }
+   Mode.dwMode = 0; /* clear ENABLE_PROCESSED_OUTPUT mode */
+   Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_MODE, &Mode, sizeof( Mode ), 0, 0 );
+   if( !NT_SUCCESS( Status ) )
+     {
+       DbgPrint( "CSR: Failed to set console mode\n" );
+       return;
+     }
+   /* blast out buffer */
+   for( i = 0, y = Console->ShowY; i < PhysicalConsoleSize.Y; i++ )
+     {
+       Status = NtWriteFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, &Console->Buffer[ (Console->ShowX * 2) + (y * Console->MaxX * 2) ], PhysicalConsoleSize.X * 2, 0, 0 );
+       if( !NT_SUCCESS( Status ) )
+        {
+          DbgPrint( "CSR: Write to console failed\n" );
+          return;
+        }
+       /* wrap back around the end of the buffer */
+       if( ++y == Console->MaxY )
+        y = 0;
+     }
+   Mode.dwMode = ENABLE_PROCESSED_OUTPUT;
+   Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_MODE, &Mode, sizeof( Mode ), 0, 0 );
+   if( !NT_SUCCESS( Status ) )
+     {
+       DbgPrint( "CSR: Failed to set console mode\n" );
+       return;
+     }
+   ScrInfo.dwCursorPosition.X = Console->CurrentX - Console->ShowX;
+   ScrInfo.dwCursorPosition.Y = ((Console->CurrentY + Console->MaxY) - Console->ShowY) % Console->MaxY;
+   Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
+   if( !NT_SUCCESS( Status ) )
+     {
+       DbgPrint( "CSR: Failed to set console info\n" );
+       return;
+     }
+}
+
+       
+VOID CsrDeleteConsole( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_CONSOLE Console )
+{
+   ConsoleInput *Event;
+   RtlFreeHeap( CsrssApiHeap, 0, Console->Buffer );
+   while( Console->InputEvents.Flink != &Console->InputEvents )
+      {
+        Event = (ConsoleInput *)Console->InputEvents.Flink;
+        Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
+        Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
+        RtlFreeHeap( CsrssApiHeap, 0, Event );
+      }
+   RtlEnterCriticalSection( &ActiveConsoleLock );
+   if( ActiveConsole == Console )
+      {
+        if( Console->Next != Console )
+           {
+              ActiveConsole = Console->Next;
+              Console->Prev->Next = Console->Next;
+              Console->Next->Prev = Console->Prev;
+           }
+        else ActiveConsole = 0;
+      }
+   if( ActiveConsole )
+     CsrDrawConsole( ActiveConsole );
+   RtlLeaveCriticalSection( &ActiveConsoleLock );
+   NtClose( Console->ActiveEvent );
+   RtlDeleteCriticalSection( &Console->Lock );
 }
 
 VOID CsrInitConsoleSupport(VOID)
@@ -151,6 +417,7 @@ VOID CsrInitConsoleSupport(VOID)
    UNICODE_STRING DeviceName;
    NTSTATUS Status;
    IO_STATUS_BLOCK Iosb;
+   CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
    
    DbgPrint("CSR: CsrInitConsoleSupport()\n");
    
@@ -189,7 +456,99 @@ VOID CsrInitConsoleSupport(VOID)
        DbgPrint("CSR: Failed to open keyboard. Expect problems.\n");
      }
    
-   DbgPrint("CSR: KeyboardDeviceHandle %x\n", KeyboardDeviceHandle);
+   ActiveConsole = 0;
+   RtlInitializeCriticalSection( &ActiveConsoleLock );
+   Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, &ScrInfo, sizeof( ScrInfo ) );
+   if( !NT_SUCCESS( Status ) )
+     {
+       DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
+       return;
+     }
+   PhysicalConsoleSize = ScrInfo.dwSize;
+}
+
+VOID Console_Api( DWORD Ignored )
+{
+  /* keep reading events from the keyboard and stuffing them into the current
+     console's input queue */
+  ConsoleInput *KeyEventRecord;
+  IO_STATUS_BLOCK Iosb;
+  NTSTATUS Status;
+  while( 1 )
+    {
+      KeyEventRecord = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( ConsoleInput ) );
+      if( KeyEventRecord == 0 )
+       {
+         DbgPrint( "CSR: Memory allocation failure!" );
+         continue;
+       }
+      KeyEventRecord->InputEvent.EventType = KEY_EVENT;
+      Status = NtReadFile( KeyboardDeviceHandle, NULL, NULL, NULL, &Iosb, &KeyEventRecord->InputEvent.Event.KeyEvent, sizeof( KEY_EVENT_RECORD ), NULL, 0 );
+      if( !NT_SUCCESS( Status ) )
+       {
+         DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
+         continue;
+       }
+      //      DbgPrint( "Char: %c\n", KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar );
+      if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) && KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
+       {
+         if( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == 'q' )
+           {
+             /* alt-tab, swap consoles */
+             RtlEnterCriticalSection( &ActiveConsoleLock );
+             if( ActiveConsole->Next != ActiveConsole )
+               ActiveConsole = ActiveConsole->Next;
+             CsrDrawConsole( ActiveConsole );
+             RtlLeaveCriticalSection( &ActiveConsoleLock );
+             continue;
+           }
+         else if( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP || KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN )
+           {
+             /* scroll up or down */
+             RtlEnterCriticalSection( &ActiveConsoleLock );
+             if( ActiveConsole == 0 )
+               {
+                 DbgPrint( "CSR: No Active Console!\n" );
+                 continue;
+               }
+             RtlEnterCriticalSection( &ActiveConsole->Lock );
+             if( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP )
+               {
+                 /* only scroll up if there is room to scroll up into */
+                 if( ActiveConsole->ShowY != ((ActiveConsole->CurrentY + 1) % ActiveConsole->MaxY) )
+                   ActiveConsole->ShowY = (ActiveConsole->ShowY + ActiveConsole->MaxY - 1) % ActiveConsole->MaxY;
+               }
+             else if( ActiveConsole->ShowY != ActiveConsole->CurrentY )
+               /* only scroll down if there is room to scroll down into */
+               if( ActiveConsole->ShowY % ActiveConsole->MaxY != ActiveConsole->CurrentY )
+                 if( ((ActiveConsole->CurrentY + 1) % ActiveConsole->MaxY) != (ActiveConsole->ShowY + PhysicalConsoleSize.Y) % ActiveConsole->MaxY )
+                   ActiveConsole->ShowY = (ActiveConsole->ShowY + 1) % ActiveConsole->MaxY;
+             CsrDrawConsole( ActiveConsole );
+             RtlLeaveCriticalSection( &ActiveConsole->Lock );
+             RtlLeaveCriticalSection( &ActiveConsoleLock );
+           }
+       }
+      if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
+        continue;
+      /* ignore dead keys */
+      if( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == 0 )
+        continue;
+      RtlEnterCriticalSection( &ActiveConsoleLock );
+      if( ActiveConsole == 0 )
+       {
+         DbgPrint( "CSR: No Active Console!\n" );
+         continue;
+       }
+      RtlEnterCriticalSection( &ActiveConsole->Lock );
+      KeyEventRecord->ListEntry.Flink = &ActiveConsole->InputEvents;
+      KeyEventRecord->ListEntry.Blink = ActiveConsole->InputEvents.Blink;
+      ActiveConsole->InputEvents.Blink->Flink = &KeyEventRecord->ListEntry;
+      ActiveConsole->InputEvents.Blink = &KeyEventRecord->ListEntry;
+      NtSetEvent( ActiveConsole->ActiveEvent, 0 );
+    }
+  RtlLeaveCriticalSection( &ActiveConsoleLock );
 }
 
+
 /* EOF */
+
index cfaddef..0eca26a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: handle.c,v 1.5 2000/03/26 22:00:10 dwelch Exp $
+/* $Id: handle.c,v 1.6 2000/04/23 17:44:53 phreak Exp $
  *
  * reactos/subsys/csrss/api/handle.c
  *
 
 #include <csrss/csrss.h>
 #include "api.h"
+#include <ntdll/rtl.h>
 
 /* FUNCTIONS *****************************************************************/
 
-NTSTATUS CsrGetObject(PCSRSS_PROCESS_DATA ProcessData,
-                     HANDLE Handle,
-                     PVOID* Object)
+NTSTATUS CsrGetObject( PCSRSS_PROCESS_DATA ProcessData, HANDLE Handle, Object_t **Object )
 {
+  //   DbgPrint( "CsrGetObject, Object: %x, %x, %x\n", Object, Handle, ProcessData->HandleTableSize );
+   if( (((ULONG)Handle) >> 2) - 1 > ProcessData->HandleTableSize )
+     {
+       DbgPrint( "CsrGetObject returning invalid handle\n" );
+       return STATUS_INVALID_HANDLE;
+     }
    *Object = ProcessData->HandleTable[(((ULONG)Handle) >> 2) - 1];
-   return(STATUS_SUCCESS);
+   RtlEnterCriticalSection( &(*Object)->Lock );
+   //   DbgPrint( "CsrGetObject returning\n" );
+   return *Object ? STATUS_SUCCESS : STATUS_INVALID_HANDLE;
+}
+
+VOID CsrUnlockObject( Object_t *Object )
+{
+   RtlLeaveCriticalSection( &Object->Lock );
 }
 
 NTSTATUS CsrReleaseObject(PCSRSS_PROCESS_DATA ProcessData,
-                         PVOID Object)
+                         HANDLE Handle)
 {
+   Object_t *Object;
+   //   DbgPrint( "CsrReleaseObject\n" );
+   if( (((ULONG)Handle) >> 2) - 1 > ProcessData->HandleTableSize || ProcessData->HandleTable[(((ULONG)Handle) >> 2) - 1] == 0 )
+      return STATUS_INVALID_HANDLE;
+   /* dec ref count */
+   Object = ProcessData->HandleTable[(((ULONG)Handle) >> 2) - 1];
+   RtlEnterCriticalSection( &Object->Lock );
+   if( --Object->ReferenceCount == 0 )
+      switch( Object->Type )
+        {
+        case CSRSS_CONSOLE_MAGIC: CsrDeleteConsole( ProcessData, (PCSRSS_CONSOLE) Object );
+          DbgPrint( "Deleting Console\n" );
+           break;
+        default: DbgPrint( "CSR: Error: releaseing unknown object type" );
+        }
+   DbgPrint( "Deleting object, refcount: %d\n", Object->ReferenceCount );
+   ProcessData->HandleTable[(((ULONG)Handle) >> 2) - 1] = 0;
+   RtlLeaveCriticalSection( &Object->Lock );
+   return STATUS_SUCCESS;
 }
 
-NTSTATUS CsrInsertObject(PCSRSS_PROCESS_DATA ProcessData,
-                        PHANDLE Handle,
-                        PVOID Object)
+NTSTATUS CsrInsertObject( PCSRSS_PROCESS_DATA ProcessData, PHANDLE Handle, Object_t *Object )
 {
    ULONG i;
    PVOID* NewBlock;
-   
+
+   //   DbgPrint( "CsrInsertObject\n" );
    for (i = 0; i < ProcessData->HandleTableSize; i++)
      {
        if (ProcessData->HandleTable[i] == NULL)
          {
             ProcessData->HandleTable[i] = Object;
             *Handle = (HANDLE)(((i + 1) << 2) | 0x3);
+            Object->ReferenceCount++;
             return(STATUS_SUCCESS);
          }
      }
@@ -56,10 +87,14 @@ NTSTATUS CsrInsertObject(PCSRSS_PROCESS_DATA ProcessData,
    RtlCopyMemory(NewBlock, 
                 ProcessData->HandleTable,
                 ProcessData->HandleTableSize * sizeof(HANDLE));
-   ProcessData->HandleTable = NewBlock;
+   RtlFreeHeap( CsrssApiHeap, 0, ProcessData->HandleTable );
+   ProcessData->HandleTable = (Object_t **)NewBlock;
    ProcessData->HandleTable[i] = Object;   
    *Handle = (HANDLE)(((i + 1) << 2) | 0x3);
+   Object->ReferenceCount++;
    ProcessData->HandleTableSize = ProcessData->HandleTableSize + 64;
-   
    return(STATUS_SUCCESS);
 }
+
+
+
index ceb07e5..8c760da 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.7 2000/04/03 21:54:41 dwelch Exp $
+/* $Id: process.c,v 1.8 2000/04/23 17:44:53 phreak Exp $
  *
  * reactos/subsys/csrss/api/process.c
  *
@@ -12,7 +12,7 @@
 #include <ddk/ntddk.h>
 
 #include <csrss/csrss.h>
-
+#include <ntdll/rtl.h>
 #include "api.h"
 
 /* GLOBALS *******************************************************************/
@@ -64,13 +64,48 @@ PCSRSS_PROCESS_DATA CsrGetProcessData(ULONG ProcessId)
    return(NULL);
 }
 
+NTSTATUS CsrFreeProcessData( ULONG Pid )
+{
+   int i;
+   for( i = 0; i < NrProcess; i++ )
+      {
+        if( ProcessData[i] && ProcessData[i]->ProcessId == Pid )
+           {
+              if( ProcessData[i]->HandleTable )
+                 {
+                    int c;
+                    for( c = 0; c < ProcessData[i]->HandleTableSize; c++ )
+                       if( ProcessData[i]->HandleTable[c] )
+                         CsrReleaseObject( ProcessData[i], (HANDLE)((c + 1) << 2) );
+                    RtlFreeHeap( CsrssApiHeap, 0, ProcessData[i]->HandleTable );
+                 }
+              if( ProcessData[i]->Console )
+                 {
+                    RtlEnterCriticalSection( &ProcessData[i]->Console->Lock );
+                    if( --ProcessData[i]->Console->ReferenceCount == 0 )
+                       {
+                          RtlLeaveCriticalSection( &ProcessData[i]->Console->Lock );
+                          CsrDeleteConsole( ProcessData[i], ProcessData[i]->Console );
+                       }
+                    RtlLeaveCriticalSection( &ProcessData[i]->Console->Lock );
+                 }
+              RtlFreeHeap( CsrssApiHeap, 0, ProcessData[i] );
+              ProcessData[i] = 0;
+              return STATUS_SUCCESS;
+           }
+      }
+   return STATUS_INVALID_PARAMETER;
+}
+
 
 NTSTATUS CsrCreateProcess (PCSRSS_PROCESS_DATA ProcessData,
                           PCSRSS_CREATE_PROCESS_REQUEST Request,
                           PCSRSS_API_REPLY Reply)
 {
    PCSRSS_PROCESS_DATA NewProcessData;
-   
+   NTSTATUS Status;
+   HANDLE Process;
+
    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - 
      sizeof(LPC_MESSAGE_HEADER);
    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
@@ -97,18 +132,43 @@ NTSTATUS CsrCreateProcess (PCSRSS_PROCESS_DATA ProcessData,
        CsrInitConsole(ProcessData,
                       Console);
        NewProcessData->Console = Console;
+       Console->ReferenceCount++;
      }
    else
      {
        NewProcessData->Console = ProcessData->Console;
+       RtlEnterCriticalSection( &ProcessData->Console->Lock );
+       ProcessData->Console->ReferenceCount++;
+       RtlLeaveCriticalSection( &ProcessData->Console->Lock );
      }
    
-   CsrInsertObject(NewProcessData,
-                  &Reply->Data.CreateProcessReply.ConsoleHandle,
-                  NewProcessData->Console);
-   
-//   DbgPrint("CSR: ConsoleHandle %x\n",
-//         Reply->Data.CreateProcessReply.ConsoleHandle);
+   if( NewProcessData->Console )
+     {
+       CLIENT_ID ClientId;
+       CsrInsertObject(NewProcessData,
+                      &Reply->Data.CreateProcessReply.ConsoleHandle,
+                      (Object_t *)NewProcessData->Console);
+       ClientId.UniqueProcess = (HANDLE)NewProcessData->ProcessId;
+       Status = NtOpenProcess( &Process, PROCESS_DUP_HANDLE, 0, &ClientId );
+       if( !NT_SUCCESS( Status ) )
+        {
+          DbgPrint( "CSR: NtOpenProcess() failed for handle duplication\n" );
+          CsrFreeProcessData( NewProcessData->ProcessId );
+          Reply->Status = Status;
+          return Status;
+        }
+       Status = NtDuplicateObject( NtCurrentProcess(), &NewProcessData->Console->ActiveEvent, Process, &NewProcessData->ConsoleEvent, SYNCHRONIZE, FALSE, 0 );
+       if( !NT_SUCCESS( Status ) )
+        {
+          DbgPrint( "CSR: NtDuplicateObject() failed\n" );
+          NtClose( Process );
+          CsrFreeProcessData( NewProcessData->ProcessId );
+          Reply->Status = Status;
+          return Status;
+        }
+       NtClose( Process );
+     }
+   else Reply->Data.CreateProcessReply.ConsoleHandle = INVALID_HANDLE_VALUE;
 //   DisplayString(L"CSR: Did CreateProcess successfully\n");
 //   DbgPrint("Reply->Header.MessageSize %d\n", Reply->Header.MessageSize);
    
index 6187d08..49fac5f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: wapi.c,v 1.6 2000/04/03 21:54:41 dwelch Exp $
+/* $Id: wapi.c,v 1.7 2000/04/23 17:44:53 phreak Exp $
  * 
  * reactos/subsys/csrss/api/wapi.c
  *
@@ -46,7 +46,8 @@ static void Thread_Api2(HANDLE ServerPort)
        
        if (LpcRequest.Header.MessageType == LPC_PORT_CLOSED)
          {
-//          DbgPrint("Client closed port\n");
+            DbgPrint("Client closed port\n");
+            CsrFreeProcessData( LpcRequest.Header.Cid.UniqueProcess );
             NtClose(ServerPort);
             NtTerminateThread(NtCurrentThread(), STATUS_SUCCESS);
          }
@@ -127,20 +128,7 @@ void Thread_Api(PVOID PortHandle)
    HANDLE ServerPort;
    HANDLE ServerThread;
    
-   CsrssApiHeap = RtlCreateHeap(HEAP_GROWABLE,
-                               NULL,
-                               65536,
-                               65536,
-                               NULL,
-                               NULL);
-   if (CsrssApiHeap == NULL)
-     {
-       PrintString("CSR: Failed to create private heap, aborting\n");
-       return;
-     }
-
    CsrInitProcessData();
-   CsrInitConsoleSupport();
    
    for (;;)
      {
index df8aecd..e99abd3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: csrss.c,v 1.6 2000/03/22 18:35:58 dwelch Exp $
+/* $Id: csrss.c,v 1.7 2000/04/23 17:44:53 phreak Exp $
  *
  * csrss.c - Client/Server Runtime subsystem
  * 
@@ -106,7 +106,7 @@ VOID NtProcessStartup(PPEB Peb)
      {
        DbgPrint("CSR: Failed to open csrss notification event\n");
      }
-   
+   DbgPrint( "foof\n" );
    if (CsrServerInitialization (argc, argv) == TRUE)
      {
        DisplayString( L"CSR: Subsystem initialized.\n" );
index 0423c99..58bd906 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.7 2000/03/22 18:35:58 dwelch Exp $
+/* $Id: init.c,v 1.8 2000/04/23 17:44:53 phreak Exp $
  * 
  * reactos/subsys/csrss/init.c
  *
@@ -33,6 +33,7 @@ HANDLE CsrSbApiPort = INVALID_HANDLE_VALUE;
 
 UNICODE_STRING CsrDirectoryName;
 
+extern HANDLE CsrssApiHeap;
 
 static NTSTATUS
 CsrParseCommandLine (
@@ -120,7 +121,19 @@ CsrServerInitialization (
        PrintString("CSR: Unable to create \\ApiPort (Status %x)\n", Status);
        return(FALSE);
      }
+   CsrssApiHeap = RtlCreateHeap(HEAP_GROWABLE,
+                               NULL,
+                               65536,
+                               65536,
+                               NULL,
+                               NULL);
+   if (CsrssApiHeap == NULL)
+     {
+       PrintString("CSR: Failed to create private heap, aborting\n");
+       return FALSE;
+     }
 
+   CsrInitConsoleSupport();
    Status = RtlCreateUserThread(NtCurrentProcess(),
                                NULL,
                                FALSE,
@@ -137,7 +150,12 @@ CsrServerInitialization (
        NtClose(ApiPortHandle);
        return FALSE;
      }
-   
+   Status = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, 0, NULL, NULL, (PTHREAD_START_ROUTINE)Console_Api, 0, NULL, NULL );
+   if( !NT_SUCCESS( Status ) )
+     {
+       PrintString( "CSR: Unable to create console thread\n" );
+       return FALSE;
+     }
    return TRUE;
 }