From cdd3a57119066e9192be3a7a4ca2be104c695e6b Mon Sep 17 00:00:00 2001 From: Phillip Susi Date: Sun, 23 Apr 2000 17:44:53 +0000 Subject: [PATCH] Whole new win32 console support, with multiple virtual consoles and scrollback support svn path=/trunk/; revision=1128 --- reactos/subsys/csrss/api.h | 58 +++- reactos/subsys/csrss/api/conio.c | 475 +++++++++++++++++++++++++---- reactos/subsys/csrss/api/handle.c | 59 +++- reactos/subsys/csrss/api/process.c | 78 ++++- reactos/subsys/csrss/api/wapi.c | 18 +- reactos/subsys/csrss/csrss.c | 4 +- reactos/subsys/csrss/init.c | 22 +- 7 files changed, 602 insertions(+), 112 deletions(-) diff --git a/reactos/subsys/csrss/api.h b/reactos/subsys/csrss/api.h index 6954fae3e63..86745fb7128 100644 --- a/reactos/subsys/csrss/api.h +++ b/reactos/subsys/csrss/api.h @@ -1,24 +1,49 @@ #include #include +#include +#include -typedef struct +/* Object type magic numbers */ + +#define CSRSS_CONSOLE_MAGIC 1 + +typedef struct Object_tt { - BOOL TopLevel; + 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 +{ + 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 ); + + + + diff --git a/reactos/subsys/csrss/api/conio.c b/reactos/subsys/csrss/api/conio.c index 03edb3bb3e4..659f975424c 100644 --- a/reactos/subsys/csrss/api/conio.c +++ b/reactos/subsys/csrss/api/conio.c @@ -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 * @@ -13,11 +13,16 @@ #include #include "api.h" +#include +#include /* 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) && iData.ReadConsoleRequest.ConsoleHandle, (Object_t **)&Console ); + if( !NT_SUCCESS( Status ) ) + { + LpcReply->Status = Status; + return Status; + } + for (i=0; iInputEvents.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 */ + diff --git a/reactos/subsys/csrss/api/handle.c b/reactos/subsys/csrss/api/handle.c index cfaddefe9b5..0eca26a1b9b 100644 --- a/reactos/subsys/csrss/api/handle.c +++ b/reactos/subsys/csrss/api/handle.c @@ -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 * @@ -13,35 +13,66 @@ #include #include "api.h" +#include /* 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); } + + + diff --git a/reactos/subsys/csrss/api/process.c b/reactos/subsys/csrss/api/process.c index ceb07e5e253..8c760da2b92 100644 --- a/reactos/subsys/csrss/api/process.c +++ b/reactos/subsys/csrss/api/process.c @@ -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 #include - +#include #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); diff --git a/reactos/subsys/csrss/api/wapi.c b/reactos/subsys/csrss/api/wapi.c index 6187d0899f7..49fac5f3f5d 100644 --- a/reactos/subsys/csrss/api/wapi.c +++ b/reactos/subsys/csrss/api/wapi.c @@ -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 (;;) { diff --git a/reactos/subsys/csrss/csrss.c b/reactos/subsys/csrss/csrss.c index df8aecd50cd..e99abd3d20e 100644 --- a/reactos/subsys/csrss/csrss.c +++ b/reactos/subsys/csrss/csrss.c @@ -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" ); diff --git a/reactos/subsys/csrss/init.c b/reactos/subsys/csrss/init.c index 0423c99603e..58bd906360f 100644 --- a/reactos/subsys/csrss/init.c +++ b/reactos/subsys/csrss/init.c @@ -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; }