reactos/reactos/subsystems/win32/csrss/win32csr/conio.c
Dmitry Gorbachev 0743fc87cf - Hackish solution of issue #2062.
- Turn off title change, as it can cause a deadlock.

svn path=/trunk/; revision=27174
2007-06-14 16:41:55 +00:00

3318 lines
100 KiB
C

/*
* reactos/subsys/csrss/win32csr/conio.c
*
* Console I/O functions
*
* ReactOS Operating System
*/
/* INCLUDES ******************************************************************/
#include "w32csr.h"
#define NDEBUG
#include <debug.h>
extern NTSTATUS FASTCALL
Win32CsrInsertObject2(PCSRSS_PROCESS_DATA, PHANDLE, Object_t *);
/* GLOBALS *******************************************************************/
#define ConioInitRect(Rect, Top, Left, Bottom, Right) \
((Rect)->top) = Top; \
((Rect)->left) = Left; \
((Rect)->bottom) = Bottom; \
((Rect)->right) = Right
#define ConioIsRectEmpty(Rect) \
(((Rect)->left > (Rect)->right) || ((Rect)->top > (Rect)->bottom))
#define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \
WideCharToMultiByte((Console)->CodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
#define ConsoleAnsiCharToUnicodeChar(Console, sWChar, dChar) \
MultiByteToWideChar((Console)->CodePage, 0, (dChar), 1, (sWChar), 1)
/* FUNCTIONS *****************************************************************/
static NTSTATUS FASTCALL
ConioConsoleFromProcessData(PCSRSS_PROCESS_DATA ProcessData, PCSRSS_CONSOLE *Console)
{
PCSRSS_CONSOLE ProcessConsole = ProcessData->Console;
if (!ProcessConsole)
{
*Console = NULL;
return STATUS_SUCCESS;
}
EnterCriticalSection(&(ProcessConsole->Header.Lock));
*Console = ProcessConsole;
return STATUS_SUCCESS;
}
VOID FASTCALL
ConioConsoleCtrlEventTimeout(DWORD Event, PCSRSS_PROCESS_DATA ProcessData, DWORD Timeout)
{
HANDLE Thread;
DPRINT("ConioConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData->ProcessId);
if (ProcessData->CtrlDispatcher)
{
Thread = CreateRemoteThread(ProcessData->Process, NULL, 0,
(LPTHREAD_START_ROUTINE) ProcessData->CtrlDispatcher,
(PVOID) Event, 0, NULL);
if (NULL == Thread)
{
DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
return;
}
WaitForSingleObject(Thread, Timeout);
CloseHandle(Thread);
}
}
VOID FASTCALL
ConioConsoleCtrlEvent(DWORD Event, PCSRSS_PROCESS_DATA ProcessData)
{
ConioConsoleCtrlEventTimeout(Event, ProcessData, INFINITE);
}
#define GET_CELL_BUFFER(b,o)\
(b)->Buffer[(o)++]
#define SET_CELL_BUFFER(b,o,c,a)\
(b)->Buffer[(o)++]=(c),\
(b)->Buffer[(o)++]=(a)
static VOID FASTCALL
ClearLineBuffer(PCSRSS_SCREEN_BUFFER Buff)
{
DWORD Offset = 2 * (Buff->CurrentY * Buff->MaxX);
UINT Pos;
for (Pos = 0; Pos < Buff->MaxX; Pos++)
{
/* Fill the cell: Offset is incremented by the macro */
SET_CELL_BUFFER(Buff, Offset, ' ', Buff->DefaultAttrib);
}
}
static NTSTATUS FASTCALL
CsrInitConsoleScreenBuffer(PCSRSS_CONSOLE Console,
PCSRSS_SCREEN_BUFFER Buffer)
{
DPRINT("CsrInitConsoleScreenBuffer Size X %d Size Y %d\n", Buffer->MaxX, Buffer->MaxY);
Buffer->Header.Type = CONIO_SCREEN_BUFFER_MAGIC;
Buffer->Header.ReferenceCount = 0;
Buffer->ShowX = 0;
Buffer->ShowY = 0;
Buffer->Buffer = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, Buffer->MaxX * Buffer->MaxY * 2);
if (NULL == Buffer->Buffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
InitializeCriticalSection(&Buffer->Header.Lock);
ConioInitScreenBuffer(Console, Buffer);
/* initialize buffer to be empty with default attributes */
for (Buffer->CurrentY = 0 ; Buffer->CurrentY < Buffer->MaxY; Buffer->CurrentY++)
{
ClearLineBuffer(Buffer);
}
Buffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
Buffer->CurrentX = 0;
Buffer->CurrentY = 0;
return STATUS_SUCCESS;
}
static NTSTATUS STDCALL
CsrInitConsole(PCSRSS_CONSOLE Console)
{
NTSTATUS Status;
SECURITY_ATTRIBUTES SecurityAttributes;
PCSRSS_SCREEN_BUFFER NewBuffer;
BOOL GuiMode;
Console->Title.MaximumLength = Console->Title.Length = 0;
Console->Title.Buffer = NULL;
//FIXME
RtlCreateUnicodeString(&Console->Title, L"Command Prompt");
Console->Header.ReferenceCount = 0;
Console->WaitingChars = 0;
Console->WaitingLines = 0;
Console->EchoCount = 0;
Console->Header.Type = CONIO_CONSOLE_MAGIC;
Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
Console->EarlyReturn = FALSE;
Console->ActiveBuffer = NULL;
InitializeListHead(&Console->InputEvents);
Console->CodePage = GetOEMCP();
Console->OutputCodePage = GetOEMCP();
SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
SecurityAttributes.lpSecurityDescriptor = NULL;
SecurityAttributes.bInheritHandle = TRUE;
Console->ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL);
if (NULL == Console->ActiveEvent)
{
RtlFreeUnicodeString(&Console->Title);
return STATUS_UNSUCCESSFUL;
}
Console->PrivateData = NULL;
InitializeCriticalSection(&Console->Header.Lock);
GuiMode = DtbgIsDesktopVisible();
/* allocate console screen buffer */
NewBuffer = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
/* init screen buffer with defaults */
NewBuffer->CursorInfo.bVisible = TRUE;
NewBuffer->CursorInfo.dwSize = 5;
/* make console active, and insert into console list */
Console->ActiveBuffer = (PCSRSS_SCREEN_BUFFER) NewBuffer;
/* add a reference count because the buffer is tied to the console */
InterlockedIncrement(&Console->ActiveBuffer->Header.ReferenceCount);
if (NULL == NewBuffer)
{
RtlFreeUnicodeString(&Console->Title);
DeleteCriticalSection(&Console->Header.Lock);
CloseHandle(Console->ActiveEvent);
return STATUS_INSUFFICIENT_RESOURCES;
}
if (! GuiMode)
{
Status = TuiInitConsole(Console);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to open text-mode console, switching to gui-mode\n");
GuiMode = TRUE;
}
}
if (GuiMode)
{
Status = GuiInitConsole(Console);
if (! NT_SUCCESS(Status))
{
HeapFree(Win32CsrApiHeap,0, NewBuffer);
RtlFreeUnicodeString(&Console->Title);
DeleteCriticalSection(&Console->Header.Lock);
CloseHandle(Console->ActiveEvent);
DPRINT1("GuiInitConsole: failed\n");
return Status;
}
}
Status = CsrInitConsoleScreenBuffer(Console, NewBuffer);
if (! NT_SUCCESS(Status))
{
ConioCleanupConsole(Console);
RtlFreeUnicodeString(&Console->Title);
DeleteCriticalSection(&Console->Header.Lock);
CloseHandle(Console->ActiveEvent);
HeapFree(Win32CsrApiHeap, 0, NewBuffer);
DPRINT1("CsrInitConsoleScreenBuffer: failed\n");
return Status;
}
/* copy buffer contents to screen */
ConioDrawConsole(Console);
return STATUS_SUCCESS;
}
CSR_API(CsrAllocConsole)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN NewConsole = FALSE;
DPRINT("CsrAllocConsole\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if (ProcessData == NULL)
{
DPRINT1("No process data\n");
return Request->Status = STATUS_INVALID_PARAMETER;
}
if (ProcessData->Console)
{
DPRINT1("Process already has a console\n");
Request->Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
/* Assume success */
Request->Status = STATUS_SUCCESS;
/* If we don't need a console, then get out of here */
if (!Request->Data.AllocConsoleRequest.ConsoleNeeded)
{
DPRINT("No console needed\n");
return STATUS_SUCCESS;
}
/* If we already have one, then don't create a new one... */
if (!Request->Data.AllocConsoleRequest.Console ||
Request->Data.AllocConsoleRequest.Console != ProcessData->ParentConsole)
{
/* Allocate a console structure */
NewConsole = TRUE;
Console = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_CONSOLE));
if (NULL == Console)
{
DPRINT1("Not enough memory for console\n");
Request->Status = STATUS_NO_MEMORY;
return STATUS_NO_MEMORY;
}
/* initialize list head */
InitializeListHead(&Console->ProcessList);
/* insert process data required for GUI initialization */
InsertHeadList(&Console->ProcessList, &ProcessData->ProcessEntry);
/* Initialize the Console */
Request->Status = CsrInitConsole(Console);
if (!NT_SUCCESS(Request->Status))
{
DPRINT1("Console init failed\n");
HeapFree(Win32CsrApiHeap, 0, Console);
return Request->Status;
}
}
else
{
/* Reuse our current console */
Console = Request->Data.AllocConsoleRequest.Console;
}
/* Set the Process Console */
ProcessData->Console = Console;
/* Return it to the caller */
Request->Data.AllocConsoleRequest.Console = Console;
/* Add a reference count because the process is tied to the console */
Console->Header.ReferenceCount++;
if (NewConsole || !ProcessData->bInheritHandles)
{
/* Insert the Objects */
Status = Win32CsrInsertObject2(ProcessData,
&Request->Data.AllocConsoleRequest.InputHandle,
&Console->Header);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to insert object\n");
ConioDeleteConsole((Object_t *) Console);
ProcessData->Console = 0;
return Request->Status = Status;
}
Status = Win32CsrInsertObject2(ProcessData,
&Request->Data.AllocConsoleRequest.OutputHandle,
&Console->ActiveBuffer->Header);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to insert object\n");
ConioDeleteConsole((Object_t *) Console);
Win32CsrReleaseObject(ProcessData,
Request->Data.AllocConsoleRequest.InputHandle);
ProcessData->Console = 0;
return Request->Status = Status;
}
}
/* Duplicate the Event */
if (!DuplicateHandle(GetCurrentProcess(),
ProcessData->Console->ActiveEvent,
ProcessData->Process,
&ProcessData->ConsoleEvent,
EVENT_ALL_ACCESS,
FALSE,
0))
{
DPRINT1("DuplicateHandle() failed: %d\n", GetLastError);
ConioDeleteConsole((Object_t *) Console);
if (NewConsole || !ProcessData->bInheritHandles)
{
Win32CsrReleaseObject(ProcessData,
Request->Data.AllocConsoleRequest.OutputHandle);
Win32CsrReleaseObject(ProcessData,
Request->Data.AllocConsoleRequest.InputHandle);
}
ProcessData->Console = 0;
return Request->Status = Status;
}
/* Set the Ctrl Dispatcher */
ProcessData->CtrlDispatcher = Request->Data.AllocConsoleRequest.CtrlDispatcher;
DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
if (!NewConsole)
{
/* Insert into the list if it has not been added */
InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ProcessEntry);
}
return STATUS_SUCCESS;
}
CSR_API(CsrFreeConsole)
{
PCSRSS_CONSOLE Console;
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if (ProcessData == NULL || ProcessData->Console == NULL)
{
return Request->Status = STATUS_INVALID_PARAMETER;
}
Console = ProcessData->Console;
ProcessData->Console = NULL;
if (0 == InterlockedDecrement(&Console->Header.ReferenceCount))
{
ConioDeleteConsole((Object_t *) Console);
}
return STATUS_SUCCESS;
}
static VOID FASTCALL
ConioNextLine(PCSRSS_SCREEN_BUFFER Buff, RECT *UpdateRect, UINT *ScrolledLines)
{
/* slide the viewable screen */
if (((Buff->CurrentY - Buff->ShowY + Buff->MaxY) % Buff->MaxY) == (ULONG)Buff->MaxY - 1)
{
if (++Buff->ShowY == Buff->MaxY)
{
Buff->ShowY = 0;
}
(*ScrolledLines)++;
}
if (++Buff->CurrentY == Buff->MaxY)
{
Buff->CurrentY = 0;
}
ClearLineBuffer(Buff);
UpdateRect->left = 0;
UpdateRect->right = Buff->MaxX - 1;
if (UpdateRect->top == (LONG)Buff->CurrentY)
{
if (++UpdateRect->top == Buff->MaxY)
{
UpdateRect->top = 0;
}
}
UpdateRect->bottom = Buff->CurrentY;
}
static NTSTATUS FASTCALL
ConioWriteConsole(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff,
CHAR *Buffer, DWORD Length, BOOL Attrib)
{
UINT i;
DWORD Offset;
RECT UpdateRect;
LONG CursorStartX, CursorStartY;
UINT ScrolledLines;
ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY, &CursorStartX, &CursorStartY);
UpdateRect.left = Buff->MaxX;
UpdateRect.top = Buff->CurrentY;
UpdateRect.right = -1;
UpdateRect.bottom = Buff->CurrentY;
ScrolledLines = 0;
for (i = 0; i < Length; i++)
{
if (Buff->Mode & ENABLE_PROCESSED_OUTPUT)
{
/* --- LF --- */
if (Buffer[i] == '\n')
{
Buff->CurrentX = 0;
ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
continue;
}
/* --- BS --- */
else if (Buffer[i] == '\b')
{
/* Only handle BS if we're not on the first pos of the first line */
if (0 != Buff->CurrentX || Buff->ShowY != Buff->CurrentY)
{
if (0 == Buff->CurrentX)
{
/* slide virtual position up */
Buff->CurrentX = Buff->MaxX - 1;
if (0 == Buff->CurrentY)
{
Buff->CurrentY = Buff->MaxY;
}
else
{
Buff->CurrentY--;
}
if ((0 == UpdateRect.top && UpdateRect.bottom < (LONG)Buff->CurrentY)
|| (0 != UpdateRect.top && (LONG)Buff->CurrentY < UpdateRect.top))
{
UpdateRect.top = Buff->CurrentY;
}
}
else
{
Buff->CurrentX--;
}
Offset = 2 * ((Buff->CurrentY * Buff->MaxX) + Buff->CurrentX);
SET_CELL_BUFFER(Buff, Offset, ' ', Buff->DefaultAttrib);
UpdateRect.left = min(UpdateRect.left, (LONG) Buff->CurrentX);
UpdateRect.right = max(UpdateRect.right, (LONG) Buff->CurrentX);
}
continue;
}
/* --- CR --- */
else if (Buffer[i] == '\r')
{
Buff->CurrentX = 0;
UpdateRect.left = min(UpdateRect.left, (LONG) Buff->CurrentX);
UpdateRect.right = max(UpdateRect.right, (LONG) Buff->CurrentX);
continue;
}
/* --- TAB --- */
else if (Buffer[i] == '\t')
{
UINT EndX;
UpdateRect.left = min(UpdateRect.left, (LONG)Buff->CurrentX);
EndX = (Buff->CurrentX + 8) & ~7;
if (EndX > Buff->MaxX)
{
EndX = Buff->MaxX;
}
Offset = 2 * (((Buff->CurrentY * Buff->MaxX)) + Buff->CurrentX);
while (Buff->CurrentX < EndX)
{
Buff->Buffer[Offset] = ' ';
Offset += 2;
Buff->CurrentX++;
}
UpdateRect.right = max(UpdateRect.right, (LONG) Buff->CurrentX - 1);
if (Buff->CurrentX == Buff->MaxX)
{
if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
{
Buff->CurrentX = 0;
ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
}
else
{
Buff->CurrentX--;
}
}
continue;
}
}
UpdateRect.left = min(UpdateRect.left, (LONG)Buff->CurrentX);
UpdateRect.right = max(UpdateRect.right, (LONG) Buff->CurrentX);
Offset = 2 * (((Buff->CurrentY * Buff->MaxX)) + Buff->CurrentX);
Buff->Buffer[Offset++] = Buffer[i];
if (Attrib)
{
Buff->Buffer[Offset] = Buff->DefaultAttrib;
}
Buff->CurrentX++;
if (Buff->CurrentX == Buff->MaxX)
{
if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
{
Buff->CurrentX = 0;
ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
}
else
{
Buff->CurrentX = CursorStartX;
}
}
}
ConioPhysicalToLogical(Buff, UpdateRect.left, UpdateRect.top, &(UpdateRect.left),
&(UpdateRect.top));
ConioPhysicalToLogical(Buff, UpdateRect.right, UpdateRect.bottom, &(UpdateRect.right),
&(UpdateRect.bottom));
if (! ConioIsRectEmpty(&UpdateRect) && NULL != Console && Buff == Console->ActiveBuffer)
{
ConioWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY, ScrolledLines,
Buffer, Length);
}
return STATUS_SUCCESS;
}
CSR_API(CsrReadConsole)
{
PLIST_ENTRY CurrentEntry;
ConsoleInput *Input;
PUCHAR Buffer;
PWCHAR UnicodeBuffer;
ULONG i;
ULONG nNumberOfCharsToRead, CharSize;
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrReadConsole\n");
CharSize = (Request->Data.ReadConsoleRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
/* truncate length to CSRSS_MAX_READ_CONSOLE_REQUEST */
nNumberOfCharsToRead = min(Request->Data.ReadConsoleRequest.NrCharactersToRead, CSRSS_MAX_READ_CONSOLE / CharSize);
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Buffer = Request->Data.ReadConsoleRequest.Buffer;
UnicodeBuffer = (PWCHAR)Buffer;
Status = ConioLockConsole(ProcessData, Request->Data.ReadConsoleRequest.ConsoleHandle,
&Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Data.ReadConsoleRequest.EventHandle = ProcessData->ConsoleEvent;
for (i = 0; i < nNumberOfCharsToRead && Console->InputEvents.Flink != &Console->InputEvents; i++)
{
/* remove input event from queue */
CurrentEntry = RemoveHeadList(&Console->InputEvents);
if (IsListEmpty(&Console->InputEvents))
{
CHECKPOINT;
ResetEvent(Console->ActiveEvent);
}
Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
/* only pay attention to valid ascii chars, on key down */
if (KEY_EVENT == Input->InputEvent.EventType
&& Input->InputEvent.Event.KeyEvent.bKeyDown
&& Input->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\0')
{
/*
* backspace handling - if we are in charge of echoing it then we handle it here
* otherwise we treat it like a normal char.
*/
if ('\b' == Input->InputEvent.Event.KeyEvent.uChar.AsciiChar && 0
!= (Console->Mode & ENABLE_ECHO_INPUT))
{
/* echo if it has not already been done, and either we or the client has chars to be deleted */
if (! Input->Echoed
&& (0 != i || Request->Data.ReadConsoleRequest.nCharsCanBeDeleted))
{
ConioWriteConsole(Console, Console->ActiveBuffer,
&Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE);
}
if (0 != i)
{
i -= 2; /* if we already have something to return, just back it up by 2 */
}
else
{ /* otherwise, return STATUS_NOTIFY_CLEANUP to tell client to back up its buffer */
Console->WaitingChars--;
ConioUnlockConsole(Console);
HeapFree(Win32CsrApiHeap, 0, Input);
Request->Data.ReadConsoleRequest.NrCharactersRead = 0;
Request->Status = STATUS_NOTIFY_CLEANUP;
return STATUS_NOTIFY_CLEANUP;
}
Request->Data.ReadConsoleRequest.nCharsCanBeDeleted--;
Input->Echoed = TRUE; /* mark as echoed so we don't echo it below */
}
/* do not copy backspace to buffer */
else
{
if(Request->Data.ReadConsoleRequest.Unicode)
UnicodeBuffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar; /* FIXME */
else
Buffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar;
}
/* echo to screen if enabled and we did not already echo the char */
if (0 != (Console->Mode & ENABLE_ECHO_INPUT)
&& ! Input->Echoed
&& '\r' != Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
{
ConioWriteConsole(Console, Console->ActiveBuffer,
&Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE);
}
}
else
{
i--;
}
Console->WaitingChars--;
HeapFree(Win32CsrApiHeap, 0, Input);
}
Request->Data.ReadConsoleRequest.NrCharactersRead = i;
if (0 == i)
{
Request->Status = STATUS_PENDING; /* we didn't read anything */
}
else if (0 != (Console->Mode & ENABLE_LINE_INPUT))
{
if (0 == Console->WaitingLines ||
(Request->Data.ReadConsoleRequest.Unicode ? (L'\n' != UnicodeBuffer[i - 1]) : ('\n' != Buffer[i - 1])))
{
Request->Status = STATUS_PENDING; /* line buffered, didn't get a complete line */
}
else
{
Console->WaitingLines--;
Request->Status = STATUS_SUCCESS; /* line buffered, did get a complete line */
}
}
else
{
Request->Status = STATUS_SUCCESS; /* not line buffered, did read something */
}
if (Request->Status == STATUS_PENDING)
{
Console->EchoCount = nNumberOfCharsToRead - i;
}
else
{
Console->EchoCount = 0; /* if the client is no longer waiting on input, do not echo */
}
ConioUnlockConsole(Console);
if (CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE) + i * CharSize > sizeof(CSR_API_MESSAGE))
{
Request->Header.u1.s1.TotalLength = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE) + i * CharSize;
Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
}
return Request->Status;
}
VOID FASTCALL
ConioPhysicalToLogical(PCSRSS_SCREEN_BUFFER Buff,
ULONG PhysicalX,
ULONG PhysicalY,
LONG *LogicalX,
LONG *LogicalY)
{
*LogicalX = PhysicalX;
if (PhysicalY < Buff->ShowY)
{
*LogicalY = Buff->MaxY - Buff->ShowY + PhysicalY;
}
else
{
*LogicalY = PhysicalY - Buff->ShowY;
}
}
BOOLEAN __inline ConioIsEqualRect(
RECT *Rect1,
RECT *Rect2)
{
return ((Rect1->left == Rect2->left) && (Rect1->right == Rect2->right) &&
(Rect1->top == Rect2->top) && (Rect1->bottom == Rect2->bottom));
}
BOOLEAN __inline ConioGetIntersection(
RECT *Intersection,
RECT *Rect1,
RECT *Rect2)
{
if (ConioIsRectEmpty(Rect1) ||
(ConioIsRectEmpty(Rect2)) ||
(Rect1->top > Rect2->bottom) ||
(Rect1->left > Rect2->right) ||
(Rect1->bottom < Rect2->top) ||
(Rect1->right < Rect2->left))
{
/* The rectangles do not intersect */
ConioInitRect(Intersection, 0, -1, 0, -1);
return FALSE;
}
ConioInitRect(Intersection,
max(Rect1->top, Rect2->top),
max(Rect1->left, Rect2->left),
min(Rect1->bottom, Rect2->bottom),
min(Rect1->right, Rect2->right));
return TRUE;
}
BOOLEAN __inline ConioGetUnion(
RECT *Union,
RECT *Rect1,
RECT *Rect2)
{
if (ConioIsRectEmpty(Rect1))
{
if (ConioIsRectEmpty(Rect2))
{
ConioInitRect(Union, 0, -1, 0, -1);
return FALSE;
}
else
{
*Union = *Rect2;
}
}
else if (ConioIsRectEmpty(Rect2))
{
*Union = *Rect1;
}
else
{
ConioInitRect(Union,
min(Rect1->top, Rect2->top),
min(Rect1->left, Rect2->left),
max(Rect1->bottom, Rect2->bottom),
max(Rect1->right, Rect2->right));
}
return TRUE;
}
BOOLEAN __inline ConioSubtractRect(
RECT *Subtraction,
RECT *Rect1,
RECT *Rect2)
{
RECT tmp;
if (ConioIsRectEmpty(Rect1))
{
ConioInitRect(Subtraction, 0, -1, 0, -1);
return FALSE;
}
*Subtraction = *Rect1;
if (ConioGetIntersection(&tmp, Rect1, Rect2))
{
if (ConioIsEqualRect(&tmp, Subtraction))
{
ConioInitRect(Subtraction, 0, -1, 0, -1);
return FALSE;
}
if ((tmp.top == Subtraction->top) && (tmp.bottom == Subtraction->bottom))
{
if (tmp.left == Subtraction->left)
{
Subtraction->left = tmp.right;
}
else if (tmp.right == Subtraction->right)
{
Subtraction->right = tmp.left;
}
}
else if ((tmp.left == Subtraction->left) && (tmp.right == Subtraction->right))
{
if (tmp.top == Subtraction->top)
{
Subtraction->top = tmp.bottom;
}
else if (tmp.bottom == Subtraction->bottom)
{
Subtraction->bottom = tmp.top;
}
}
}
return TRUE;
}
static VOID FASTCALL
ConioCopyRegion(PCSRSS_SCREEN_BUFFER ScreenBuffer,
RECT *SrcRegion,
RECT *DstRegion)
{
SHORT SrcY, DstY;
DWORD SrcOffset;
DWORD DstOffset;
DWORD BytesPerLine;
LONG i;
DstY = DstRegion->top;
BytesPerLine = ConioRectWidth(DstRegion) * 2;
SrcY = (SrcRegion->top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
DstY = (DstRegion->top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
SrcOffset = (SrcY * ScreenBuffer->MaxX + SrcRegion->left + ScreenBuffer->ShowX) * 2;
DstOffset = (DstY * ScreenBuffer->MaxX + DstRegion->left + ScreenBuffer->ShowX) * 2;
for (i = SrcRegion->top; i <= SrcRegion->bottom; i++)
{
RtlCopyMemory(
&ScreenBuffer->Buffer[DstOffset],
&ScreenBuffer->Buffer[SrcOffset],
BytesPerLine);
if (++DstY == ScreenBuffer->MaxY)
{
DstY = 0;
DstOffset = (DstRegion->left + ScreenBuffer->ShowX) * 2;
}
else
{
DstOffset += ScreenBuffer->MaxX * 2;
}
if (++SrcY == ScreenBuffer->MaxY)
{
SrcY = 0;
SrcOffset = (SrcRegion->left + ScreenBuffer->ShowX) * 2;
}
else
{
SrcOffset += ScreenBuffer->MaxX * 2;
}
}
}
static VOID FASTCALL
ConioFillRegion(PCSRSS_CONSOLE Console,
PCSRSS_SCREEN_BUFFER ScreenBuffer,
RECT *Region,
CHAR_INFO *CharInfo,
BOOL bUnicode)
{
SHORT X, Y;
DWORD Offset;
DWORD Delta;
LONG i;
CHAR Char;
if(bUnicode)
ConsoleUnicodeCharToAnsiChar(Console, &Char, &CharInfo->Char.UnicodeChar);
else
Char = CharInfo->Char.AsciiChar;
Y = (Region->top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
Offset = (Y * ScreenBuffer->MaxX + Region->left + ScreenBuffer->ShowX) * 2;
Delta = (ScreenBuffer->MaxX - ConioRectWidth(Region)) * 2;
for (i = Region->top; i <= Region->bottom; i++)
{
for (X = Region->left; X <= Region->right; X++)
{
SET_CELL_BUFFER(ScreenBuffer, Offset, Char, CharInfo->Attributes);
}
if (++Y == ScreenBuffer->MaxY)
{
Y = 0;
Offset = (Region->left + ScreenBuffer->ShowX) * 2;
}
else
{
Offset += Delta;
}
}
}
static VOID FASTCALL
ConioInputEventToAnsi(PCSRSS_CONSOLE Console, PINPUT_RECORD InputEvent)
{
if (InputEvent->EventType == KEY_EVENT)
{
WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar;
InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0;
ConsoleUnicodeCharToAnsiChar(Console,
&InputEvent->Event.KeyEvent.uChar.AsciiChar,
&UnicodeChar);
}
}
CSR_API(CsrWriteConsole)
{
NTSTATUS Status;
PCHAR Buffer;
PCSRSS_SCREEN_BUFFER Buff;
PCSRSS_CONSOLE Console;
DWORD Written = 0;
ULONG Length;
ULONG CharSize = (Request->Data.WriteConsoleRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
DPRINT("CsrWriteConsole\n");
if (Request->Header.u1.s1.TotalLength
< CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE)
+ (Request->Data.WriteConsoleRequest.NrCharactersToWrite * CharSize))
{
DPRINT1("Invalid request size\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
return Request->Status = STATUS_INVALID_PARAMETER;
}
Status = ConioConsoleFromProcessData(ProcessData, &Console);
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
if(Request->Data.WriteConsoleRequest.Unicode)
{
Length = WideCharToMultiByte(Console->CodePage, 0,
(PWCHAR)Request->Data.WriteConsoleRequest.Buffer,
Request->Data.WriteConsoleRequest.NrCharactersToWrite,
NULL, 0, NULL, NULL);
Buffer = RtlAllocateHeap(GetProcessHeap(), 0, Length);
if (Buffer)
{
WideCharToMultiByte(Console->CodePage, 0,
(PWCHAR)Request->Data.WriteConsoleRequest.Buffer,
Request->Data.WriteConsoleRequest.NrCharactersToWrite,
Buffer, Length, NULL, NULL);
}
else
{
Status = STATUS_NO_MEMORY;
}
}
else
{
Buffer = (PCHAR)Request->Data.WriteConsoleRequest.Buffer;
}
if (Buffer)
{
Status = ConioLockScreenBuffer(ProcessData, Request->Data.WriteConsoleRequest.ConsoleHandle, &Buff);
if (NT_SUCCESS(Status))
{
Request->Status = ConioWriteConsole(Console, Buff, Buffer,
Request->Data.WriteConsoleRequest.NrCharactersToWrite, TRUE);
if (NT_SUCCESS(Status))
{
Written = Request->Data.WriteConsoleRequest.NrCharactersToWrite;
}
ConioUnlockScreenBuffer(Buff);
}
if (Request->Data.WriteConsoleRequest.Unicode)
{
RtlFreeHeap(GetProcessHeap(), 0, Buffer);
}
}
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
Request->Data.WriteConsoleRequest.NrCharactersWritten = Written;
return Request->Status = Status;
}
VOID STDCALL
ConioDeleteScreenBuffer(Object_t *Object)
{
PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_SCREEN_BUFFER) Object;
DeleteCriticalSection(&Buffer->Header.Lock);
HeapFree(Win32CsrApiHeap, 0, Buffer->Buffer);
HeapFree(Win32CsrApiHeap, 0, Buffer);
}
VOID FASTCALL
ConioDrawConsole(PCSRSS_CONSOLE Console)
{
RECT Region;
ConioInitRect(&Region, 0, 0, Console->Size.Y - 1, Console->Size.X - 1);
ConioDrawRegion(Console, &Region);
}
VOID STDCALL
ConioDeleteConsole(Object_t *Object)
{
PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Object;
ConsoleInput *Event;
DPRINT("ConioDeleteConsole\n");
/* Drain input event queue */
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;
HeapFree(Win32CsrApiHeap, 0, Event);
}
#if 0 // FIXME
if (0 == InterlockedDecrement(&Console->ActiveBuffer->Header.ReferenceCount))
{
ConioDeleteScreenBuffer((Object_t *) Console->ActiveBuffer);
}
#endif
Console->ActiveBuffer = NULL;
ConioCleanupConsole(Console);
CloseHandle(Console->ActiveEvent);
DeleteCriticalSection(&Console->Header.Lock);
RtlFreeUnicodeString(&Console->Title);
HeapFree(Win32CsrApiHeap, 0, Console);
}
VOID STDCALL
CsrInitConsoleSupport(VOID)
{
DPRINT("CSR: CsrInitConsoleSupport()\n");
/* Should call LoadKeyboardLayout */
}
static VOID FASTCALL
ConioProcessChar(PCSRSS_CONSOLE Console,
ConsoleInput *KeyEventRecord)
{
BOOL updown;
BOOL bClientWake = FALSE;
ConsoleInput *TempInput;
/* process Ctrl-C and Ctrl-Break */
if (Console->Mode & ENABLE_PROCESSED_INPUT &&
KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown &&
((KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) ||
(KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == 'C')) &&
(KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)))
{
PCSRSS_PROCESS_DATA current;
PLIST_ENTRY current_entry;
DPRINT1("Console_Api Ctrl-C\n");
current_entry = Console->ProcessList.Flink;
while (current_entry != &Console->ProcessList)
{
current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
current_entry = current_entry->Flink;
ConioConsoleCtrlEvent((DWORD)CTRL_C_EVENT, current);
}
HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
return;
}
if (0 != (KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState
& (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
&& (VK_UP == KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode
|| VK_DOWN == KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode))
{
if (KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown)
{
/* scroll up or down */
if (NULL == Console)
{
DPRINT1("No Active Console!\n");
HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
return;
}
if (VK_UP == KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode)
{
/* only scroll up if there is room to scroll up into */
if (Console->ActiveBuffer->ShowY != ((Console->ActiveBuffer->CurrentY + 1) %
Console->ActiveBuffer->MaxY))
{
Console->ActiveBuffer->ShowY = (Console->ActiveBuffer->ShowY +
Console->ActiveBuffer->MaxY - 1) %
Console->ActiveBuffer->MaxY;
}
}
else if (Console->ActiveBuffer->ShowY != Console->ActiveBuffer->CurrentY)
/* only scroll down if there is room to scroll down into */
{
if (Console->ActiveBuffer->ShowY % Console->ActiveBuffer->MaxY !=
Console->ActiveBuffer->CurrentY)
{
if (((Console->ActiveBuffer->CurrentY + 1) % Console->ActiveBuffer->MaxY) !=
(Console->ActiveBuffer->ShowY + Console->ActiveBuffer->MaxY) %
Console->ActiveBuffer->MaxY)
{
Console->ActiveBuffer->ShowY = (Console->ActiveBuffer->ShowY + 1) %
Console->ActiveBuffer->MaxY;
}
}
}
ConioDrawConsole(Console);
}
HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
return;
}
if (NULL == Console)
{
DPRINT1("No Active Console!\n");
HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
return;
}
if (0 != (Console->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)))
{
switch(KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
{
case '\r':
/* first add the \r */
KeyEventRecord->InputEvent.EventType = KEY_EVENT;
updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown;
KeyEventRecord->Echoed = FALSE;
KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r';
InsertTailList(&Console->InputEvents, &KeyEventRecord->ListEntry);
Console->WaitingChars++;
KeyEventRecord = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
if (NULL == KeyEventRecord)
{
DPRINT1("Failed to allocate KeyEventRecord\n");
return;
}
KeyEventRecord->InputEvent.EventType = KEY_EVENT;
KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown;
KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0;
KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0;
KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n';
KeyEventRecord->Fake = TRUE;
break;
}
}
/* add event to the queue */
InsertTailList(&Console->InputEvents, &KeyEventRecord->ListEntry);
Console->WaitingChars++;
/* if line input mode is enabled, only wake the client on enter key down */
if (0 == (Console->Mode & ENABLE_LINE_INPUT)
|| Console->EarlyReturn
|| ('\n' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
&& KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown))
{
if ('\n' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
{
Console->WaitingLines++;
}
bClientWake = TRUE;
SetEvent(Console->ActiveEvent);
}
KeyEventRecord->Echoed = FALSE;
if (0 != (Console->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT))
&& '\b' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
&& KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown)
{
/* walk the input queue looking for a char to backspace */
for (TempInput = (ConsoleInput *) Console->InputEvents.Blink;
TempInput != (ConsoleInput *) &Console->InputEvents
&& (KEY_EVENT == TempInput->InputEvent.EventType
|| ! TempInput->InputEvent.Event.KeyEvent.bKeyDown
|| '\b' == TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar);
TempInput = (ConsoleInput *) TempInput->ListEntry.Blink)
{
/* NOP */;
}
/* if we found one, delete it, otherwise, wake the client */
if (TempInput != (ConsoleInput *) &Console->InputEvents)
{
/* delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue */
RemoveEntryList(&TempInput->ListEntry);
if (TempInput->Echoed)
{
ConioWriteConsole(Console, Console->ActiveBuffer,
&KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar,
1, TRUE);
}
HeapFree(Win32CsrApiHeap, 0, TempInput);
RemoveEntryList(&KeyEventRecord->ListEntry);
HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
Console->WaitingChars -= 2;
}
else
{
SetEvent(Console->ActiveEvent);
}
}
else
{
/* echo chars if we are supposed to and client is waiting for some */
if (0 != (Console->Mode & ENABLE_ECHO_INPUT) && Console->EchoCount
&& KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
&& KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown
&& '\r' != KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
{
/* mark the char as already echoed */
ConioWriteConsole(Console, Console->ActiveBuffer,
&KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar,
1, TRUE);
Console->EchoCount--;
KeyEventRecord->Echoed = TRUE;
}
}
/* Console->WaitingChars++; */
if (bClientWake || 0 == (Console->Mode & ENABLE_LINE_INPUT))
{
SetEvent(Console->ActiveEvent);
}
}
static DWORD FASTCALL
ConioGetShiftState(PBYTE KeyState)
{
DWORD ssOut = 0;
if (KeyState[VK_CAPITAL] & 1)
ssOut |= CAPSLOCK_ON;
if (KeyState[VK_NUMLOCK] & 1)
ssOut |= NUMLOCK_ON;
if (KeyState[VK_SCROLL] & 1)
ssOut |= SCROLLLOCK_ON;
if (KeyState[VK_SHIFT] & 0x80)
ssOut |= SHIFT_PRESSED;
if (KeyState[VK_LCONTROL] & 0x80)
ssOut |= LEFT_CTRL_PRESSED;
if (KeyState[VK_RCONTROL] & 0x80)
ssOut |= RIGHT_CTRL_PRESSED;
if (KeyState[VK_LMENU] & 0x80)
ssOut |= LEFT_ALT_PRESSED;
if (KeyState[VK_RMENU] & 0x80)
ssOut |= RIGHT_ALT_PRESSED;
return ssOut;
}
VOID STDCALL
ConioProcessKey(MSG *msg, PCSRSS_CONSOLE Console, BOOL TextMode)
{
static BYTE KeyState[256] = { 0 };
/* MSDN mentions that you should use the last virtual key code received
* when putting a virtual key identity to a WM_CHAR message since multiple
* or translated keys may be involved. */
static UINT LastVirtualKey = 0;
DWORD ShiftState;
ConsoleInput *ConInRec;
UINT RepeatCount;
CHAR AsciiChar;
WCHAR UnicodeChar;
UINT VirtualKeyCode;
UINT VirtualScanCode;
BOOL Down = FALSE;
INPUT_RECORD er;
ULONG ResultSize = 0;
RepeatCount = 1;
VirtualScanCode = (msg->lParam >> 16) & 0xff;
Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR ||
msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR;
GetKeyboardState(KeyState);
ShiftState = ConioGetShiftState(KeyState);
if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
{
VirtualKeyCode = LastVirtualKey;
UnicodeChar = msg->wParam;
}
else
{
WCHAR Chars[2];
INT RetChars = 0;
VirtualKeyCode = msg->wParam;
RetChars = ToUnicodeEx(VirtualKeyCode,
VirtualScanCode,
KeyState,
Chars,
2,
0,
0);
UnicodeChar = (1 == RetChars ? Chars[0] : 0);
}
if (0 == ResultSize)
{
AsciiChar = 0;
}
er.EventType = KEY_EVENT;
er.Event.KeyEvent.bKeyDown = Down;
er.Event.KeyEvent.wRepeatCount = RepeatCount;
er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
er.Event.KeyEvent.dwControlKeyState = ShiftState;
er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode;
er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode;
if (TextMode)
{
if (0 != (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
&& VK_TAB == VirtualKeyCode)
{
if (Down)
{
TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1);
}
return;
}
else if (VK_MENU == VirtualKeyCode && ! Down)
{
if (TuiSwapConsole(0))
{
return;
}
}
}
if (NULL == Console)
{
return;
}
ConInRec = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
if (NULL == ConInRec)
{
return;
}
ConInRec->InputEvent = er;
ConInRec->Fake = UnicodeChar &&
(msg->message != WM_CHAR && msg->message != WM_SYSCHAR &&
msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP);
ConInRec->NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR);
ConInRec->Echoed = FALSE;
if (ConInRec->NotChar)
LastVirtualKey = msg->wParam;
DPRINT ("csrss: %s %s %s %s %02x %02x '%c' %04x\n",
Down ? "down" : "up ",
(msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ?
"char" : "key ",
ConInRec->Fake ? "fake" : "real",
ConInRec->NotChar ? "notc" : "char",
VirtualScanCode,
VirtualKeyCode,
(AsciiChar >= ' ') ? AsciiChar : '.',
ShiftState);
if (! ConInRec->Fake || ! ConInRec->NotChar)
{
/* FIXME - convert to ascii */
ConioProcessChar(Console, ConInRec);
}
else
{
HeapFree(Win32CsrApiHeap, 0, ConInRec);
}
}
CSR_API(CsrGetScreenBufferInfo)
{
NTSTATUS Status;
PCSRSS_SCREEN_BUFFER Buff;
PCONSOLE_SCREEN_BUFFER_INFO pInfo;
DPRINT("CsrGetScreenBufferInfo\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockScreenBuffer(ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle, &Buff);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
pInfo = &Request->Data.ScreenBufferInfoRequest.Info;
pInfo->dwSize.X = Buff->MaxX;
pInfo->dwSize.Y = Buff->MaxY;
pInfo->dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
pInfo->dwCursorPosition.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
pInfo->wAttributes = Buff->DefaultAttrib;
pInfo->srWindow.Left = 0;
pInfo->srWindow.Right = Buff->MaxX - 1;
pInfo->srWindow.Top = 0;
pInfo->srWindow.Bottom = Buff->MaxY - 1;
pInfo->dwMaximumWindowSize.X = Buff->MaxX;
pInfo->dwMaximumWindowSize.Y = Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
Request->Status = STATUS_SUCCESS;
return Request->Status;
}
CSR_API(CsrSetCursor)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
LONG OldCursorX, OldCursorY;
LONG NewCursorX, NewCursorY;
DPRINT("CsrSetCursor\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff);
if (! NT_SUCCESS(Status))
{
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = Status;
}
NewCursorX = Request->Data.SetCursorRequest.Position.X;
NewCursorY = Request->Data.SetCursorRequest.Position.Y;
if (NewCursorX < 0 || NewCursorX >= Buff->MaxX ||
NewCursorY < 0 || NewCursorY >= Buff->MaxY)
{
ConioUnlockScreenBuffer(Buff);
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = STATUS_INVALID_PARAMETER;
}
ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY, &OldCursorX, &OldCursorY);
Buff->CurrentX = NewCursorX + Buff->ShowX;
Buff->CurrentY = (NewCursorY + Buff->ShowY) % Buff->MaxY;
if (NULL != Console && Buff == Console->ActiveBuffer)
{
if (! ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
{
ConioUnlockScreenBuffer(Buff);
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = STATUS_UNSUCCESSFUL;
}
}
ConioUnlockScreenBuffer(Buff);
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = STATUS_SUCCESS;
}
static VOID FASTCALL
ConioComputeUpdateRect(PCSRSS_SCREEN_BUFFER Buff, RECT *UpdateRect, COORD *Start, UINT Length)
{
if (Buff->MaxX <= Start->X + Length)
{
UpdateRect->left = 0;
}
else
{
UpdateRect->left = Start->X;
}
if (Buff->MaxX <= Start->X + Length)
{
UpdateRect->right = Buff->MaxX - 1;
}
else
{
UpdateRect->right = Start->X + Length - 1;
}
UpdateRect->top = Start->Y;
UpdateRect->bottom = Start->Y+ (Start->X + Length - 1) / Buff->MaxX;
if (Buff->MaxY <= UpdateRect->bottom)
{
UpdateRect->bottom = Buff->MaxY - 1;
}
}
CSR_API(CsrWriteConsoleOutputChar)
{
NTSTATUS Status;
PCHAR String, tmpString = NULL;
PBYTE Buffer;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DWORD X, Y, Length, CharSize, Written = 0;
RECT UpdateRect;
DPRINT("CsrWriteConsoleOutputChar\n");
CharSize = (Request->Data.WriteConsoleOutputCharRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
if (Request->Header.u1.s1.TotalLength
< CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_CHAR)
+ (Request->Data.WriteConsoleOutputCharRequest.Length * CharSize))
{
DPRINT1("Invalid request size\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
return Request->Status = STATUS_INVALID_PARAMETER;
}
Status = ConioConsoleFromProcessData(ProcessData, &Console);
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if (NT_SUCCESS(Status))
{
if(Request->Data.WriteConsoleOutputCharRequest.Unicode)
{
Length = WideCharToMultiByte(Console->CodePage, 0,
(PWCHAR)Request->Data.WriteConsoleOutputCharRequest.String,
Request->Data.WriteConsoleOutputCharRequest.Length,
NULL, 0, NULL, NULL);
tmpString = String = RtlAllocateHeap(GetProcessHeap(), 0, Length);
if (String)
{
WideCharToMultiByte(Console->CodePage, 0,
(PWCHAR)Request->Data.WriteConsoleOutputCharRequest.String,
Request->Data.WriteConsoleOutputCharRequest.Length,
String, Length, NULL, NULL);
}
else
{
Status = STATUS_NO_MEMORY;
}
}
else
{
String = (PCHAR)Request->Data.WriteConsoleOutputCharRequest.String;
}
if (String)
{
Status = ConioLockScreenBuffer(ProcessData,
Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle,
&Buff);
if (NT_SUCCESS(Status))
{
X = Request->Data.WriteConsoleOutputCharRequest.Coord.X + Buff->ShowX;
Y = (Request->Data.WriteConsoleOutputCharRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
Length = Request->Data.WriteConsoleOutputCharRequest.Length;
Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
while (Length--)
{
*Buffer = *String++;
Written++;
Buffer += 2;
if (++X == Buff->MaxX)
{
if (++Y == Buff->MaxY)
{
Y = 0;
Buffer = Buff->Buffer;
}
X = 0;
}
}
if (NULL != Console && Buff == Console->ActiveBuffer)
{
ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputCharRequest.Coord,
Request->Data.WriteConsoleOutputCharRequest.Length);
ConioDrawRegion(Console, &UpdateRect);
}
Request->Data.WriteConsoleOutputCharRequest.EndCoord.X = X - Buff->ShowX;
Request->Data.WriteConsoleOutputCharRequest.EndCoord.Y = (Y + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
}
if (Request->Data.WriteConsoleRequest.Unicode)
{
RtlFreeHeap(GetProcessHeap(), 0, tmpString);
}
}
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
}
Request->Data.WriteConsoleOutputCharRequest.NrCharactersWritten = Written;
return Request->Status = Status;
}
CSR_API(CsrFillOutputChar)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DWORD X, Y, Length, Written = 0;
CHAR Char;
PBYTE Buffer;
RECT UpdateRect;
DPRINT("CsrFillOutputChar\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, &Buff);
if (! NT_SUCCESS(Status))
{
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = Status;
}
X = Request->Data.FillOutputRequest.Position.X + Buff->ShowX;
Y = (Request->Data.FillOutputRequest.Position.Y + Buff->ShowY) % Buff->MaxY;
Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
if(Request->Data.FillOutputRequest.Unicode)
ConsoleUnicodeCharToAnsiChar(Console, &Char, &Request->Data.FillOutputRequest.Char.UnicodeChar);
else
Char = Request->Data.FillOutputRequest.Char.AsciiChar;
Length = Request->Data.FillOutputRequest.Length;
while (Length--)
{
*Buffer = Char;
Buffer += 2;
Written++;
if (++X == Buff->MaxX)
{
if (++Y == Buff->MaxY)
{
Y = 0;
Buffer = Buff->Buffer;
}
X = 0;
}
}
if (NULL != Console && Buff == Console->ActiveBuffer)
{
ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputRequest.Position,
Request->Data.FillOutputRequest.Length);
ConioDrawRegion(Console, &UpdateRect);
}
ConioUnlockScreenBuffer(Buff);
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
Length = Request->Data.FillOutputRequest.Length;
Request->Data.FillOutputRequest.NrCharactersWritten = Length;
return Request->Status;
}
CSR_API(CsrReadInputEvent)
{
PLIST_ENTRY CurrentEntry;
PCSRSS_CONSOLE Console;
NTSTATUS Status;
BOOLEAN Done = FALSE;
ConsoleInput *Input;
DPRINT("CsrReadInputEvent\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Request->Data.ReadInputRequest.Event = ProcessData->ConsoleEvent;
Status = ConioLockConsole(ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
/* only get input if there is any */
CurrentEntry = Console->InputEvents.Flink;
while (CurrentEntry != &Console->InputEvents)
{
Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
CurrentEntry = CurrentEntry->Flink;
if (Done && !Input->Fake)
{
Request->Data.ReadInputRequest.MoreEvents = TRUE;
break;
}
RemoveEntryList(&Input->ListEntry);
if (!Done && !Input->Fake)
{
Request->Data.ReadInputRequest.Input = Input->InputEvent;
if (Request->Data.ReadInputRequest.Unicode == FALSE)
{
ConioInputEventToAnsi(Console, &Request->Data.ReadInputRequest.Input);
}
Done = TRUE;
}
if (Input->InputEvent.EventType == KEY_EVENT)
{
if (0 != (Console->Mode & ENABLE_LINE_INPUT)
&& Input->InputEvent.Event.KeyEvent.bKeyDown
&& '\r' == Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
{
Console->WaitingLines--;
}
Console->WaitingChars--;
}
HeapFree(Win32CsrApiHeap, 0, Input);
}
if (Done)
{
Status = STATUS_SUCCESS;
Console->EarlyReturn = FALSE;
}
else
{
Status = STATUS_PENDING;
Console->EarlyReturn = TRUE; /* mark for early return */
}
if (IsListEmpty(&Console->InputEvents))
{
ResetEvent(Console->ActiveEvent);
}
ConioUnlockConsole(Console);
return Request->Status = Status;
}
CSR_API(CsrWriteConsoleOutputAttrib)
{
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
PUCHAR Buffer;
PWORD Attribute;
int X, Y, Length;
NTSTATUS Status;
RECT UpdateRect;
DPRINT("CsrWriteConsoleOutputAttrib\n");
if (Request->Header.u1.s1.TotalLength
< CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_ATTRIB)
+ Request->Data.WriteConsoleOutputAttribRequest.Length * sizeof(WORD))
{
DPRINT1("Invalid request size\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
return Request->Status = STATUS_INVALID_PARAMETER;
}
Status = ConioConsoleFromProcessData(ProcessData, &Console);
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Status = ConioLockScreenBuffer(ProcessData,
Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle,
&Buff);
if (! NT_SUCCESS(Status))
{
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = Status;
}
X = Request->Data.WriteConsoleOutputAttribRequest.Coord.X + Buff->ShowX;
Y = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
Length = Request->Data.WriteConsoleOutputAttribRequest.Length;
Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + 1];
Attribute = Request->Data.WriteConsoleOutputAttribRequest.Attribute;
while (Length--)
{
*Buffer = (UCHAR)(*Attribute++);
Buffer += 2;
if (++X == Buff->MaxX)
{
if (++Y == Buff->MaxY)
{
Y = 0;
Buffer = Buff->Buffer + 1;
}
X = 0;
}
}
if (NULL != Console && Buff == Console->ActiveBuffer)
{
ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputAttribRequest.Coord,
Request->Data.WriteConsoleOutputAttribRequest.Length);
ConioDrawRegion(Console, &UpdateRect);
}
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
Request->Data.WriteConsoleOutputAttribRequest.EndCoord.X = Buff->CurrentX - Buff->ShowX;
Request->Data.WriteConsoleOutputAttribRequest.EndCoord.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrFillOutputAttrib)
{
PCSRSS_SCREEN_BUFFER Buff;
PUCHAR Buffer;
NTSTATUS Status;
int X, Y, Length;
UCHAR Attr;
RECT UpdateRect;
PCSRSS_CONSOLE Console;
DPRINT("CsrFillOutputAttrib\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, &Buff);
if (! NT_SUCCESS(Status))
{
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = Status;
}
X = Request->Data.FillOutputAttribRequest.Coord.X + Buff->ShowX;
Y = (Request->Data.FillOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
Length = Request->Data.FillOutputAttribRequest.Length;
Attr = Request->Data.FillOutputAttribRequest.Attribute;
Buffer = &Buff->Buffer[(Y * Buff->MaxX * 2) + (X * 2) + 1];
while (Length--)
{
*Buffer = Attr;
Buffer += 2;
if (++X == Buff->MaxX)
{
if (++Y == Buff->MaxY)
{
Y = 0;
Buffer = Buff->Buffer + 1;
}
X = 0;
}
}
if (NULL != Console && Buff == Console->ActiveBuffer)
{
ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputAttribRequest.Coord,
Request->Data.FillOutputAttribRequest.Length);
ConioDrawRegion(Console, &UpdateRect);
}
ConioUnlockScreenBuffer(Buff);
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrGetCursorInfo)
{
PCSRSS_SCREEN_BUFFER Buff;
NTSTATUS Status;
DPRINT("CsrGetCursorInfo\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockScreenBuffer(ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, &Buff);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Data.GetCursorInfoRequest.Info.bVisible = Buff->CursorInfo.bVisible;
Request->Data.GetCursorInfoRequest.Info.dwSize = Buff->CursorInfo.dwSize;
ConioUnlockScreenBuffer(Buff);
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrSetCursorInfo)
{
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DWORD Size;
BOOL Visible;
NTSTATUS Status;
DPRINT("CsrSetCursorInfo\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorInfoRequest.ConsoleHandle, &Buff);
if (! NT_SUCCESS(Status))
{
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = Status;
}
Size = Request->Data.SetCursorInfoRequest.Info.dwSize;
Visible = Request->Data.SetCursorInfoRequest.Info.bVisible;
if (Size < 1)
{
Size = 1;
}
if (100 < Size)
{
Size = 100;
}
if (Size != Buff->CursorInfo.dwSize
|| (Visible && ! Buff->CursorInfo.bVisible) || (! Visible && Buff->CursorInfo.bVisible))
{
Buff->CursorInfo.dwSize = Size;
Buff->CursorInfo.bVisible = Visible;
if (NULL != Console && ! ConioSetCursorInfo(Console, Buff))
{
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return Request->Status = STATUS_UNSUCCESSFUL;
}
}
ConioUnlockScreenBuffer(Buff);
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrSetTextAttrib)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
LONG OldCursorX, OldCursorY;
DPRINT("CsrSetTextAttrib\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff);
if (! NT_SUCCESS(Status))
{
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = Status;
}
ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY, &OldCursorX, &OldCursorY);
Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
if (NULL != Console && Buff == Console->ActiveBuffer)
{
if (! ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
{
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return Request->Status = STATUS_UNSUCCESSFUL;
}
}
ConioUnlockScreenBuffer(Buff);
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrSetConsoleMode)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DPRINT("CsrSetConsoleMode\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = Win32CsrGetObject(ProcessData,
Request->Data.SetConsoleModeRequest.ConsoleHandle,
(Object_t **) &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Buff = (PCSRSS_SCREEN_BUFFER)Console;
if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
{
Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
}
else if (CONIO_SCREEN_BUFFER_MAGIC == Console->Header.Type)
{
Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
}
else
{
return Request->Status = STATUS_INVALID_HANDLE;
}
Request->Status = STATUS_SUCCESS;
return Request->Status;
}
CSR_API(CsrGetConsoleMode)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff; /* gee, I really wish I could use an anonymous union here */
DPRINT("CsrGetConsoleMode\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = Win32CsrGetObject(ProcessData, Request->Data.GetConsoleModeRequest.ConsoleHandle,
(Object_t **) &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Status = STATUS_SUCCESS;
Buff = (PCSRSS_SCREEN_BUFFER) Console;
if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
{
Request->Data.GetConsoleModeRequest.ConsoleMode = Console->Mode;
}
else if (CONIO_SCREEN_BUFFER_MAGIC == Buff->Header.Type)
{
Request->Data.GetConsoleModeRequest.ConsoleMode = Buff->Mode;
}
else
{
Request->Status = STATUS_INVALID_HANDLE;
}
return Request->Status;
}
CSR_API(CsrCreateScreenBuffer)
{
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
NTSTATUS Status;
DPRINT("CsrCreateScreenBuffer\n");
if (ProcessData == NULL)
{
return Request->Status = STATUS_INVALID_PARAMETER;
}
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
if (NULL == Console)
{
return Request->Status = STATUS_INVALID_HANDLE;
}
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Buff = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
if (Buff != NULL)
{
if (Console->ActiveBuffer)
{
Buff->MaxX = Console->ActiveBuffer->MaxX;
Buff->MaxY = Console->ActiveBuffer->MaxY;
Buff->CursorInfo.bVisible = Console->ActiveBuffer->CursorInfo.bVisible;
Buff->CursorInfo.dwSize = Console->ActiveBuffer->CursorInfo.dwSize;
}
else
{
Buff->CursorInfo.bVisible = TRUE;
Buff->CursorInfo.dwSize = 5;
}
if (Buff->MaxX == 0)
{
Buff->MaxX = 80;
}
if (Buff->MaxY == 0)
{
Buff->MaxY = 25;
}
Status = CsrInitConsoleScreenBuffer(Console, Buff);
if(! NT_SUCCESS(Status))
{
Request->Status = Status;
}
else
{
Request->Status = Win32CsrInsertObject(ProcessData, &Request->Data.CreateScreenBufferRequest.OutputHandle, &Buff->Header);
}
}
else
{
Request->Status = STATUS_INSUFFICIENT_RESOURCES;
}
ConioUnlockConsole(Console);
return Request->Status;
}
CSR_API(CsrSetScreenBuffer)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DPRINT("CsrSetScreenBuffer\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
if (NULL == Console)
{
DPRINT1("Trying to set screen buffer for app without console\n");
return Request->Status = STATUS_INVALID_HANDLE;
}
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetScreenBufferRequest.OutputHandle, &Buff);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return Request->Status;
}
if (Buff == Console->ActiveBuffer)
{
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return STATUS_SUCCESS;
}
/* drop reference to old buffer, maybe delete */
if (! InterlockedDecrement(&Console->ActiveBuffer->Header.ReferenceCount))
{
ConioDeleteScreenBuffer((Object_t *) Console->ActiveBuffer);
}
/* tie console to new buffer */
Console->ActiveBuffer = Buff;
/* inc ref count on new buffer */
InterlockedIncrement(&Buff->Header.ReferenceCount);
/* Redraw the console */
ConioDrawConsole(Console);
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrSetTitle)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
PWCHAR Buffer;
DPRINT("CsrSetTitle\n");
if (Request->Header.u1.s1.TotalLength
< CSR_API_MESSAGE_HEADER_SIZE(CSRSS_SET_TITLE)
+ Request->Data.SetTitleRequest.Length)
{
DPRINT1("Invalid request size\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
return Request->Status = STATUS_INVALID_PARAMETER;
}
Status = ConioLockConsole(ProcessData, Request->Data.SetTitleRequest.Console, &Console);
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if(! NT_SUCCESS(Status))
{
Request->Status = Status;
}
else
{
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Request->Data.SetTitleRequest.Length);
if (Buffer)
{
/* copy title to console */
RtlFreeUnicodeString(&Console->Title);
Console->Title.Buffer = Buffer;
Console->Title.Length = Console->Title.MaximumLength = Request->Data.SetTitleRequest.Length;
memcpy(Console->Title.Buffer, Request->Data.SetTitleRequest.Title, Console->Title.Length);
if (! ConioChangeTitle(Console))
{
Request->Status = STATUS_UNSUCCESSFUL;
}
else
{
Request->Status = STATUS_SUCCESS;
}
}
else
{
Request->Status = STATUS_NO_MEMORY;
}
}
ConioUnlockConsole(Console);
return Request->Status;
}
CSR_API(CsrGetTitle)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
DWORD Length;
DPRINT("CsrGetTitle\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockConsole(ProcessData,
Request->Data.GetTitleRequest.ConsoleHandle,
&Console);
if (! NT_SUCCESS(Status))
{
DPRINT1("Can't get console\n");
return Request->Status = Status;
}
/* Copy title of the console to the user title buffer */
RtlZeroMemory(&Request->Data.GetTitleRequest, sizeof(CSRSS_GET_TITLE));
Request->Data.GetTitleRequest.ConsoleHandle = Request->Data.GetTitleRequest.ConsoleHandle;
Request->Data.GetTitleRequest.Length = Console->Title.Length;
memcpy (Request->Data.GetTitleRequest.Title, Console->Title.Buffer,
Console->Title.Length);
Length = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_SET_TITLE) + Console->Title.Length;
ConioUnlockConsole(Console);
if (Length > sizeof(CSR_API_MESSAGE))
{
Request->Header.u1.s1.TotalLength = Length;
Request->Header.u1.s1.DataLength = Length - sizeof(PORT_MESSAGE);
}
Request->Status = STATUS_SUCCESS;
return Request->Status;
}
CSR_API(CsrWriteConsoleOutput)
{
SHORT i, X, Y, SizeX, SizeY;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
RECT ScreenBuffer;
CHAR_INFO* CurCharInfo;
RECT WriteRegion;
CHAR_INFO* CharInfo;
COORD BufferCoord;
COORD BufferSize;
NTSTATUS Status;
DWORD Offset;
DWORD PSize;
DPRINT("CsrWriteConsoleOutput\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockScreenBuffer(ProcessData,
Request->Data.WriteConsoleOutputRequest.ConsoleHandle,
&Buff);
if (! NT_SUCCESS(Status))
{
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = Status;
}
BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
PSize = BufferSize.X * BufferSize.Y * sizeof(CHAR_INFO);
BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase) ||
(((ULONG_PTR)CharInfo + PSize) >
((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
{
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return Request->Status = STATUS_ACCESS_VIOLATION;
}
WriteRegion.left = Request->Data.WriteConsoleOutputRequest.WriteRegion.Left;
WriteRegion.top = Request->Data.WriteConsoleOutputRequest.WriteRegion.Top;
WriteRegion.right = Request->Data.WriteConsoleOutputRequest.WriteRegion.Right;
WriteRegion.bottom = Request->Data.WriteConsoleOutputRequest.WriteRegion.Bottom;
SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&WriteRegion));
SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&WriteRegion));
WriteRegion.bottom = WriteRegion.top + SizeY - 1;
WriteRegion.right = WriteRegion.left + SizeX - 1;
/* Make sure WriteRegion is inside the screen buffer */
ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
if (! ConioGetIntersection(&WriteRegion, &ScreenBuffer, &WriteRegion))
{
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
/* It is okay to have a WriteRegion completely outside the screen buffer.
No data is written then. */
return Request->Status = STATUS_SUCCESS;
}
for (i = 0, Y = WriteRegion.top; Y <= WriteRegion.bottom; i++, Y++)
{
CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
Offset = (((Y + Buff->ShowY) % Buff->MaxY) * Buff->MaxX + WriteRegion.left) * 2;
for (X = WriteRegion.left; X <= WriteRegion.right; X++)
{
if (Request->Data.WriteConsoleOutputRequest.Unicode)
{
CHAR AsciiChar;
ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar);
SET_CELL_BUFFER(Buff, Offset, AsciiChar, CurCharInfo->Attributes);
}
else
{
SET_CELL_BUFFER(Buff, Offset, CurCharInfo->Char.AsciiChar, CurCharInfo->Attributes);
}
CurCharInfo++;
}
}
if (NULL != Console)
{
ConioDrawRegion(Console, &WriteRegion);
}
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
Request->Data.WriteConsoleOutputRequest.WriteRegion.Right = WriteRegion.left + SizeX - 1;
Request->Data.WriteConsoleOutputRequest.WriteRegion.Bottom = WriteRegion.top + SizeY - 1;
Request->Data.WriteConsoleOutputRequest.WriteRegion.Left = WriteRegion.left;
Request->Data.WriteConsoleOutputRequest.WriteRegion.Top = WriteRegion.top;
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrFlushInputBuffer)
{
PLIST_ENTRY CurrentEntry;
PCSRSS_CONSOLE Console;
ConsoleInput* Input;
NTSTATUS Status;
DPRINT("CsrFlushInputBuffer\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockConsole(ProcessData,
Request->Data.FlushInputBufferRequest.ConsoleInput,
&Console);
if(! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
/* Discard all entries in the input event queue */
while (!IsListEmpty(&Console->InputEvents))
{
CurrentEntry = RemoveHeadList(&Console->InputEvents);
Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
/* Destroy the event */
HeapFree(Win32CsrApiHeap, 0, Input);
}
ResetEvent(Console->ActiveEvent);
Console->WaitingChars=0;
ConioUnlockConsole(Console);
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrScrollConsoleScreenBuffer)
{
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
RECT ScreenBuffer;
RECT SrcRegion;
RECT DstRegion;
RECT FillRegion;
RECT ScrollRectangle;
RECT ClipRectangle;
NTSTATUS Status;
BOOLEAN DoFill;
HANDLE ConsoleHandle;
BOOLEAN UseClipRectangle;
COORD DestinationOrigin;
CHAR_INFO Fill;
DPRINT("CsrScrollConsoleScreenBuffer\n");
ConsoleHandle = Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle;
UseClipRectangle = Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle;
DestinationOrigin = Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin;
Fill = Request->Data.ScrollConsoleScreenBufferRequest.Fill;
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockScreenBuffer(ProcessData, ConsoleHandle, &Buff);
if (! NT_SUCCESS(Status))
{
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = Status;
}
ScrollRectangle.left = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Left;
ScrollRectangle.top = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Top;
ScrollRectangle.right = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Right;
ScrollRectangle.bottom = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Bottom;
ClipRectangle.left = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Left;
ClipRectangle.top = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Top;
ClipRectangle.right = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Right;
ClipRectangle.bottom = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Bottom;
/* Make sure source rectangle is inside the screen buffer */
ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
if (! ConioGetIntersection(&SrcRegion, &ScreenBuffer, &ScrollRectangle))
{
ConioUnlockScreenBuffer(Buff);
return Request->Status = STATUS_INVALID_PARAMETER;
}
if (UseClipRectangle && ! ConioGetIntersection(&SrcRegion, &SrcRegion, &ClipRectangle))
{
ConioUnlockScreenBuffer(Buff);
return Request->Status = STATUS_SUCCESS;
}
ConioInitRect(&DstRegion,
DestinationOrigin.Y,
DestinationOrigin.X,
DestinationOrigin.Y + ConioRectHeight(&ScrollRectangle) - 1,
DestinationOrigin.X + ConioRectWidth(&ScrollRectangle) - 1);
/* Make sure destination rectangle is inside the screen buffer */
if (! ConioGetIntersection(&DstRegion, &DstRegion, &ScreenBuffer))
{
ConioUnlockScreenBuffer(Buff);
return Request->Status = STATUS_INVALID_PARAMETER;
}
ConioCopyRegion(Buff, &SrcRegion, &DstRegion);
/* Get the region that should be filled with the specified character and attributes */
DoFill = FALSE;
ConioGetUnion(&FillRegion, &SrcRegion, &DstRegion);
if (ConioSubtractRect(&FillRegion, &FillRegion, &DstRegion))
{
/* FIXME: The subtracted rectangle is off by one line */
FillRegion.top += 1;
ConioFillRegion(Console, Buff, &FillRegion, &Fill, Request->Data.ScrollConsoleScreenBufferRequest.Unicode);
DoFill = TRUE;
}
if (NULL != Console && Buff == Console->ActiveBuffer)
{
/* Draw destination region */
ConioDrawRegion(Console, &DstRegion);
if (DoFill)
{
/* Draw filled region */
ConioDrawRegion(Console, &FillRegion);
}
}
ConioUnlockScreenBuffer(Buff);
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrReadConsoleOutputChar)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DWORD Xpos, Ypos;
PCHAR ReadBuffer;
DWORD i;
ULONG CharSize;
CHAR Char;
DPRINT("CsrReadConsoleOutputChar\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
ReadBuffer = Request->Data.ReadConsoleOutputCharRequest.String;
CharSize = (Request->Data.ReadConsoleOutputCharRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, &Buff);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X + Buff->ShowX;
Ypos = (Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + Buff->ShowY) % Buff->MaxY;
for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
{
Char = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX)];
if(Request->Data.ReadConsoleOutputCharRequest.Unicode)
{
ConsoleAnsiCharToUnicodeChar(Console, (WCHAR*)ReadBuffer, &Char);
ReadBuffer += sizeof(WCHAR);
}
else
*(ReadBuffer++) = Char;
Xpos++;
if (Xpos == Buff->MaxX)
{
Xpos = 0;
Ypos++;
if (Ypos == Buff->MaxY)
{
Ypos = 0;
}
}
}
*ReadBuffer = 0;
Request->Status = STATUS_SUCCESS;
Request->Data.ReadConsoleOutputCharRequest.EndCoord.X = Xpos - Buff->ShowX;
Request->Data.ReadConsoleOutputCharRequest.EndCoord.Y = (Ypos - Buff->ShowY + Buff->MaxY) % Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
if (NULL != Console)
{
ConioUnlockConsole(Console);
}
Request->Data.ReadConsoleOutputCharRequest.CharsRead = (DWORD)((ULONG_PTR)ReadBuffer - (ULONG_PTR)Request->Data.ReadConsoleOutputCharRequest.String) / CharSize;
if (Request->Data.ReadConsoleOutputCharRequest.CharsRead * CharSize + CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_CHAR) > sizeof(CSR_API_MESSAGE))
{
Request->Header.u1.s1.TotalLength = Request->Data.ReadConsoleOutputCharRequest.CharsRead * CharSize + CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_CHAR);
Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
}
return Request->Status;
}
CSR_API(CsrReadConsoleOutputAttrib)
{
NTSTATUS Status;
PCSRSS_SCREEN_BUFFER Buff;
DWORD Xpos, Ypos;
PWORD ReadBuffer;
DWORD i;
DWORD CurrentLength;
DPRINT("CsrReadConsoleOutputAttrib\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
ReadBuffer = Request->Data.ReadConsoleOutputAttribRequest.Attribute;
Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, &Buff);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X + Buff->ShowX;
Ypos = (Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + Buff->ShowY) % Buff->MaxY;
for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
{
*ReadBuffer = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX) + 1];
ReadBuffer++;
Xpos++;
if (Xpos == Buff->MaxX)
{
Xpos = 0;
Ypos++;
if (Ypos == Buff->MaxY)
{
Ypos = 0;
}
}
}
*ReadBuffer = 0;
Request->Status = STATUS_SUCCESS;
Request->Data.ReadConsoleOutputAttribRequest.EndCoord.X = Xpos - Buff->ShowX;
Request->Data.ReadConsoleOutputAttribRequest.EndCoord.Y = (Ypos - Buff->ShowY + Buff->MaxY) % Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
CurrentLength = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_ATTRIB)
+ Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead * sizeof(WORD);
if (CurrentLength > sizeof(CSR_API_MESSAGE))
{
Request->Header.u1.s1.TotalLength = CurrentLength;
Request->Header.u1.s1.DataLength = CurrentLength - sizeof(PORT_MESSAGE);
}
return Request->Status;
}
CSR_API(CsrGetNumberOfConsoleInputEvents)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
PLIST_ENTRY CurrentItem;
DWORD NumEvents;
ConsoleInput *Input;
DPRINT("CsrGetNumberOfConsoleInputEvents\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
CurrentItem = Console->InputEvents.Flink;
NumEvents = 0;
/* If there are any events ... */
while (CurrentItem != &Console->InputEvents)
{
Input = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
CurrentItem = CurrentItem->Flink;
if (!Input->Fake)
{
NumEvents++;
}
}
ConioUnlockConsole(Console);
Request->Status = STATUS_SUCCESS;
Request->Data.GetNumInputEventsRequest.NumInputEvents = NumEvents;
return Request->Status;
}
CSR_API(CsrPeekConsoleInput)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
DWORD Size;
DWORD Length;
PLIST_ENTRY CurrentItem;
PINPUT_RECORD InputRecord;
ConsoleInput* Item;
UINT NumItems;
DPRINT("CsrPeekConsoleInput\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console);
if(! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
Length = Request->Data.PeekConsoleInputRequest.Length;
Size = Length * sizeof(INPUT_RECORD);
if (((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
|| (((ULONG_PTR)InputRecord + Size) > ((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
{
ConioUnlockConsole(Console);
Request->Status = STATUS_ACCESS_VIOLATION;
return Request->Status ;
}
NumItems = 0;
if (! IsListEmpty(&Console->InputEvents))
{
CurrentItem = Console->InputEvents.Flink;
while (CurrentItem != &Console->InputEvents && NumItems < Length)
{
Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
if (Item->Fake)
{
CurrentItem = CurrentItem->Flink;
continue;
}
++NumItems;
*InputRecord = Item->InputEvent;
if (Request->Data.ReadInputRequest.Unicode == FALSE)
{
ConioInputEventToAnsi(Console, InputRecord);
}
InputRecord++;
CurrentItem = CurrentItem->Flink;
}
}
ConioUnlockConsole(Console);
Request->Status = STATUS_SUCCESS;
Request->Data.PeekConsoleInputRequest.Length = NumItems;
return Request->Status;
}
CSR_API(CsrReadConsoleOutput)
{
PCHAR_INFO CharInfo;
PCHAR_INFO CurCharInfo;
PCSRSS_SCREEN_BUFFER Buff;
DWORD Size;
DWORD Length;
DWORD SizeX, SizeY;
NTSTATUS Status;
COORD BufferSize;
COORD BufferCoord;
RECT ReadRegion;
RECT ScreenRect;
DWORD i, Offset;
LONG X, Y;
UINT CodePage;
DPRINT("CsrReadConsoleOutput\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputRequest.ConsoleHandle, &Buff);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
CharInfo = Request->Data.ReadConsoleOutputRequest.CharInfo;
ReadRegion.left = Request->Data.ReadConsoleOutputRequest.ReadRegion.Left;
ReadRegion.top = Request->Data.ReadConsoleOutputRequest.ReadRegion.Top;
ReadRegion.right = Request->Data.ReadConsoleOutputRequest.ReadRegion.Right;
ReadRegion.bottom = Request->Data.ReadConsoleOutputRequest.ReadRegion.Bottom;
BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
Length = BufferSize.X * BufferSize.Y;
Size = Length * sizeof(CHAR_INFO);
/* FIXME: Is this correct? */
CodePage = ProcessData->Console->OutputCodePage;
if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
|| (((ULONG_PTR)CharInfo + Size) > ((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
{
ConioUnlockScreenBuffer(Buff);
Request->Status = STATUS_ACCESS_VIOLATION;
return Request->Status ;
}
SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&ReadRegion));
SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&ReadRegion));
ReadRegion.bottom = ReadRegion.top + SizeY;
ReadRegion.right = ReadRegion.left + SizeX;
ConioInitRect(&ScreenRect, 0, 0, Buff->MaxY, Buff->MaxX);
if (! ConioGetIntersection(&ReadRegion, &ScreenRect, &ReadRegion))
{
ConioUnlockScreenBuffer(Buff);
Request->Status = STATUS_SUCCESS;
return Request->Status;
}
for (i = 0, Y = ReadRegion.top; Y < ReadRegion.bottom; ++i, ++Y)
{
CurCharInfo = CharInfo + (i * BufferSize.X);
Offset = (((Y + Buff->ShowY) % Buff->MaxY) * Buff->MaxX + ReadRegion.left) * 2;
for (X = ReadRegion.left; X < ReadRegion.right; ++X)
{
if (Request->Data.ReadConsoleOutputRequest.Unicode)
{
MultiByteToWideChar(CodePage, 0,
(PCHAR)&GET_CELL_BUFFER(Buff, Offset), 1,
&CurCharInfo->Char.UnicodeChar, 1);
}
else
{
CurCharInfo->Char.AsciiChar = GET_CELL_BUFFER(Buff, Offset);
}
CurCharInfo->Attributes = GET_CELL_BUFFER(Buff, Offset);
++CurCharInfo;
}
}
ConioUnlockScreenBuffer(Buff);
Request->Status = STATUS_SUCCESS;
Request->Data.ReadConsoleOutputRequest.ReadRegion.Right = ReadRegion.left + SizeX - 1;
Request->Data.ReadConsoleOutputRequest.ReadRegion.Bottom = ReadRegion.top + SizeY - 1;
Request->Data.ReadConsoleOutputRequest.ReadRegion.Left = ReadRegion.left;
Request->Data.ReadConsoleOutputRequest.ReadRegion.Top = ReadRegion.top;
return Request->Status;
}
CSR_API(CsrWriteConsoleInput)
{
PINPUT_RECORD InputRecord;
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DWORD Length;
DWORD Size;
DWORD i;
ConsoleInput* Record;
DPRINT("CsrWriteConsoleInput\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockConsole(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
Length = Request->Data.WriteConsoleInputRequest.Length;
Size = Length * sizeof(INPUT_RECORD);
if (((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
|| (((ULONG_PTR)InputRecord + Size) > ((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
{
ConioUnlockConsole(Console);
Request->Status = STATUS_ACCESS_VIOLATION;
return Request->Status ;
}
for (i = 0; i < Length; i++)
{
Record = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
if (NULL == Record)
{
ConioUnlockConsole(Console);
Request->Status = STATUS_INSUFFICIENT_RESOURCES;
return Request->Status;
}
Record->Echoed = FALSE;
Record->Fake = FALSE;
//Record->InputEvent = *InputRecord++;
memcpy(&Record->InputEvent, &InputRecord[i], sizeof(INPUT_RECORD));
if (KEY_EVENT == Record->InputEvent.EventType)
{
/* FIXME - convert from unicode to ascii!! */
ConioProcessChar(Console, Record);
}
}
ConioUnlockConsole(Console);
Request->Status = STATUS_SUCCESS;
Request->Data.WriteConsoleInputRequest.Length = i;
return Request->Status;
}
/**********************************************************************
* HardwareStateProperty
*
* DESCRIPTION
* Set/Get the value of the HardwareState and switch
* between direct video buffer ouput and GDI windowed
* output.
* ARGUMENTS
* Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
* object. We use the same object to Request.
* NOTE
* ConsoleHwState has the correct size to be compatible
* with NT's, but values are not.
*/
static NTSTATUS FASTCALL
SetConsoleHardwareState (PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
{
DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
{
if (Console->HardwareState != ConsoleHwState)
{
/* TODO: implement switching from full screen to windowed mode */
/* TODO: or back; now simply store the hardware state */
Console->HardwareState = ConsoleHwState;
}
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */
}
CSR_API(CsrHardwareStateProperty)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrHardwareStateProperty\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioLockConsole(ProcessData,
Request->Data.ConsoleHardwareStateRequest.ConsoleHandle,
&Console);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to get console handle in SetConsoleHardwareState\n");
return Request->Status = Status;
}
switch (Request->Data.ConsoleHardwareStateRequest.SetGet)
{
case CONSOLE_HARDWARE_STATE_GET:
Request->Data.ConsoleHardwareStateRequest.State = Console->HardwareState;
break;
case CONSOLE_HARDWARE_STATE_SET:
DPRINT("Setting console hardware state.\n");
Request->Status = SetConsoleHardwareState(Console, Request->Data.ConsoleHardwareStateRequest.State);
break;
default:
Request->Status = STATUS_INVALID_PARAMETER_2; /* Client: (handle, [set_get], mode) */
break;
}
ConioUnlockConsole(Console);
return Request->Status;
}
CSR_API(CsrGetConsoleWindow)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrGetConsoleWindow\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Data.GetConsoleWindowRequest.WindowHandle = Console->hWindow;
ConioUnlockConsole(Console);
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrSetConsoleIcon)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrSetConsoleIcon\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Console->hWindowIcon = Request->Data.SetConsoleIconRequest.WindowIcon;
Request->Status = (ConioChangeIcon(Console) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
ConioUnlockConsole(Console);
return Request->Status;
}
CSR_API(CsrGetConsoleCodePage)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrGetConsoleCodePage\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Request->Data.GetConsoleCodePage.CodePage = Console->CodePage;
ConioUnlockConsole(Console);
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrSetConsoleCodePage)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrSetConsoleCodePage\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if (IsValidCodePage(Request->Data.SetConsoleCodePage.CodePage))
{
Console->CodePage = Request->Data.SetConsoleCodePage.CodePage;
ConioUnlockConsole(Console);
return Request->Status = STATUS_SUCCESS;
}
ConioUnlockConsole(Console);
return Request->Status = STATUS_UNSUCCESSFUL;
}
CSR_API(CsrGetConsoleOutputCodePage)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrGetConsoleOutputCodePage\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Request->Data.GetConsoleOutputCodePage.CodePage = Console->OutputCodePage;
ConioUnlockConsole(Console);
return Request->Status = STATUS_SUCCESS;
}
CSR_API(CsrSetConsoleOutputCodePage)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrSetConsoleOutputCodePage\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if (IsValidCodePage(Request->Data.SetConsoleOutputCodePage.CodePage))
{
Console->OutputCodePage = Request->Data.SetConsoleOutputCodePage.CodePage;
ConioUnlockConsole(Console);
return Request->Status = STATUS_SUCCESS;
}
ConioUnlockConsole(Console);
return Request->Status = STATUS_UNSUCCESSFUL;
}
CSR_API(CsrGetProcessList)
{
PHANDLE Buffer;
PCSRSS_CONSOLE Console;
PCSRSS_PROCESS_DATA current;
PLIST_ENTRY current_entry;
ULONG nItems, nCopied, Length;
NTSTATUS Status;
DPRINT("CsrGetProcessList\n");
Buffer = Request->Data.GetProcessListRequest.ProcessId;
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
nItems = nCopied = 0;
Request->Data.GetProcessListRequest.nProcessIdsCopied = 0;
Request->Data.GetProcessListRequest.nProcessIdsTotal = 0;
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Request->Status = Status;
}
DPRINT1("Console_Api Ctrl-C\n");
for(current_entry = Console->ProcessList.Flink;
current_entry != &Console->ProcessList;
current_entry = current_entry->Flink)
{
current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
if(++nItems < Request->Data.GetProcessListRequest.nMaxIds)
{
*(Buffer++) = current->ProcessId;
nCopied++;
}
}
ConioUnlockConsole(Console);
Request->Data.GetProcessListRequest.nProcessIdsCopied = nCopied;
Request->Data.GetProcessListRequest.nProcessIdsTotal = nItems;
Length = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_GET_PROCESS_LIST) + nCopied * sizeof(HANDLE);
if (Length > sizeof(CSR_API_MESSAGE))
{
Request->Header.u1.s1.TotalLength = Length;
Request->Header.u1.s1.DataLength = Length - sizeof(PORT_MESSAGE);
}
return Request->Status = STATUS_SUCCESS;
}
/* EOF */