reactos/win32ss/user/consrv/conoutput.c
Hermès Bélusca-Maïto f4d53fbd91 [KERNEL32-CONSRV]
- Introduce a CONSOLE_PROPS structure to hold console properties such as its title or startup attributes it should have. Initialized at console application launch time. I have to see how could it be possible to merge this structure with some parts of the GUI_CONSOLE_DATA structure and of the ConsoleInfo structure from console.dll (in /dll/cpl).
- Use a helper function to initialize the CONSOLE_PROPS structure in kernel32, at console app start or when calling AllocConsole.
- In BasepInitConsole, do initialization of CONSOLE_PROPS and related only if we are about to launch a console app.

[CONSRV]
- Adapt CONSOLE_CONNECTION_INFO and CONSOLE_ALLOCCONSOLE structures to take into account CONSOLE_PROPS.
- Fix the way we are setting console titles.
- Add experimental support for loading console properties and title and icon from shell links, thanks to the helper LoadShellLinkInfo. However I'm using there Shell COM facility to extract link properties (I could do it "the RAW way", however I would then know the format of link files, that I don't know and that I don't want to mix up with the console code). Therefore I must add dependencies to uuid and ole32 libraries. Note that icons are used in GUI consoles only (use the PrivateExtractIconExW function to retrieve both handles to the big and small icons at the same time).

Part 1/2

[CONSRV]
- Remove an unuseful xxxInitScreenBuffer function in the virtual functions console table.
- In GUI_CONSOLE_DATA structure and related functions, temporarily explicitely mark which members may be used for both GUI and TUI consoles (for a future simplification).
- Add temporary debug prints when we are setting console icon, to see the flow of calls (will be removed just before merging back to trunk).
- Add temporary debug prints in ConSrvInitConsoleScreenBuffer and ConioDeleteScreenBuffer, to figure out how SBs are initialized.

svn path=/branches/ros-csrss/; revision=58305
2013-02-10 12:36:57 +00:00

