reactos/win32ss/user/consrv/conoutput.c

1481 lines
45 KiB
C
Raw Normal View History

/*
* reactos/win32ss/user/consrv/conio.c
*
* Console I/O functions
*
* ReactOS Operating System
*/
/* INCLUDES ******************************************************************/
#include "consrv.h"
#include "conio.h"
#define NDEBUG
#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 ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \
WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
#define ConsoleAnsiCharToUnicodeChar(Console, dWChar, sChar) \
MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1)
/* FUNCTIONS *****************************************************************/
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;
}
}
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.Console = Console;
Buffer->Header.HandleCount = 0;
Buffer->ShowX = 0;
Buffer->ShowY = 0;
Buffer->VirtualY = 0;
Buffer->Buffer = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, Buffer->MaxX * Buffer->MaxY * 2);
if (NULL == Buffer->Buffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
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;
InsertHeadList(&Console->BufferList, &Buffer->ListEntry);
return STATUS_SUCCESS;
}
static VOID FASTCALL
ConioNextLine(PCSRSS_SCREEN_BUFFER Buff, SMALL_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;
}
NTSTATUS FASTCALL
ConioWriteConsole(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff,
CHAR *Buffer, DWORD Length, BOOL Attrib)
{
UINT i;
PBYTE Ptr;
SMALL_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;
}
__inline BOOLEAN ConioGetIntersection(
SMALL_RECT *Intersection,
SMALL_RECT *Rect1,
SMALL_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(
SMALL_RECT *Union,
SMALL_RECT *Rect1,
SMALL_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,
SMALL_RECT *SrcRegion,
SMALL_RECT *DstRegion,
SMALL_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;
}
}
CSR_API(SrvWriteConsole)
{
NTSTATUS Status;
PCSRSS_WRITE_CONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
PCHAR Buffer;
PCSRSS_SCREEN_BUFFER Buff;
PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
PCSRSS_CONSOLE Console;
DWORD Written = 0;
ULONG Length;
ULONG CharSize = (WriteConsoleRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
DPRINT("SrvWriteConsole\n");
if (ApiMessage->Header.u1.s1.TotalLength
< CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE)
+ (WriteConsoleRequest->NrCharactersToWrite * CharSize))
{
DPRINT1("Invalid ApiMessage size\n");
return STATUS_INVALID_PARAMETER;
}
Status = ConioLockScreenBuffer(ProcessData, WriteConsoleRequest->ConsoleHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
if (Console->UnpauseEvent)
{
Status = NtDuplicateObject(GetCurrentProcess(), Console->UnpauseEvent,
ProcessData->ProcessHandle, &WriteConsoleRequest->UnpauseEvent,
SYNCHRONIZE, 0, 0);
ConioUnlockScreenBuffer(Buff);
return NT_SUCCESS(Status) ? STATUS_PENDING : Status;
}
if(WriteConsoleRequest->Unicode)
{
Length = WideCharToMultiByte(Console->OutputCodePage, 0,
(PWCHAR)WriteConsoleRequest->Buffer,
WriteConsoleRequest->NrCharactersToWrite,
NULL, 0, NULL, NULL);
Buffer = RtlAllocateHeap(GetProcessHeap(), 0, Length);
if (Buffer)
{
WideCharToMultiByte(Console->OutputCodePage, 0,
(PWCHAR)WriteConsoleRequest->Buffer,
WriteConsoleRequest->NrCharactersToWrite,
Buffer, Length, NULL, NULL);
}
else
{
Status = STATUS_NO_MEMORY;
}
}
else
{
Buffer = (PCHAR)WriteConsoleRequest->Buffer;
}
if (Buffer)
{
if (NT_SUCCESS(Status))
{
Status = ConioWriteConsole(Console, Buff, Buffer,
WriteConsoleRequest->NrCharactersToWrite, TRUE);
if (NT_SUCCESS(Status))
{
Written = WriteConsoleRequest->NrCharactersToWrite;
}
}
if (WriteConsoleRequest->Unicode)
{
RtlFreeHeap(GetProcessHeap(), 0, Buffer);
}
}
ConioUnlockScreenBuffer(Buff);
WriteConsoleRequest->NrCharactersWritten = Written;
return Status;
}
VOID WINAPI
ConioDeleteScreenBuffer(PCSRSS_SCREEN_BUFFER Buffer)
{
PCSRSS_CONSOLE Console = Buffer->Header.Console;
RemoveEntryList(&Buffer->ListEntry);
if (Buffer == Console->ActiveBuffer)
{
/* Deleted active buffer; switch to most recently created */
Console->ActiveBuffer = NULL;
if (!IsListEmpty(&Console->BufferList))
{
Console->ActiveBuffer = CONTAINING_RECORD(Console->BufferList.Flink, CSRSS_SCREEN_BUFFER, ListEntry);
ConioDrawConsole(Console);
}
}
HeapFree(ConSrvHeap, 0, Buffer->Buffer);
HeapFree(ConSrvHeap, 0, Buffer);
}
VOID FASTCALL
ConioDrawConsole(PCSRSS_CONSOLE Console)
{
SMALL_RECT Region;
ConioInitRect(&Region, 0, 0, Console->Size.Y - 1, Console->Size.X - 1);
ConioDrawRegion(Console, &Region);
}
CSR_API(SrvGetConsoleScreenBufferInfo) // CsrGetScreenBufferInfo
{
NTSTATUS Status;
PCSRSS_SCREEN_BUFFER_INFO ScreenBufferInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScreenBufferInfoRequest;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
PCONSOLE_SCREEN_BUFFER_INFO pInfo;
DPRINT("SrvGetConsoleScreenBufferInfo\n");
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, ScreenBufferInfoRequest->ConsoleHandle, &Buff, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
pInfo = &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);
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleCursor)
{
NTSTATUS Status;
PCSRSS_SET_CURSOR SetCursorRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorRequest;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
LONG OldCursorX, OldCursorY;
LONG NewCursorX, NewCursorY;
DPRINT("SrvSetConsoleCursor\n");
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, SetCursorRequest->ConsoleHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
NewCursorX = SetCursorRequest->Position.X;
NewCursorY = SetCursorRequest->Position.Y;
if (NewCursorX < 0 || NewCursorX >= Buff->MaxX ||
NewCursorY < 0 || NewCursorY >= Buff->MaxY)
{
ConioUnlockScreenBuffer(Buff);
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);
return STATUS_UNSUCCESSFUL;
}
}
ConioUnlockScreenBuffer(Buff);
return STATUS_SUCCESS;
}
static VOID FASTCALL
ConioComputeUpdateRect(PCSRSS_SCREEN_BUFFER Buff, SMALL_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;
PCSRSS_WRITE_CONSOLE_OUTPUT_CHAR WriteConsoleOutputCharRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleOutputCharRequest;
PCHAR String, tmpString = NULL;
PBYTE Buffer;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DWORD X, Y, Length, CharSize, Written = 0;
SMALL_RECT UpdateRect;
DPRINT("CsrWriteConsoleOutputChar\n");
CharSize = (WriteConsoleOutputCharRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
if (ApiMessage->Header.u1.s1.TotalLength
< CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_CHAR)
+ (WriteConsoleOutputCharRequest->Length * CharSize))
{
DPRINT1("Invalid ApiMessage size\n");
return STATUS_INVALID_PARAMETER;
}
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process,
WriteConsoleOutputCharRequest->ConsoleHandle,
&Buff,
GENERIC_WRITE);
if (NT_SUCCESS(Status))
{
Console = Buff->Header.Console;
if(WriteConsoleOutputCharRequest->Unicode)
{
Length = WideCharToMultiByte(Console->OutputCodePage, 0,
(PWCHAR)WriteConsoleOutputCharRequest->String,
WriteConsoleOutputCharRequest->Length,
NULL, 0, NULL, NULL);
tmpString = String = RtlAllocateHeap(GetProcessHeap(), 0, Length);
if (String)
{
WideCharToMultiByte(Console->OutputCodePage, 0,
(PWCHAR)WriteConsoleOutputCharRequest->String,
WriteConsoleOutputCharRequest->Length,
String, Length, NULL, NULL);
}
else
{
Status = STATUS_NO_MEMORY;
}
}
else
{
String = (PCHAR)WriteConsoleOutputCharRequest->String;
}
if (String)
{
if (NT_SUCCESS(Status))
{
X = WriteConsoleOutputCharRequest->Coord.X;
Y = (WriteConsoleOutputCharRequest->Coord.Y + Buff->VirtualY) % Buff->MaxY;
Length = 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, &WriteConsoleOutputCharRequest->Coord,
WriteConsoleOutputCharRequest->Length);
ConioDrawRegion(Console, &UpdateRect);
}
WriteConsoleOutputCharRequest->EndCoord.X = X;
WriteConsoleOutputCharRequest->EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
}
if (WriteConsoleOutputCharRequest->Unicode)
{
RtlFreeHeap(GetProcessHeap(), 0, tmpString);
}
}
ConioUnlockScreenBuffer(Buff);
}
WriteConsoleOutputCharRequest->NrCharactersWritten = Written;
return Status;
}
CSR_API(CsrFillOutputChar)
{
NTSTATUS Status;
PCSRSS_FILL_OUTPUT FillOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputRequest;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DWORD X, Y, Length, Written = 0;
CHAR Char;
PBYTE Buffer;
SMALL_RECT UpdateRect;
DPRINT("CsrFillOutputChar\n");
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, FillOutputRequest->ConsoleHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
X = FillOutputRequest->Position.X;
Y = (FillOutputRequest->Position.Y + Buff->VirtualY) % Buff->MaxY;
Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
if(FillOutputRequest->Unicode)
ConsoleUnicodeCharToAnsiChar(Console, &Char, &FillOutputRequest->Char.UnicodeChar);
else
Char = FillOutputRequest->Char.AsciiChar;
Length = 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, &FillOutputRequest->Position,
FillOutputRequest->Length);
ConioDrawRegion(Console, &UpdateRect);
}
ConioUnlockScreenBuffer(Buff);
Length = FillOutputRequest->Length;
FillOutputRequest->NrCharactersWritten = Length;
return STATUS_SUCCESS;
}
CSR_API(CsrWriteConsoleOutputAttrib)
{
PCSRSS_WRITE_CONSOLE_OUTPUT_ATTRIB WriteConsoleOutputAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleOutputAttribRequest;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
PUCHAR Buffer;
PWORD Attribute;
int X, Y, Length;
NTSTATUS Status;
SMALL_RECT UpdateRect;
DPRINT("CsrWriteConsoleOutputAttrib\n");
if (ApiMessage->Header.u1.s1.TotalLength
< CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_ATTRIB)
+ WriteConsoleOutputAttribRequest->Length * sizeof(WORD))
{
DPRINT1("Invalid ApiMessage size\n");
return STATUS_INVALID_PARAMETER;
}
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process,
WriteConsoleOutputAttribRequest->ConsoleHandle,
&Buff,
GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
X = WriteConsoleOutputAttribRequest->Coord.X;
Y = (WriteConsoleOutputAttribRequest->Coord.Y + Buff->VirtualY) % Buff->MaxY;
Length = WriteConsoleOutputAttribRequest->Length;
Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + 1];
Attribute = 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, &WriteConsoleOutputAttribRequest->Coord,
WriteConsoleOutputAttribRequest->Length);
ConioDrawRegion(Console, &UpdateRect);
}
WriteConsoleOutputAttribRequest->EndCoord.X = X;
WriteConsoleOutputAttribRequest->EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
return STATUS_SUCCESS;
}
CSR_API(CsrFillOutputAttrib)
{
PCSRSS_FILL_OUTPUT_ATTRIB FillOutputAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputAttribRequest;
PCSRSS_SCREEN_BUFFER Buff;
PUCHAR Buffer;
NTSTATUS Status;
int X, Y, Length;
UCHAR Attr;
SMALL_RECT UpdateRect;
PCSRSS_CONSOLE Console;
DPRINT("CsrFillOutputAttrib\n");
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, FillOutputAttribRequest->ConsoleHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
X = FillOutputAttribRequest->Coord.X;
Y = (FillOutputAttribRequest->Coord.Y + Buff->VirtualY) % Buff->MaxY;
Length = FillOutputAttribRequest->Length;
Attr = 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, &FillOutputAttribRequest->Coord,
FillOutputAttribRequest->Length);
ConioDrawRegion(Console, &UpdateRect);
}
ConioUnlockScreenBuffer(Buff);
return STATUS_SUCCESS;
}
DWORD FASTCALL
ConioEffectiveCursorSize(PCSRSS_CONSOLE Console, DWORD Scale)
{
DWORD Size = (Console->ActiveBuffer->CursorInfo.dwSize * Scale + 99) / 100;
/* If line input in progress, perhaps adjust for insert toggle */
if (Console->LineBuffer && !Console->LineComplete && Console->LineInsertToggle)
return (Size * 2 <= Scale) ? (Size * 2) : (Size / 2);
return Size;
}
CSR_API(SrvGetConsoleCursorInfo)
{
NTSTATUS Status;
PCSRSS_GET_CURSOR_INFO GetCursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetCursorInfoRequest;
PCSRSS_SCREEN_BUFFER Buff;
DPRINT("SrvGetConsoleCursorInfo\n");
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, GetCursorInfoRequest->ConsoleHandle, &Buff, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return Status;
}
GetCursorInfoRequest->Info.bVisible = Buff->CursorInfo.bVisible;
GetCursorInfoRequest->Info.dwSize = Buff->CursorInfo.dwSize;
ConioUnlockScreenBuffer(Buff);
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleCursorInfo)
{
PCSRSS_SET_CURSOR_INFO SetCursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorInfoRequest;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DWORD Size;
BOOL Visible;
NTSTATUS Status;
DPRINT("SrvSetConsoleCursorInfo\n");
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, SetCursorInfoRequest->ConsoleHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
Size = SetCursorInfoRequest->Info.dwSize;
Visible = 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);
return STATUS_UNSUCCESSFUL;
}
}
ConioUnlockScreenBuffer(Buff);
return STATUS_SUCCESS;
}
CSR_API(CsrSetTextAttrib)
{
NTSTATUS Status;
PCSRSS_SET_ATTRIB SetAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetAttribRequest;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DPRINT("CsrSetTextAttrib\n");
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, SetAttribRequest->ConsoleHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
Buff->DefaultAttrib = SetAttribRequest->Attrib;
if (Buff == Console->ActiveBuffer)
{
if (! ConioUpdateScreenInfo(Console, Buff))
{
ConioUnlockScreenBuffer(Buff);
return STATUS_UNSUCCESSFUL;
}
}
ConioUnlockScreenBuffer(Buff);
return STATUS_SUCCESS;
}
CSR_API(SrvCreateConsoleScreenBuffer)
{
PCSRSS_CREATE_SCREEN_BUFFER CreateScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CreateScreenBufferRequest;
PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
NTSTATUS Status;
DPRINT("SrvCreateConsoleScreenBuffer\n");
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
Status = ConioConsoleFromProcessData(ProcessData, &Console);
if (! NT_SUCCESS(Status))
{
return Status;
}
Buff = HeapAlloc(ConSrvHeap, 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,
&CreateScreenBufferRequest->OutputHandle,
&Buff->Header,
CreateScreenBufferRequest->Access,
CreateScreenBufferRequest->Inheritable,
CreateScreenBufferRequest->ShareMode);
}
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
ConioUnlockConsole(Console);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return Status;
}
CSR_API(SrvSetConsoleActiveScreenBuffer)
{
NTSTATUS Status;
PCSRSS_SET_SCREEN_BUFFER SetScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferRequest;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DPRINT("SrvSetConsoleActiveScreenBuffer\n");
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, SetScreenBufferRequest->OutputHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
if (Buff == Console->ActiveBuffer)
{
ConioUnlockScreenBuffer(Buff);
return STATUS_SUCCESS;
}
/* If old buffer has no handles, it's now unreferenced */
if (Console->ActiveBuffer->Header.HandleCount == 0)
{
ConioDeleteScreenBuffer(Console->ActiveBuffer);
}
/* tie console to new buffer */
Console->ActiveBuffer = Buff;
/* Redraw the console */
ConioDrawConsole(Console);
ConioUnlockScreenBuffer(Buff);
return STATUS_SUCCESS;
}
CSR_API(SrvWriteConsoleOutput)
{
PCSRSS_WRITE_CONSOLE_OUTPUT WriteConsoleOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleOutputRequest;
SHORT i, X, Y, SizeX, SizeY;
PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
SMALL_RECT ScreenBuffer;
CHAR_INFO* CurCharInfo;
SMALL_RECT WriteRegion;
CHAR_INFO* CharInfo;
COORD BufferCoord;
COORD BufferSize;
NTSTATUS Status;
PBYTE Ptr;
DPRINT("SrvWriteConsoleOutput\n");
Status = ConioLockScreenBuffer(ProcessData,
WriteConsoleOutputRequest->ConsoleHandle,
&Buff,
GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
BufferSize = WriteConsoleOutputRequest->BufferSize;
BufferCoord = WriteConsoleOutputRequest->BufferCoord;
CharInfo = WriteConsoleOutputRequest->CharInfo;
if (!Win32CsrValidateBuffer(ProcessData, CharInfo,
BufferSize.X * BufferSize.Y, sizeof(CHAR_INFO)))
{
ConioUnlockScreenBuffer(Buff);
return STATUS_ACCESS_VIOLATION;
}
WriteRegion = WriteConsoleOutputRequest->WriteRegion;
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);
/* 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 (WriteConsoleOutputRequest->Unicode)
{
ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar);
}
else
{
AsciiChar = CurCharInfo->Char.AsciiChar;
}
*Ptr++ = AsciiChar;
*Ptr++ = CurCharInfo->Attributes;
CurCharInfo++;
}
}
ConioDrawRegion(Console, &WriteRegion);
ConioUnlockScreenBuffer(Buff);
WriteConsoleOutputRequest->WriteRegion.Right = WriteRegion.Left + SizeX - 1;
WriteConsoleOutputRequest->WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
WriteConsoleOutputRequest->WriteRegion.Left = WriteRegion.Left;
WriteConsoleOutputRequest->WriteRegion.Top = WriteRegion.Top;
return STATUS_SUCCESS;
}
CSR_API(SrvScrollConsoleScreenBuffer)
{
PCSRSS_SCROLL_CONSOLE_SCREEN_BUFFER ScrollConsoleScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScrollConsoleScreenBufferRequest;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
SMALL_RECT ScreenBuffer;
SMALL_RECT SrcRegion;
SMALL_RECT DstRegion;
SMALL_RECT UpdateRegion;
SMALL_RECT ScrollRectangle;
SMALL_RECT ClipRectangle;
NTSTATUS Status;
HANDLE ConsoleHandle;
BOOLEAN UseClipRectangle;
COORD DestinationOrigin;
CHAR_INFO Fill;
CHAR FillChar;
DPRINT("SrvScrollConsoleScreenBuffer\n");
ConsoleHandle = ScrollConsoleScreenBufferRequest->ConsoleHandle;
UseClipRectangle = ScrollConsoleScreenBufferRequest->UseClipRectangle;
DestinationOrigin = ScrollConsoleScreenBufferRequest->DestinationOrigin;
Fill = ScrollConsoleScreenBufferRequest->Fill;
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, ConsoleHandle, &Buff, GENERIC_WRITE);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
ScrollRectangle = ScrollConsoleScreenBufferRequest->ScrollRectangle;
/* 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 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 = ScrollConsoleScreenBufferRequest->ClipRectangle;
if (!ConioGetIntersection(&ClipRectangle, &ClipRectangle, &ScreenBuffer))
{
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 (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);
return STATUS_SUCCESS;
}
CSR_API(CsrReadConsoleOutputChar)
{
NTSTATUS Status;
PCSRSS_READ_CONSOLE_OUTPUT_CHAR ReadConsoleOutputCharRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleOutputCharRequest;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
DWORD Xpos, Ypos;
PCHAR ReadBuffer;
DWORD i;
ULONG CharSize;
CHAR Char;
DPRINT("CsrReadConsoleOutputChar\n");
ReadBuffer = ReadConsoleOutputCharRequest->String;
CharSize = (ReadConsoleOutputCharRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, ReadConsoleOutputCharRequest->ConsoleHandle, &Buff, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
Xpos = ReadConsoleOutputCharRequest->ReadCoord.X;
Ypos = (ReadConsoleOutputCharRequest->ReadCoord.Y + Buff->VirtualY) % Buff->MaxY;
for (i = 0; i < ReadConsoleOutputCharRequest->NumCharsToRead; ++i)
{
Char = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX)];
if(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;
ReadConsoleOutputCharRequest->EndCoord.X = Xpos;
ReadConsoleOutputCharRequest->EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
ReadConsoleOutputCharRequest->CharsRead = (DWORD)((ULONG_PTR)ReadBuffer - (ULONG_PTR)ReadConsoleOutputCharRequest->String) / CharSize;
if (ReadConsoleOutputCharRequest->CharsRead * CharSize + CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_CHAR) > sizeof(CSR_API_MESSAGE))
{
DPRINT1("Length won't fit in message\n");
return STATUS_BUFFER_TOO_SMALL;
}
return STATUS_SUCCESS;
}
CSR_API(CsrReadConsoleOutputAttrib)
{
NTSTATUS Status;
PCSRSS_READ_CONSOLE_OUTPUT_ATTRIB ReadConsoleOutputAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleOutputAttribRequest;
PCSRSS_SCREEN_BUFFER Buff;
DWORD Xpos, Ypos;
PWORD ReadBuffer;
DWORD i;
DWORD CurrentLength;
DPRINT("CsrReadConsoleOutputAttrib\n");
ReadBuffer = ReadConsoleOutputAttribRequest->Attribute;
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, ReadConsoleOutputAttribRequest->ConsoleHandle, &Buff, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return Status;
}
Xpos = ReadConsoleOutputAttribRequest->ReadCoord.X;
Ypos = (ReadConsoleOutputAttribRequest->ReadCoord.Y + Buff->VirtualY) % Buff->MaxY;
for (i = 0; i < 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;
ReadConsoleOutputAttribRequest->EndCoord.X = Xpos;
ReadConsoleOutputAttribRequest->EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
ConioUnlockScreenBuffer(Buff);
CurrentLength = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_ATTRIB)
+ ReadConsoleOutputAttribRequest->NumAttrsToRead * sizeof(WORD);
if (CurrentLength > sizeof(CSR_API_MESSAGE))
{
DPRINT1("Length won't fit in message\n");
return STATUS_BUFFER_TOO_SMALL;
}
return STATUS_SUCCESS;
}
CSR_API(SrvReadConsoleOutput)
{
PCSRSS_READ_CONSOLE_OUTPUT ReadConsoleOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleOutputRequest;
PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
PCHAR_INFO CharInfo;
PCHAR_INFO CurCharInfo;
PCSRSS_SCREEN_BUFFER Buff;
DWORD SizeX, SizeY;
NTSTATUS Status;
COORD BufferSize;
COORD BufferCoord;
SMALL_RECT ReadRegion;
SMALL_RECT ScreenRect;
DWORD i;
PBYTE Ptr;
LONG X, Y;
UINT CodePage;
DPRINT("SrvReadConsoleOutput\n");
Status = ConioLockScreenBuffer(ProcessData, ReadConsoleOutputRequest->ConsoleHandle, &Buff, GENERIC_READ);
if (! NT_SUCCESS(Status))
{
return Status;
}
CharInfo = ReadConsoleOutputRequest->CharInfo;
ReadRegion = ReadConsoleOutputRequest->ReadRegion;
BufferSize = ReadConsoleOutputRequest->BufferSize;
BufferCoord = ReadConsoleOutputRequest->BufferCoord;
/* FIXME: Is this correct? */
CodePage = ProcessData->Console->OutputCodePage;
if (!Win32CsrValidateBuffer(ProcessData, CharInfo,
BufferSize.X * BufferSize.Y, sizeof(CHAR_INFO)))
{
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 (ReadConsoleOutputRequest->Unicode)
{
MultiByteToWideChar(CodePage, 0,
(PCHAR)Ptr++, 1,
&CurCharInfo->Char.UnicodeChar, 1);
}
else
{
CurCharInfo->Char.AsciiChar = *Ptr++;
}
CurCharInfo->Attributes = *Ptr++;
++CurCharInfo;
}
}
ConioUnlockScreenBuffer(Buff);
ReadConsoleOutputRequest->ReadRegion.Right = ReadRegion.Left + SizeX - 1;
ReadConsoleOutputRequest->ReadRegion.Bottom = ReadRegion.Top + SizeY - 1;
ReadConsoleOutputRequest->ReadRegion.Left = ReadRegion.Left;
ReadConsoleOutputRequest->ReadRegion.Top = ReadRegion.Top;
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleScreenBufferSize)
{
NTSTATUS Status;
PCSRSS_SET_SCREEN_BUFFER_SIZE SetScreenBufferSize = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferSize;
PCSRSS_CONSOLE Console;
PCSRSS_SCREEN_BUFFER Buff;
Status = ConioLockScreenBuffer(CsrGetClientThread()->Process, SetScreenBufferSize->OutputHandle, &Buff, GENERIC_WRITE);
if (!NT_SUCCESS(Status))
{
return Status;
}
Console = Buff->Header.Console;
Status = ConioResizeBuffer(Console, Buff, SetScreenBufferSize->Size);
ConioUnlockScreenBuffer(Buff);
return Status;
}
/* EOF */