reactos/subsystems/win32/csrss/win32csr/conio.c
Timo Kreuzer 9ea495ba33 Create a branch for header work.
svn path=/branches/header-work/; revision=45691
2010-02-26 22:57:55 +00:00

3122 lines
93 KiB
C

/*
* reactos/subsys/csrss/win32csr/conio.c
*
* Console I/O functions
*
* ReactOS Operating System
*/
/* INCLUDES ******************************************************************/
#define NDEBUG
#include "w32csr.h"
#include <debug.h>
/* 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 ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
WideCharToMultiByte((Console)->CodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
#define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \
WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
#define ConsoleAnsiCharToUnicodeChar(Console, sWChar, dChar) \
MultiByteToWideChar((Console)->OutputCodePage, 0, (dChar), 1, (sWChar), 1)
/* FUNCTIONS *****************************************************************/
NTSTATUS FASTCALL
ConioConsoleFromProcessData(PCSRSS_PROCESS_DATA ProcessData, PCSRSS_CONSOLE *Console)
{
PCSRSS_CONSOLE ProcessConsole = ProcessData->Console;
if (!ProcessConsole)
{
*Console = NULL;
return STATUS_INVALID_HANDLE;
}
InterlockedIncrement(&ProcessConsole->Header.ReferenceCount);
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,
UlongToPtr(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, 0);
}
PBYTE FASTCALL
ConioCoordToPointer(PCSRSS_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
{
return &Buff->Buffer[2 * (((Y + Buff->VirtualY) % Buff->MaxY) * Buff->MaxX + X)];
}
static VOID FASTCALL
ClearLineBuffer(PCSRSS_SCREEN_BUFFER Buff)
{
PBYTE Ptr = ConioCoordToPointer(Buff, 0, Buff->CurrentY);
UINT Pos;
for (Pos = 0; Pos < Buff->MaxX; Pos++)
{
/* Fill the cell */
*Ptr++ = ' ';
*Ptr++ = 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->VirtualY = 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 WINAPI
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));
if (NULL == NewBuffer)
{
RtlFreeUnicodeString(&Console->Title);
DeleteCriticalSection(&Console->Header.Lock);
CloseHandle(Console->ActiveEvent);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* init screen buffer with defaults */
NewBuffer->CursorInfo.bVisible = TRUE;
NewBuffer->CursorInfo.dwSize = CSR_DEFAULT_CURSOR_SIZE;
/* make console active, and insert into console list */
Console->ActiveBuffer = (PCSRSS_SCREEN_BUFFER) NewBuffer;
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;
}
/* add a reference count because the buffer is tied to the console */
InterlockedIncrement(&Console->ActiveBuffer->Header.ReferenceCount);
/* 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->Console)
{
DPRINT1("Process already has a console\n");
return STATUS_INVALID_PARAMETER;
}
/* 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");
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 */
Status = CsrInitConsole(Console);
if (!NT_SUCCESS(Status))
{
DPRINT1("Console init failed\n");
HeapFree(Win32CsrApiHeap, 0, Console);
return 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 = Win32CsrInsertObject(ProcessData,
&Request->Data.AllocConsoleRequest.InputHandle,
&Console->Header,
GENERIC_READ | GENERIC_WRITE,
TRUE);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to insert object\n");
ConioDeleteConsole((Object_t *) Console);
ProcessData->Console = 0;
return Status;
}
Status = Win32CsrInsertObject(ProcessData,
&Request->Data.AllocConsoleRequest.OutputHandle,
&Console->ActiveBuffer->Header,
GENERIC_READ | GENERIC_WRITE,
TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to insert object\n");
ConioDeleteConsole((Object_t *) Console);
Win32CsrReleaseObject(ProcessData,
Request->Data.AllocConsoleRequest.InputHandle);
ProcessData->Console = 0;
return 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 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->Console == NULL)
{
return STATUS_INVALID_PARAMETER;
}
Console = ProcessData->Console;
ProcessData->Console = NULL;
RemoveEntryList(&ProcessData->ProcessEntry);
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)
{
/* If we hit bottom, slide the viewable screen */
if (++Buff->CurrentY == Buff->MaxY)
{
Buff->CurrentY--;
if (++Buff->VirtualY == Buff->MaxY)
{
Buff->VirtualY = 0;
}
(*ScrolledLines)++;
ClearLineBuffer(Buff);
if (UpdateRect->top != 0)
{
UpdateRect->top--;
}
}
UpdateRect->left = 0;
UpdateRect->right = Buff->MaxX - 1;
UpdateRect->bottom = Buff->CurrentY;
}
static NTSTATUS FASTCALL
ConioWriteConsole(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff,
CHAR *Buffer, DWORD Length, BOOL Attrib)
{
UINT i;
PBYTE Ptr;
RECT UpdateRect;
LONG CursorStartX, CursorStartY;
UINT ScrolledLines;
CursorStartX = Buff->CurrentX;
CursorStartY = Buff->CurrentY;
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 || 0 != Buff->CurrentY)
{
if (0 == Buff->CurrentX)
{
/* slide virtual position up */
Buff->CurrentX = Buff->MaxX - 1;
Buff->CurrentY--;
UpdateRect.top = min(UpdateRect.top, (LONG)Buff->CurrentY);
}
else
{
Buff->CurrentX--;
}
Ptr = ConioCoordToPointer(Buff, Buff->CurrentX, Buff->CurrentY);
Ptr[0] = ' ';
Ptr[1] = 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;
}
Ptr = ConioCoordToPointer(Buff, Buff->CurrentX, Buff->CurrentY);
while (Buff->CurrentX < EndX)
{
*Ptr++ = ' ';
*Ptr++ = Buff->DefaultAttrib;
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);
Ptr = ConioCoordToPointer(Buff, Buff->CurrentX, Buff->CurrentY);
Ptr[0] = Buffer[i];
if (Attrib)
{
Ptr[1] = 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;
}
}
}
if (! ConioIsRectEmpty(&UpdateRect) && 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, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return 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))
{
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;
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)
{
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])))
{
Status = STATUS_PENDING; /* line buffered, didn't get a complete line */
}
else
{
Console->WaitingLines--;
Status = STATUS_SUCCESS; /* line buffered, did get a complete line */
}
}
else
{
Status = STATUS_SUCCESS; /* not line buffered, did read something */
}
if (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 Status;
}
__inline BOOLEAN 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;
}
__inline BOOLEAN 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;
}
/* Move from one rectangle to another. We must be careful about the order that
* this is done, to avoid overwriting parts of the source before they are moved. */
static VOID FASTCALL
ConioMoveRegion(PCSRSS_SCREEN_BUFFER ScreenBuffer,
RECT *SrcRegion,
RECT *DstRegion,
RECT *ClipRegion,
WORD Fill)
{
int Width = ConioRectWidth(SrcRegion);
int Height = ConioRectHeight(SrcRegion);
int SX, SY;
int DX, DY;
int XDelta, YDelta;
int i, j;
SY = SrcRegion->top;
DY = DstRegion->top;
YDelta = 1;
if (SY < DY)
{
/* Moving down: work from bottom up */
SY = SrcRegion->bottom;
DY = DstRegion->bottom;
YDelta = -1;
}
for (i = 0; i < Height; i++)
{
PWORD SRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, SY);
PWORD DRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, DY);
SX = SrcRegion->left;
DX = DstRegion->left;
XDelta = 1;
if (SX < DX)
{
/* Moving right: work from right to left */
SX = SrcRegion->right;
DX = DstRegion->right;
XDelta = -1;
}
for (j = 0; j < Width; j++)
{
WORD Cell = SRow[SX];
if (SX >= ClipRegion->left && SX <= ClipRegion->right
&& SY >= ClipRegion->top && SY <= ClipRegion->bottom)
{
SRow[SX] = Fill;
}
if (DX >= ClipRegion->left && DX <= ClipRegion->right
&& DY >= ClipRegion->top && DY <= ClipRegion->bottom)
{
DRow[DX] = Cell;
}
SX += XDelta;
DX += XDelta;
}
SY += YDelta;
DY += YDelta;
}
}
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;
ConsoleInputUnicodeCharToAnsiChar(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 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 Status;
}
if(Request->Data.WriteConsoleRequest.Unicode)
{
Length = WideCharToMultiByte(Console->OutputCodePage, 0,
(PWCHAR)Request->Data.WriteConsoleRequest.Buffer,
Request->Data.WriteConsoleRequest.NrCharactersToWrite,
NULL, 0, NULL, NULL);
Buffer = RtlAllocateHeap(GetProcessHeap(), 0, Length);
if (Buffer)
{
WideCharToMultiByte(Console->OutputCodePage, 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, GENERIC_WRITE);
if (NT_SUCCESS(Status))
{
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);
}
}
ConioUnlockConsole(Console);
Request->Data.WriteConsoleRequest.NrCharactersWritten = Written;
return Status;
}
VOID WINAPI
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 WINAPI
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);
}
ConioCleanupConsole(Console);
if (0 == InterlockedDecrement(&Console->ActiveBuffer->Header.ReferenceCount))
{
ConioDeleteScreenBuffer((Object_t *) Console->ActiveBuffer);
}
Console->ActiveBuffer = NULL;
CloseHandle(Console->ActiveEvent);
DeleteCriticalSection(&Console->Header.Lock);
RtlFreeUnicodeString(&Console->Title);
IntDeleteAllAliases(Console->Aliases);
HeapFree(Win32CsrApiHeap, 0, Console);
}
VOID WINAPI
CsrInitConsoleSupport(VOID)
{
DPRINT("CSR: CsrInitConsoleSupport()\n");
/* Should call LoadKeyboardLayout */
}
static VOID FASTCALL
ConioProcessChar(PCSRSS_CONSOLE Console,
ConsoleInput *KeyEventRecord)
{
BOOL updown;
ConsoleInput *TempInput;
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++;
}
}
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;
return;
}
}
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++; */
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 WINAPI
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)
{
DPRINT1("No Active Console!\n");
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)
{
HeapFree(Win32CsrApiHeap, 0, ConInRec);
return;
}
/* process Ctrl-C and Ctrl-Break */
if (Console->Mode & ENABLE_PROCESSED_INPUT &&
er.Event.KeyEvent.bKeyDown &&
((er.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) ||
(er.Event.KeyEvent.wVirtualKeyCode == 'C')) &&
(er.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, ConInRec);
return;
}
if (0 != (er.Event.KeyEvent.dwControlKeyState
& (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
&& (VK_UP == er.Event.KeyEvent.wVirtualKeyCode
|| VK_DOWN == er.Event.KeyEvent.wVirtualKeyCode))
{
if (er.Event.KeyEvent.bKeyDown)
{
/* scroll up or down */
if (VK_UP == er.Event.KeyEvent.wVirtualKeyCode)
{
/* only scroll up if there is room to scroll up into */
if (Console->ActiveBuffer->CurrentY != Console->ActiveBuffer->MaxY - 1)
{
Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY +
Console->ActiveBuffer->MaxY - 1) %
Console->ActiveBuffer->MaxY;
Console->ActiveBuffer->CurrentY++;
}
}
else
{
/* only scroll down if there is room to scroll down into */
if (Console->ActiveBuffer->CurrentY != 0)
{
Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) %
Console->ActiveBuffer->MaxY;
Console->ActiveBuffer->CurrentY--;
}
}
ConioDrawConsole(Console);
}
HeapFree(Win32CsrApiHeap, 0, ConInRec);
return;
}
/* FIXME - convert to ascii */
ConioProcessChar(Console, ConInRec);
}
CSR_API(CsrGetScreenBufferInfo)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
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 = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Status;
}
Status = ConioLockScreenBuffer(ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle, &Buff, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return Status;
}
pInfo = &Request->Data.ScreenBufferInfoRequest.Info;
pInfo->dwSize.X = Buff->MaxX;
pInfo->dwSize.Y = Buff->MaxY;
pInfo->dwCursorPosition.X = Buff->CurrentX;
pInfo->dwCursorPosition.Y = Buff->CurrentY;
pInfo->wAttributes = Buff->DefaultAttrib;
pInfo->srWindow.Left = Buff->ShowX;
pInfo->srWindow.Right = Buff->ShowX + Console->Size.X - 1;
pInfo->srWindow.Top = Buff->ShowY;
pInfo->srWindow.Bottom = Buff->ShowY + Console->Size.Y - 1;
pInfo->dwMaximumWindowSize.X = Buff->MaxX;
pInfo->dwMaximumWindowSize.Y = Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return STATUS_SUCCESS;
}
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 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, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return 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);
ConioUnlockConsole(Console);
return STATUS_INVALID_PARAMETER;
}
OldCursorX = Buff->CurrentX;
OldCursorY = Buff->CurrentY;
Buff->CurrentX = NewCursorX;
Buff->CurrentY = NewCursorY;
if (Buff == Console->ActiveBuffer)
{
if (! ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
{
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return STATUS_UNSUCCESSFUL;
}
}
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return 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 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->OutputCodePage, 0,
(PWCHAR)Request->Data.WriteConsoleOutputCharRequest.String,
Request->Data.WriteConsoleOutputCharRequest.Length,
NULL, 0, NULL, NULL);
tmpString = String = RtlAllocateHeap(GetProcessHeap(), 0, Length);
if (String)
{
WideCharToMultiByte(Console->OutputCodePage, 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,
GENERIC_WRITE);
if (NT_SUCCESS(Status))
{
X = Request->Data.WriteConsoleOutputCharRequest.Coord.X;
Y = (Request->Data.WriteConsoleOutputCharRequest.Coord.Y + Buff->VirtualY) % 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 (Buff == Console->ActiveBuffer)
{
ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputCharRequest.Coord,
Request->Data.WriteConsoleOutputCharRequest.Length);
ConioDrawRegion(Console, &UpdateRect);
}
Request->Data.WriteConsoleOutputCharRequest.EndCoord.X = X;
Request->Data.WriteConsoleOutputCharRequest.EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
}
if (Request->Data.WriteConsoleRequest.Unicode)
{
RtlFreeHeap(GetProcessHeap(), 0, tmpString);
}
}
ConioUnlockConsole(Console);
}
Request->Data.WriteConsoleOutputCharRequest.NrCharactersWritten = Written;
return 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 Status;
}
Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return Status;
}
X = Request->Data.FillOutputRequest.Position.X;
Y = (Request->Data.FillOutputRequest.Position.Y + Buff->VirtualY) % 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 (Buff == Console->ActiveBuffer)
{
ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputRequest.Position,
Request->Data.FillOutputRequest.Length);
ConioDrawRegion(Console, &UpdateRect);
}
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
Length = Request->Data.FillOutputRequest.Length;
Request->Data.FillOutputRequest.NrCharactersWritten = Length;
return STATUS_SUCCESS;
}
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, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return 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 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 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 Status;
}
Status = ConioLockScreenBuffer(ProcessData,
Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle,
&Buff,
GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return Status;
}
X = Request->Data.WriteConsoleOutputAttribRequest.Coord.X;
Y = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->VirtualY) % 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 (Buff == Console->ActiveBuffer)
{
ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputAttribRequest.Coord,
Request->Data.WriteConsoleOutputAttribRequest.Length);
ConioDrawRegion(Console, &UpdateRect);
}
ConioUnlockConsole(Console);
Request->Data.WriteConsoleOutputAttribRequest.EndCoord.X = X;
Request->Data.WriteConsoleOutputAttribRequest.EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
return 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 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, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return Status;
}
X = Request->Data.FillOutputAttribRequest.Coord.X;
Y = (Request->Data.FillOutputAttribRequest.Coord.Y + Buff->VirtualY) % 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 (Buff == Console->ActiveBuffer)
{
ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputAttribRequest.Coord,
Request->Data.FillOutputAttribRequest.Length);
ConioDrawRegion(Console, &UpdateRect);
}
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return 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, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return Status;
}
Request->Data.GetCursorInfoRequest.Info.bVisible = Buff->CursorInfo.bVisible;
Request->Data.GetCursorInfoRequest.Info.dwSize = Buff->CursorInfo.dwSize;
ConioUnlockScreenBuffer(Buff);
return 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 Status;
}
Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorInfoRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return 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 (! ConioSetCursorInfo(Console, Buff))
{
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return STATUS_UNSUCCESSFUL;
}
}
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return STATUS_SUCCESS;
}
CSR_API(CsrSetTextAttrib)
{
NTSTATUS Status;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DPRINT("CsrSetTextAttrib\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Status;
}
Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return Status;
}
Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
if (Buff == Console->ActiveBuffer)
{
if (! ConioUpdateScreenInfo(Console, Buff))
{
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return STATUS_UNSUCCESSFUL;
}
}
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return 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, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return 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
{
Status = STATUS_INVALID_HANDLE;
}
Win32CsrReleaseObjectByPointer((Object_t *)Console);
return 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, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return Status;
}
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
{
Status = STATUS_INVALID_HANDLE;
}
Win32CsrReleaseObjectByPointer((Object_t *)Console);
return Status;
}
CSR_API(CsrCreateScreenBuffer)
{
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
NTSTATUS Status;
DPRINT("CsrCreateScreenBuffer\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Status;
}
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 = CSR_DEFAULT_CURSOR_SIZE;
}
if (Buff->MaxX == 0)
{
Buff->MaxX = 80;
}
if (Buff->MaxY == 0)
{
Buff->MaxY = 25;
}
Status = CsrInitConsoleScreenBuffer(Console, Buff);
if(NT_SUCCESS(Status))
{
Status = Win32CsrInsertObject(ProcessData,
&Request->Data.CreateScreenBufferRequest.OutputHandle,
&Buff->Header,
Request->Data.CreateScreenBufferRequest.Access,
Request->Data.CreateScreenBufferRequest.Inheritable);
}
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
ConioUnlockConsole(Console);
return 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 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.SetScreenBufferRequest.OutputHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return 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 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 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))
{
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))
{
Status = STATUS_UNSUCCESSFUL;
}
else
{
Status = STATUS_SUCCESS;
}
}
else
{
Status = STATUS_NO_MEMORY;
}
ConioUnlockConsole(Console);
}
return 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 = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
DPRINT1("Can't get console\n");
return Status;
}
/* Copy title of the console to the user title buffer */
RtlZeroMemory(&Request->Data.GetTitleRequest, sizeof(CSRSS_GET_TITLE));
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);
}
return STATUS_SUCCESS;
}
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;
PBYTE Ptr;
DWORD PSize;
DPRINT("CsrWriteConsoleOutput\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return 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,
GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return 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 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 STATUS_SUCCESS;
}
for (i = 0, Y = WriteRegion.top; Y <= WriteRegion.bottom; i++, Y++)
{
CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
Ptr = ConioCoordToPointer(Buff, WriteRegion.left, Y);
for (X = WriteRegion.left; X <= WriteRegion.right; X++)
{
CHAR AsciiChar;
if (Request->Data.WriteConsoleOutputRequest.Unicode)
{
ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar);
}
else
{
AsciiChar = CurCharInfo->Char.AsciiChar;
}
*Ptr++ = AsciiChar;
*Ptr++ = CurCharInfo->Attributes;
CurCharInfo++;
}
}
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 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,
GENERIC_WRITE);
if(! NT_SUCCESS(Status))
{
return 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 STATUS_SUCCESS;
}
CSR_API(CsrScrollConsoleScreenBuffer)
{
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
RECT ScreenBuffer;
RECT SrcRegion;
RECT DstRegion;
RECT UpdateRegion;
RECT ScrollRectangle;
RECT ClipRectangle;
NTSTATUS Status;
HANDLE ConsoleHandle;
BOOLEAN UseClipRectangle;
COORD DestinationOrigin;
CHAR_INFO Fill;
CHAR FillChar;
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 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, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return 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;
/* 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);
ConioUnlockConsole(Console);
return STATUS_SUCCESS;
}
/* If the source was clipped on the left or top, adjust the destination accordingly */
if (ScrollRectangle.left < 0)
{
DestinationOrigin.X -= ScrollRectangle.left;
}
if (ScrollRectangle.top < 0)
{
DestinationOrigin.Y -= ScrollRectangle.top;
}
if (UseClipRectangle)
{
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;
if (!ConioGetIntersection(&ClipRectangle, &ClipRectangle, &ScreenBuffer))
{
ConioUnlockConsole(Console);
ConioUnlockScreenBuffer(Buff);
return STATUS_SUCCESS;
}
}
else
{
ClipRectangle = ScreenBuffer;
}
ConioInitRect(&DstRegion,
DestinationOrigin.Y,
DestinationOrigin.X,
DestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
DestinationOrigin.X + ConioRectWidth(&SrcRegion) - 1);
if (Request->Data.ScrollConsoleScreenBufferRequest.Unicode)
ConsoleUnicodeCharToAnsiChar(Console, &FillChar, &Fill.Char.UnicodeChar);
else
FillChar = Fill.Char.AsciiChar;
ConioMoveRegion(Buff, &SrcRegion, &DstRegion, &ClipRectangle, Fill.Attributes << 8 | (BYTE)FillChar);
if (Buff == Console->ActiveBuffer)
{
ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &ClipRectangle))
{
/* Draw update region */
ConioDrawRegion(Console, &UpdateRegion);
}
}
ConioUnlockScreenBuffer(Buff);
ConioUnlockConsole(Console);
return 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 Status;
}
Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, &Buff, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
ConioUnlockConsole(Console);
return Status;
}
Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X;
Ypos = (Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + Buff->VirtualY) % 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->Data.ReadConsoleOutputCharRequest.EndCoord.X = Xpos;
Request->Data.ReadConsoleOutputCharRequest.EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
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 STATUS_SUCCESS;
}
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, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return Status;
}
Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X;
Ypos = (Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + Buff->VirtualY) % 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->Data.ReadConsoleOutputAttribRequest.EndCoord.X = Xpos;
Request->Data.ReadConsoleOutputAttribRequest.EndCoord.Y = (Ypos - Buff->VirtualY + 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 STATUS_SUCCESS;
}
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, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return 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->Data.GetNumInputEventsRequest.NumInputEvents = NumEvents;
return STATUS_SUCCESS;
}
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, GENERIC_READ);
if(! NT_SUCCESS(Status))
{
return 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);
return STATUS_ACCESS_VIOLATION;
}
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->Data.PeekConsoleInputRequest.Length = NumItems;
return STATUS_SUCCESS;
}
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;
PBYTE Ptr;
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, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return 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);
return STATUS_ACCESS_VIOLATION;
}
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);
return STATUS_SUCCESS;
}
for (i = 0, Y = ReadRegion.top; Y < ReadRegion.bottom; ++i, ++Y)
{
CurCharInfo = CharInfo + (i * BufferSize.X);
Ptr = ConioCoordToPointer(Buff, ReadRegion.left, Y);
for (X = ReadRegion.left; X < ReadRegion.right; ++X)
{
if (Request->Data.ReadConsoleOutputRequest.Unicode)
{
MultiByteToWideChar(CodePage, 0,
(PCHAR)Ptr++, 1,
&CurCharInfo->Char.UnicodeChar, 1);
}
else
{
CurCharInfo->Char.AsciiChar = *Ptr++;
}
CurCharInfo->Attributes = *Ptr++;
++CurCharInfo;
}
}
ConioUnlockScreenBuffer(Buff);
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 STATUS_SUCCESS;
}
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, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return 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);
return STATUS_ACCESS_VIOLATION;
}
for (i = 0; i < Length; i++)
{
Record = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
if (NULL == Record)
{
ConioUnlockConsole(Console);
return STATUS_INSUFFICIENT_RESOURCES;
}
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->Data.WriteConsoleInputRequest.Length = i;
return STATUS_SUCCESS;
}
/**********************************************************************
* 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,
GENERIC_READ);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to get console handle in SetConsoleHardwareState\n");
return 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");
Status = SetConsoleHardwareState(Console, Request->Data.ConsoleHardwareStateRequest.State);
break;
default:
Status = STATUS_INVALID_PARAMETER_2; /* Client: (handle, [set_get], mode) */
break;
}
ConioUnlockConsole(Console);
return 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 Status;
}
Request->Data.GetConsoleWindowRequest.WindowHandle = Console->hWindow;
ConioUnlockConsole(Console);
return 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 Status;
}
Status = (ConioChangeIcon(Console, Request->Data.SetConsoleIconRequest.WindowIcon)
? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
ConioUnlockConsole(Console);
return Status;
}
CSR_API(CsrGetConsoleCodePage)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrGetConsoleCodePage\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return 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 STATUS_SUCCESS;
}
CSR_API(CsrSetConsoleCodePage)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrSetConsoleCodePage\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return 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 STATUS_SUCCESS;
}
ConioUnlockConsole(Console);
return STATUS_INVALID_PARAMETER;
}
CSR_API(CsrGetConsoleOutputCodePage)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrGetConsoleOutputCodePage\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return 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 STATUS_SUCCESS;
}
CSR_API(CsrSetConsoleOutputCodePage)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status;
DPRINT("CsrSetConsoleOutputCodePage\n");
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return 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 STATUS_SUCCESS;
}
ConioUnlockConsole(Console);
return STATUS_INVALID_PARAMETER;
}
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 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 STATUS_SUCCESS;
}
CSR_API(CsrGenerateCtrlEvent)
{
PCSRSS_CONSOLE Console;
PCSRSS_PROCESS_DATA current;
PLIST_ENTRY current_entry;
DWORD Group;
NTSTATUS Status;
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 Status;
}
Group = Request->Data.GenerateCtrlEvent.ProcessGroup;
Status = STATUS_INVALID_PARAMETER;
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 (Group == 0 || current->ProcessGroup == Group)
{
ConioConsoleCtrlEvent(Request->Data.GenerateCtrlEvent.Event, current);
Status = STATUS_SUCCESS;
}
}
ConioUnlockConsole(Console);
return Status;
}
/* EOF */