1493 lines
46 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/consrv/conoutput.c
* PURPOSE: Console I/O functions
* PROGRAMMERS:
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "conio.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
#define TAB_WIDTH 8
#define ConioInitRect(Rect, top, left, bottom, right) \
do { \
((Rect)->Top) = top; \
((Rect)->Left) = left; \
((Rect)->Bottom) = bottom; \
((Rect)->Right) = right; \
} while(0)
#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)
/* PRIVATE FUNCTIONS **********************************************************/
PBYTE FASTCALL
ConioCoordToPointer(PCONSOLE_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
{
return &Buff->Buffer[2 * (((Y + Buff->VirtualY) % Buff->MaxY) * Buff->MaxX + X)];
}
static VOID FASTCALL
ClearLineBuffer(PCONSOLE_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
ConSrvInitConsoleScreenBuffer(PCONSOLE Console,
PCONSOLE_SCREEN_BUFFER Buffer)
{
DPRINT1("ConSrvInitConsoleScreenBuffer 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 = RtlAllocateHeap(ConSrvHeap, HEAP_ZERO_MEMORY, Buffer->MaxX * Buffer->MaxY * 2);
if (NULL == Buffer->Buffer)
{
DPRINT1("ConSrvInitConsoleScreenBuffer - D'oh!\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Buffer->DefaultAttrib = DEFAULT_ATTRIB;
/* 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(PCONSOLE_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(PCONSOLE Console, PCONSOLE_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 we are in processed mode, interpret special characters and
* display them correctly. Otherwise, just put them into the buffer.
*/
if (Buff->Mode & ENABLE_PROCESSED_OUTPUT)
{
/* --- CR --- */
if (Buffer[i] == '\r')
{
Buff->CurrentX = 0;
UpdateRect.Left = min(UpdateRect.Left, (LONG)Buff->CurrentX);
UpdateRect.Right = max(UpdateRect.Right, (LONG)Buff->CurrentX);
continue;
}
/* --- LF --- */
else 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;
}
/* --- TAB --- */
else if (Buffer[i] == '\t')
{
UINT EndX;
UpdateRect.Left = min(UpdateRect.Left, (LONG)Buff->CurrentX);
EndX = (Buff->CurrentX + TAB_WIDTH) & ~(TAB_WIDTH - 1);
EndX = min(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;
}
/* --- BEL ---*/
else if (Buffer[i] == '\a')
{
DPRINT1("Bell\n");
SendNotifyMessage(Console->hWindow, PM_CONSOLE_BEEP, 0, 0);
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(PCONSOLE_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;
}
}
VOID WINAPI
ConioDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
{
PCONSOLE Console = Buffer->Header.Console;
DPRINT1("ConioDeleteScreenBuffer(Buffer = 0x%p, Buffer->Buffer = 0x%p) ; Console = 0x%p\n", Buffer, Buffer->Buffer, Console);
RemoveEntryList(&Buffer->ListEntry);
if (Buffer == Console->ActiveBuffer)
{
/* Deleted active buffer; switch to most recently created */
Console->ActiveBuffer = NULL;
if (!IsListEmpty(&Console->BufferList))
{
DPRINT1("ConioDeleteScreenBuffer - Bang !!!!!!!!\n");
Console->ActiveBuffer = CONTAINING_RECORD(Console->BufferList.Flink, CONSOLE_SCREEN_BUFFER, ListEntry);
ConioDrawConsole(Console);
}
}
RtlFreeHeap(ConSrvHeap, 0, Buffer->Buffer);
RtlFreeHeap(ConSrvHeap, 0, Buffer);
}
VOID FASTCALL
ConioDrawConsole(PCONSOLE Console)
{
SMALL_RECT Region;
ConioInitRect(&Region, 0, 0, Console->Size.Y - 1, Console->Size.X - 1);
ConioDrawRegion(Console, &Region);
}
static VOID FASTCALL
ConioComputeUpdateRect(PCONSOLE_SCREEN_BUFFER Buff, SMALL_RECT* UpdateRect, PCOORD 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;
}
}
DWORD FASTCALL
ConioEffectiveCursorSize(PCONSOLE 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;
}
static NTSTATUS
DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
IN PCSR_THREAD ClientThread,
IN BOOL CreateWaitBlock OPTIONAL);
// Wait function CSR_WAIT_FUNCTION
static BOOLEAN
WriteConsoleThread(IN PLIST_ENTRY WaitList,
IN PCSR_THREAD WaitThread,
IN PCSR_API_MESSAGE WaitApiMessage,
IN PVOID WaitContext,
IN PVOID WaitArgument1,
IN PVOID WaitArgument2,
IN ULONG WaitFlags)
{
NTSTATUS Status;
DPRINT1("WriteConsoleThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
/*
* If we are notified of the process termination via a call
* to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
* CsrDestroyThread, just return.
*/
if (WaitFlags & CsrProcessTerminating)
{
Status = STATUS_THREAD_IS_TERMINATING;
goto Quit;
}
Status = DoWriteConsole(WaitApiMessage,
WaitThread,
FALSE);
Quit:
if (Status != STATUS_PENDING)
{
WaitApiMessage->Status = Status;
}
return (Status == STATUS_PENDING ? FALSE : TRUE);
}
static NTSTATUS
DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
IN PCSR_THREAD ClientThread,
IN BOOL CreateWaitBlock OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
PCHAR Buffer;
DWORD Written = 0;
ULONG Length;
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(ClientThread->Process), WriteConsoleRequest->OutputHandle, &Buff, GENERIC_WRITE, FALSE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
// if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION))
if (Console->PauseFlags && Console->UnpauseEvent != NULL)
{
if (CreateWaitBlock)
{
if (!CsrCreateWait(&Console->WriteWaitQueue,
WriteConsoleThread,
ClientThread,
ApiMessage,
NULL,
NULL))
{
/* Fail */
ConSrvReleaseScreenBuffer(Buff, FALSE);
return STATUS_NO_MEMORY;
}
}
/* Wait until we un-pause the console */
Status = STATUS_PENDING;
}
else
{
if (WriteConsoleRequest->Unicode)
{
Length = WideCharToMultiByte(Console->OutputCodePage, 0,
(PWCHAR)WriteConsoleRequest->Buffer,
WriteConsoleRequest->NrCharactersToWrite,
NULL, 0, NULL, NULL);
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 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(RtlGetProcessHeap(), 0, Buffer);
}
}
WriteConsoleRequest->NrCharactersWritten = Written;
}
ConSrvReleaseScreenBuffer(Buff, FALSE);
return Status;
}
/* PUBLIC APIS ****************************************************************/
CSR_API(SrvReadConsoleOutput)
{
PCONSOLE_READOUTPUT ReadOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCHAR_INFO CharInfo;
PCHAR_INFO CurCharInfo;
PCONSOLE_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");
CharInfo = ReadOutputRequest->CharInfo;
ReadRegion = ReadOutputRequest->ReadRegion;
BufferSize = ReadOutputRequest->BufferSize;
BufferCoord = ReadOutputRequest->BufferCoord;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ReadOutputRequest->CharInfo,
BufferSize.X * BufferSize.Y,
sizeof(CHAR_INFO)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetScreenBuffer(ProcessData, ReadOutputRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
/* FIXME: Is this correct? */
CodePage = ProcessData->Console->OutputCodePage;
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))
{
ConSrvReleaseScreenBuffer(Buff, TRUE);
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 (ReadOutputRequest->Unicode)
{
// ConsoleAnsiCharToUnicodeChar(ProcessData->Console, (PCHAR)Ptr++, &CurCharInfo->Char.UnicodeChar);
MultiByteToWideChar(CodePage, 0,
(PCHAR)Ptr++, 1,
&CurCharInfo->Char.UnicodeChar, 1);
}
else
{
CurCharInfo->Char.AsciiChar = *Ptr++;
}
CurCharInfo->Attributes = *Ptr++;
++CurCharInfo;
}
}
ConSrvReleaseScreenBuffer(Buff, TRUE);
ReadOutputRequest->ReadRegion.Right = ReadRegion.Left + SizeX - 1;
ReadOutputRequest->ReadRegion.Bottom = ReadRegion.Top + SizeY - 1;
ReadOutputRequest->ReadRegion.Left = ReadRegion.Left;
ReadOutputRequest->ReadRegion.Top = ReadRegion.Top;
return STATUS_SUCCESS;
}
CSR_API(SrvWriteConsole)
{
NTSTATUS Status;
PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
DPRINT("SrvWriteConsole\n");
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&WriteConsoleRequest->Buffer,
WriteConsoleRequest->BufferSize,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
Status = DoWriteConsole(ApiMessage,
CsrGetClientThread(),
TRUE);
if (Status == STATUS_PENDING)
*ReplyCode = CsrReplyPending;
return Status;
}
CSR_API(SrvWriteConsoleOutput)
{
PCONSOLE_WRITEOUTPUT WriteOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
SHORT i, X, Y, SizeX, SizeY;
PCONSOLE Console;
PCONSOLE_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");
BufferSize = WriteOutputRequest->BufferSize;
BufferCoord = WriteOutputRequest->BufferCoord;
CharInfo = WriteOutputRequest->CharInfo;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&WriteOutputRequest->CharInfo,
BufferSize.X * BufferSize.Y,
sizeof(CHAR_INFO)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetScreenBuffer(ProcessData,
WriteOutputRequest->OutputHandle,
&Buff,
GENERIC_WRITE,
TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
WriteRegion = WriteOutputRequest->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))
{
ConSrvReleaseScreenBuffer(Buff, TRUE);
/* 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 (WriteOutputRequest->Unicode)
{
ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar);
}
else
{
AsciiChar = CurCharInfo->Char.AsciiChar;
}
*Ptr++ = AsciiChar;
*Ptr++ = CurCharInfo->Attributes;
CurCharInfo++;
}
}
ConioDrawRegion(Console, &WriteRegion);
ConSrvReleaseScreenBuffer(Buff, TRUE);
WriteOutputRequest->WriteRegion.Right = WriteRegion.Left + SizeX - 1;
WriteOutputRequest->WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
WriteOutputRequest->WriteRegion.Left = WriteRegion.Left;
WriteOutputRequest->WriteRegion.Top = WriteRegion.Top;
return STATUS_SUCCESS;
}
CSR_API(SrvReadConsoleOutputString)
{
NTSTATUS Status;
PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputCodeRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
USHORT CodeType;
DWORD Xpos, Ypos;
PVOID ReadBuffer;
DWORD i;
ULONG CodeSize;
BYTE Code;
DPRINT("SrvReadConsoleOutputString\n");
CodeType = ReadOutputCodeRequest->CodeType;
switch (CodeType)
{
case CODE_ASCII:
CodeSize = sizeof(CHAR);
break;
case CODE_UNICODE:
CodeSize = sizeof(WCHAR);
break;
case CODE_ATTRIBUTE:
CodeSize = sizeof(WORD);
break;
default:
return STATUS_INVALID_PARAMETER;
}
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ReadOutputCodeRequest->pCode.pCode,
ReadOutputCodeRequest->NumCodesToRead,
CodeSize))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ReadOutputCodeRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
ReadBuffer = ReadOutputCodeRequest->pCode.pCode;
Xpos = ReadOutputCodeRequest->ReadCoord.X;
Ypos = (ReadOutputCodeRequest->ReadCoord.Y + Buff->VirtualY) % Buff->MaxY;
/*
* MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
*
* If the number of attributes (resp. characters) to be read from extends
* beyond the end of the specified screen buffer row, attributes (resp.
* characters) are read from the next row. If the number of attributes
* (resp. characters) to be read from extends beyond the end of the console
* screen buffer, attributes (resp. characters) up to the end of the console
* screen buffer are read.
*
* TODO: Do NOT loop up to NumCodesToRead, but stop before
* if we are going to overflow...
*/
for (i = 0; i < ReadOutputCodeRequest->NumCodesToRead; ++i)
{
Code = Buff->Buffer[2 * (Xpos + Ypos * Buff->MaxX) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)];
switch (CodeType)
{
case CODE_UNICODE:
ConsoleAnsiCharToUnicodeChar(Console, (PWCHAR)ReadBuffer, (PCHAR)&Code);
break;
case CODE_ASCII:
*(PCHAR)ReadBuffer = (CHAR)Code;
break;
case CODE_ATTRIBUTE:
*(PWORD)ReadBuffer = (WORD)Code;
break;
}
ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
Xpos++;
if (Xpos == Buff->MaxX)
{
Xpos = 0;
Ypos++;
if (Ypos == Buff->MaxY)
{
Ypos = 0;
}
}
}
// switch (CodeType)
// {
// case CODE_UNICODE:
// *(PWCHAR)ReadBuffer = 0;
// break;
// case CODE_ASCII:
// *(PCHAR)ReadBuffer = 0;
// break;
// case CODE_ATTRIBUTE:
// *(PWORD)ReadBuffer = 0;
// break;
// }
ReadOutputCodeRequest->EndCoord.X = Xpos;
ReadOutputCodeRequest->EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
ConSrvReleaseScreenBuffer(Buff, TRUE);
ReadOutputCodeRequest->CodesRead = (DWORD)((ULONG_PTR)ReadBuffer - (ULONG_PTR)ReadOutputCodeRequest->pCode.pCode) / CodeSize;
// <= ReadOutputCodeRequest->NumCodesToRead
return STATUS_SUCCESS;
}
CSR_API(SrvWriteConsoleOutputString)
{
NTSTATUS Status;
PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputCodeRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
USHORT CodeType;
PBYTE Buffer; // PUCHAR
PCHAR String, tmpString = NULL;
DWORD X, Y, Length; // , Written = 0;
ULONG CodeSize;
SMALL_RECT UpdateRect;
DPRINT("SrvWriteConsoleOutputString\n");
CodeType = WriteOutputCodeRequest->CodeType;
switch (CodeType)
{
case CODE_ASCII:
CodeSize = sizeof(CHAR);
break;
case CODE_UNICODE:
CodeSize = sizeof(WCHAR);
break;
case CODE_ATTRIBUTE:
CodeSize = sizeof(WORD);
break;
default:
return STATUS_INVALID_PARAMETER;
}
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&WriteOutputCodeRequest->pCode.pCode,
WriteOutputCodeRequest->Length,
CodeSize))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
WriteOutputCodeRequest->OutputHandle,
&Buff,
GENERIC_WRITE,
TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
switch (CodeType)
{
case CODE_UNICODE:
{
Length = WideCharToMultiByte(Console->OutputCodePage, 0,
(PWCHAR)WriteOutputCodeRequest->pCode.UnicodeChar,
WriteOutputCodeRequest->Length,
NULL, 0, NULL, NULL);
tmpString = String = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
if (String)
{
WideCharToMultiByte(Console->OutputCodePage, 0,
(PWCHAR)WriteOutputCodeRequest->pCode.UnicodeChar,
WriteOutputCodeRequest->Length,
String, Length, NULL, NULL);
}
else
{
Status = STATUS_NO_MEMORY;
}
break;
}
case CODE_ASCII:
String = (PCHAR)WriteOutputCodeRequest->pCode.AsciiChar;
break;
case CODE_ATTRIBUTE:
default:
// *(ReadBuffer++) = Code;
String = (PCHAR)WriteOutputCodeRequest->pCode.Attribute;
break;
}
if (String && NT_SUCCESS(Status))
{
X = WriteOutputCodeRequest->Coord.X;
Y = (WriteOutputCodeRequest->Coord.Y + Buff->VirtualY) % Buff->MaxY;
Length = WriteOutputCodeRequest->Length;
Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)];
while (Length--)
{
*Buffer = *String++;
// ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
String = (PCHAR)((ULONG_PTR)String + CodeSize);
// Written++;
Buffer += 2;
if (++X == Buff->MaxX)
{
if (++Y == Buff->MaxY)
{
Y = 0;
Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0);
}
X = 0;
}
}
if (Buff == Console->ActiveBuffer)
{
ConioComputeUpdateRect(Buff, &UpdateRect, &WriteOutputCodeRequest->Coord,
WriteOutputCodeRequest->Length);
ConioDrawRegion(Console, &UpdateRect);
}
WriteOutputCodeRequest->EndCoord.X = X;
WriteOutputCodeRequest->EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
}
if (tmpString)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString);
}
ConSrvReleaseScreenBuffer(Buff, TRUE);
// WriteOutputCodeRequest->NrCharactersWritten = Written;
return Status;
}
CSR_API(SrvFillConsoleOutput)
{
NTSTATUS Status;
PCONSOLE_FILLOUTPUTCODE FillOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
DWORD X, Y, Length; // , Written = 0;
USHORT CodeType;
BYTE Code;
PBYTE Buffer;
SMALL_RECT UpdateRect;
DPRINT("SrvFillConsoleOutput\n");
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), FillOutputRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
CodeType = FillOutputRequest->CodeType;
X = FillOutputRequest->Coord.X;
Y = (FillOutputRequest->Coord.Y + Buff->VirtualY) % Buff->MaxY;
Length = FillOutputRequest->Length;
Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)];
switch (CodeType)
{
case CODE_ASCII:
Code = (BYTE)FillOutputRequest->Code.AsciiChar;
break;
case CODE_UNICODE:
ConsoleUnicodeCharToAnsiChar(Console, (PCHAR)&Code, &FillOutputRequest->Code.UnicodeChar);
break;
case CODE_ATTRIBUTE:
Code = (BYTE)FillOutputRequest->Code.Attribute;
break;
default:
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_INVALID_PARAMETER;
}
while (Length--)
{
*Buffer = Code;
Buffer += 2;
// Written++;
if (++X == Buff->MaxX)
{
if (++Y == Buff->MaxY)
{
Y = 0;
Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0);
}
X = 0;
}
}
if (Buff == Console->ActiveBuffer)
{
ConioComputeUpdateRect(Buff, &UpdateRect, &FillOutputRequest->Coord,
FillOutputRequest->Length);
ConioDrawRegion(Console, &UpdateRect);
}
ConSrvReleaseScreenBuffer(Buff, TRUE);
/*
Length = FillOutputRequest->Length;
FillOutputRequest->NrCharactersWritten = Length;
*/
return STATUS_SUCCESS;
}
CSR_API(SrvGetConsoleCursorInfo)
{
NTSTATUS Status;
PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
PCONSOLE_SCREEN_BUFFER Buff;
DPRINT("SrvGetConsoleCursorInfo\n");
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
CursorInfoRequest->Info.bVisible = Buff->CursorInfo.bVisible;
CursorInfoRequest->Info.dwSize = Buff->CursorInfo.dwSize;
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleCursorInfo)
{
NTSTATUS Status;
PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
DWORD Size;
BOOL Visible;
DPRINT("SrvSetConsoleCursorInfo\n");
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
Size = CursorInfoRequest->Info.dwSize;
Visible = CursorInfoRequest->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))
{
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_UNSUCCESSFUL;
}
}
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleCursorPosition)
{
NTSTATUS Status;
PCONSOLE_SETCURSORPOSITION SetCursorPositionRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorPositionRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
LONG OldCursorX, OldCursorY;
LONG NewCursorX, NewCursorY;
DPRINT("SrvSetConsoleCursorPosition\n");
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetCursorPositionRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
NewCursorX = SetCursorPositionRequest->Position.X;
NewCursorY = SetCursorPositionRequest->Position.Y;
if ( NewCursorX < 0 || NewCursorX >= Buff->MaxX ||
NewCursorY < 0 || NewCursorY >= Buff->MaxY )
{
ConSrvReleaseScreenBuffer(Buff, TRUE);
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))
{
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_UNSUCCESSFUL;
}
}
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleTextAttribute)
{
NTSTATUS Status;
PCONSOLE_SETTEXTATTRIB SetTextAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetTextAttribRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
DPRINT("SrvSetConsoleTextAttribute\n");
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetTextAttribRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
Buff->DefaultAttrib = SetTextAttribRequest->Attrib;
if (Buff == Console->ActiveBuffer)
{
if (!ConioUpdateScreenInfo(Console, Buff))
{
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_UNSUCCESSFUL;
}
}
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvCreateConsoleScreenBuffer)
{
NTSTATUS Status;
PCONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CreateScreenBufferRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
DPRINT("SrvCreateConsoleScreenBuffer\n");
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (!NT_SUCCESS(Status))
{
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return Status;
}
Buff = RtlAllocateHeap(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CONSOLE_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 = ConSrvInitConsoleScreenBuffer(Console, Buff);
if (NT_SUCCESS(Status))
{
Status = ConSrvInsertObject(ProcessData,
&CreateScreenBufferRequest->OutputHandle,
&Buff->Header,
CreateScreenBufferRequest->Access,
CreateScreenBufferRequest->Inheritable,
CreateScreenBufferRequest->ShareMode);
}
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
ConSrvReleaseConsole(Console, TRUE);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return Status;
}
CSR_API(SrvGetConsoleScreenBufferInfo)
{
NTSTATUS Status;
PCONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScreenBufferInfoRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
PCONSOLE_SCREEN_BUFFER_INFO pInfo = &ScreenBufferInfoRequest->Info;
DPRINT("SrvGetConsoleScreenBufferInfo\n");
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ScreenBufferInfoRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
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;
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleActiveScreenBuffer)
{
NTSTATUS Status;
PCONSOLE_SETACTIVESCREENBUFFER SetScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
DPRINT("SrvSetConsoleActiveScreenBuffer\n");
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetScreenBufferRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
if (Buff == Console->ActiveBuffer)
{
ConSrvReleaseScreenBuffer(Buff, TRUE);
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);
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvScrollConsoleScreenBuffer)
{
PCONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScrollScreenBufferRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
SMALL_RECT ScreenBuffer;
SMALL_RECT SrcRegion;
SMALL_RECT DstRegion;
SMALL_RECT UpdateRegion;
SMALL_RECT ScrollRectangle;
SMALL_RECT ClipRectangle;
NTSTATUS Status;
HANDLE OutputHandle;
BOOLEAN UseClipRectangle;
COORD DestinationOrigin;
CHAR_INFO Fill;
CHAR FillChar;
DPRINT("SrvScrollConsoleScreenBuffer\n");
OutputHandle = ScrollScreenBufferRequest->OutputHandle;
UseClipRectangle = ScrollScreenBufferRequest->UseClipRectangle;
DestinationOrigin = ScrollScreenBufferRequest->DestinationOrigin;
Fill = ScrollScreenBufferRequest->Fill;
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), OutputHandle, &Buff, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
ScrollRectangle = ScrollScreenBufferRequest->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))
{
ConSrvReleaseScreenBuffer(Buff, TRUE);
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 = ScrollScreenBufferRequest->ClipRectangle;
if (!ConioGetIntersection(&ClipRectangle, &ClipRectangle, &ScreenBuffer))
{
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_SUCCESS;
}
}
else
{
ClipRectangle = ScreenBuffer;
}
ConioInitRect(&DstRegion,
DestinationOrigin.Y,
DestinationOrigin.X,
DestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
DestinationOrigin.X + ConioRectWidth(&SrcRegion) - 1);
if (ScrollScreenBufferRequest->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);
}
}
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleScreenBufferSize)
{
NTSTATUS Status;
PCONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferSizeRequest;
PCONSOLE_SCREEN_BUFFER Buff;
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetScreenBufferSizeRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConioResizeBuffer(Buff->Header.Console, Buff, SetScreenBufferSizeRequest->Size);
ConSrvReleaseScreenBuffer(Buff, TRUE);
return Status;
}
/* EOF */