reactos/win32ss/user/winsrv/consrv/conoutput.c
2019-05-26 00:00:39 +02:00

1057 lines
40 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/conoutput.c
* PURPOSE: General Console Output Functions
* PROGRAMMERS: Jeffrey Morlan
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#define NDEBUG
#include <debug.h>
/* PUBLIC SERVER APIS *********************************************************/
/*
* FIXME: This function MUST be moved from condrv/conoutput.c because only
* consrv knows how to manipulate VDM screenbuffers.
*/
NTSTATUS NTAPI
ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN PCHAR_CELL CharInfo/*Buffer*/,
IN COORD CharInfoSize,
IN PSMALL_RECT WriteRegion);
NTSTATUS NTAPI
ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
IN PCONSOLE_SCREEN_BUFFER Buffer,
IN PSMALL_RECT Region);
CSR_API(SrvInvalidateBitMapRect)
{
NTSTATUS Status;
PCONSOLE_INVALIDATEDIBITS InvalidateDIBitsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.InvalidateDIBitsRequest;
PCONSOLE_SCREEN_BUFFER Buffer;
DPRINT("SrvInvalidateBitMapRect\n");
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
InvalidateDIBitsRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
/* In text-mode only, draw the VDM buffer if present */
if (GetType(Buffer) == TEXTMODE_BUFFER && Buffer->Header.Console->VDMBuffer)
{
PTEXTMODE_SCREEN_BUFFER TextBuffer = (PTEXTMODE_SCREEN_BUFFER)Buffer;
/*Status =*/ ConDrvWriteConsoleOutputVDM(Buffer->Header.Console,
TextBuffer,
Buffer->Header.Console->VDMBuffer,
Buffer->Header.Console->VDMBufferSize,
&InvalidateDIBitsRequest->Region);
}
Status = ConDrvInvalidateBitMapRect(Buffer->Header.Console,
Buffer,
&InvalidateDIBitsRequest->Region);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsolePalette(IN PCONSOLE Console,
// IN PGRAPHICS_SCREEN_BUFFER Buffer,
IN PCONSOLE_SCREEN_BUFFER Buffer,
IN HPALETTE PaletteHandle,
IN UINT PaletteUsage);
CSR_API(SrvSetConsolePalette)
{
NTSTATUS Status;
PCONSOLE_SETPALETTE SetPaletteRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetPaletteRequest;
// PGRAPHICS_SCREEN_BUFFER Buffer;
PCONSOLE_SCREEN_BUFFER Buffer;
DPRINT("SrvSetConsolePalette\n");
// NOTE: Tests show that this function is used only for graphics screen buffers
// and otherwise it returns FALSE + sets last error to invalid handle.
// I think it's ridiculous, because if you are in text mode, simulating
// a change of VGA palette via DAC registers (done by a call to SetConsolePalette)
// cannot be done... So I allow it in ReactOS !
/*
Status = ConSrvGetGraphicsBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetPaletteRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
*/
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetPaletteRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
/*
* Make the palette handle public, so that it can be
* used by other threads calling GDI functions on it.
* Indeed, the palette handle comes from a console app
* calling ourselves, running in CSRSS.
*/
NtUserConsoleControl(ConsoleMakePalettePublic,
&SetPaletteRequest->PaletteHandle,
sizeof(SetPaletteRequest->PaletteHandle));
Status = ConDrvSetConsolePalette(Buffer->Header.Console,
Buffer,
SetPaletteRequest->PaletteHandle,
SetPaletteRequest->Usage);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleCursorInfo(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
OUT PCONSOLE_CURSOR_INFO CursorInfo);
CSR_API(SrvGetConsoleCursorInfo)
{
NTSTATUS Status;
PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvGetConsoleCursorInfo\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
CursorInfoRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleCursorInfo(Buffer->Header.Console,
Buffer,
&CursorInfoRequest->Info);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleCursorInfo(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN PCONSOLE_CURSOR_INFO CursorInfo);
CSR_API(SrvSetConsoleCursorInfo)
{
NTSTATUS Status;
PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvSetConsoleCursorInfo\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
CursorInfoRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleCursorInfo(Buffer->Header.Console,
Buffer,
&CursorInfoRequest->Info);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleCursorPosition(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN PCOORD Position);
CSR_API(SrvSetConsoleCursorPosition)
{
NTSTATUS Status;
PCONSOLE_SETCURSORPOSITION SetCursorPositionRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorPositionRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvSetConsoleCursorPosition\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetCursorPositionRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleCursorPosition(Buffer->Header.Console,
Buffer,
&SetCursorPositionRequest->Position);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
CSR_API(SrvCreateConsoleScreenBuffer)
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PCONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CreateScreenBufferRequest;
PCSR_PROCESS Process = CsrGetClientThread()->Process;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
PCONSRV_CONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
PVOID ScreenBufferInfo = NULL;
TEXTMODE_BUFFER_INFO TextModeInfo = {{80, 25},
DEFAULT_SCREEN_ATTRIB,
DEFAULT_POPUP_ATTRIB ,
TRUE,
CSR_DEFAULT_CURSOR_SIZE};
GRAPHICS_BUFFER_INFO GraphicsInfo;
GraphicsInfo.Info = CreateScreenBufferRequest->GraphicsBufferInfo; // HACK for MSVC
DPRINT("SrvCreateConsoleScreenBuffer\n");
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_TEXTMODE_BUFFER)
{
ScreenBufferInfo = &TextModeInfo;
/*
if (Console->ActiveBuffer)
{
TextModeInfo.ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize;
if (TextModeInfo.ScreenBufferSize.X == 0) TextModeInfo.ScreenBufferSize.X = 80;
if (TextModeInfo.ScreenBufferSize.Y == 0) TextModeInfo.ScreenBufferSize.Y = 25;
TextModeInfo.ScreenAttrib = Console->ActiveBuffer->ScreenBuffer.TextBuffer.ScreenDefaultAttrib;
TextModeInfo.PopupAttrib = Console->ActiveBuffer->ScreenBuffer.TextBuffer.PopupDefaultAttrib;
TextModeInfo.IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible;
TextModeInfo.CursorSize = Console->ActiveBuffer->CursorInfo.dwSize;
}
*/
/*
* This is Windows' behaviour
*/
/* Use the current console size. Regularize it if needed. */
TextModeInfo.ScreenBufferSize = Console->ConsoleSize;
if (TextModeInfo.ScreenBufferSize.X == 0) TextModeInfo.ScreenBufferSize.X = 1;
if (TextModeInfo.ScreenBufferSize.Y == 0) TextModeInfo.ScreenBufferSize.Y = 1;
/* If we have an active screen buffer, use its attributes as the new ones */
if (Console->ActiveBuffer && GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER)
{
PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)Console->ActiveBuffer;
TextModeInfo.ScreenAttrib = Buffer->ScreenDefaultAttrib;
TextModeInfo.PopupAttrib = Buffer->PopupDefaultAttrib;
TextModeInfo.IsCursorVisible = Buffer->CursorInfo.bVisible;
TextModeInfo.CursorSize = Buffer->CursorInfo.dwSize;
}
}
else if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_GRAPHICS_BUFFER)
{
/* Get infos from the graphics buffer information structure */
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMapInfo,
CreateScreenBufferRequest->GraphicsBufferInfo.dwBitMapInfoLength,
sizeof(BYTE)))
{
Status = STATUS_INVALID_PARAMETER;
goto Quit;
}
ScreenBufferInfo = &GraphicsInfo;
/* Initialize shared variables */
// CreateScreenBufferRequest->GraphicsBufferInfo.hMutex
CreateScreenBufferRequest->hMutex = GraphicsInfo.Info.hMutex = INVALID_HANDLE_VALUE;
// CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap
CreateScreenBufferRequest->lpBitMap = GraphicsInfo.Info.lpBitMap = NULL;
/* A graphics screen buffer is never inheritable */
CreateScreenBufferRequest->InheritHandle = FALSE;
}
Status = ConDrvCreateScreenBuffer(&Buff,
(PCONSOLE)Console,
Process->ProcessHandle,
CreateScreenBufferRequest->ScreenBufferType,
ScreenBufferInfo);
if (!NT_SUCCESS(Status)) goto Quit;
/* Insert the new handle inside the process handles table */
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
Status = ConSrvInsertObject(ProcessData,
&CreateScreenBufferRequest->OutputHandle,
&Buff->Header,
CreateScreenBufferRequest->DesiredAccess,
CreateScreenBufferRequest->InheritHandle,
CreateScreenBufferRequest->ShareMode);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
if (!NT_SUCCESS(Status)) goto Quit;
if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_GRAPHICS_BUFFER)
{
PGRAPHICS_SCREEN_BUFFER Buffer = (PGRAPHICS_SCREEN_BUFFER)Buff;
/*
* Initialize the graphics buffer information structure
* and give it back to the client.
*/
// CreateScreenBufferRequest->GraphicsBufferInfo.hMutex
CreateScreenBufferRequest->hMutex = Buffer->ClientMutex;
// CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap
CreateScreenBufferRequest->lpBitMap = Buffer->ClientBitMap;
}
Quit:
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleActiveScreenBuffer(IN PCONSOLE Console,
IN PCONSOLE_SCREEN_BUFFER Buffer);
CSR_API(SrvSetConsoleActiveScreenBuffer)
{
NTSTATUS Status;
PCONSOLE_SETACTIVESCREENBUFFER SetScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferRequest;
PCONSOLE_SCREEN_BUFFER Buffer;
DPRINT("SrvSetConsoleActiveScreenBuffer\n");
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetScreenBufferRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleActiveScreenBuffer(Buffer->Header.Console,
Buffer);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
/* CSR THREADS FOR WriteConsole ***********************************************/
static NTSTATUS
DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
IN PCSR_THREAD ClientThread,
IN BOOLEAN CreateWaitBlock OPTIONAL);
// Wait function CSR_WAIT_FUNCTION
static BOOLEAN
NTAPI
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;
DPRINT("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);
}
NTSTATUS NTAPI
ConDrvWriteConsole(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
IN BOOLEAN Unicode,
IN PVOID StringBuffer,
IN ULONG NumCharsToWrite,
OUT PULONG NumCharsWritten OPTIONAL);
static NTSTATUS
DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
IN PCSR_THREAD ClientThread,
IN BOOLEAN CreateWaitBlock OPTIONAL)
{
NTSTATUS Status;
PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
PTEXTMODE_SCREEN_BUFFER ScreenBuffer;
PVOID Buffer;
ULONG NrCharactersWritten = 0;
ULONG CharSize = (WriteConsoleRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(ClientThread->Process),
WriteConsoleRequest->OutputHandle,
&ScreenBuffer, GENERIC_WRITE, FALSE);
if (!NT_SUCCESS(Status)) return Status;
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than eighty
* bytes are written. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
if (WriteConsoleRequest->UsingStaticBuffer &&
WriteConsoleRequest->NumBytes <= sizeof(WriteConsoleRequest->StaticBuffer))
{
/*
* Adjust the internal pointer, because its old value points to
* the static buffer in the original ApiMessage structure.
*/
// WriteConsoleRequest->Buffer = WriteConsoleRequest->StaticBuffer;
Buffer = WriteConsoleRequest->StaticBuffer;
}
else
{
Buffer = WriteConsoleRequest->Buffer;
}
DPRINT("Calling ConDrvWriteConsole\n");
Status = ConDrvWriteConsole(ScreenBuffer->Header.Console,
ScreenBuffer,
WriteConsoleRequest->Unicode,
Buffer,
WriteConsoleRequest->NumBytes / CharSize, // NrCharactersToWrite
&NrCharactersWritten);
DPRINT("ConDrvWriteConsole returned (%d ; Status = 0x%08x)\n",
NrCharactersWritten, Status);
if (Status == STATUS_PENDING)
{
if (CreateWaitBlock)
{
PCONSRV_CONSOLE Console = (PCONSRV_CONSOLE)ScreenBuffer->Header.Console;
if (!CsrCreateWait(&Console->WriteWaitQueue,
WriteConsoleThread,
ClientThread,
ApiMessage,
NULL))
{
/* Fail */
Status = STATUS_NO_MEMORY;
goto Quit;
}
}
/* Wait until we un-pause the console */
// Status = STATUS_PENDING;
}
else
{
/* We read all what we wanted. Set the number of bytes written. */
WriteConsoleRequest->NumBytes = NrCharactersWritten * CharSize;
}
Quit:
ConSrvReleaseScreenBuffer(ScreenBuffer, FALSE);
return Status;
}
/* TEXT OUTPUT APIS ***********************************************************/
NTSTATUS NTAPI
ConDrvReadConsoleOutput(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN BOOLEAN Unicode,
OUT PCHAR_INFO CharInfo/*Buffer*/,
IN OUT PSMALL_RECT ReadRegion);
CSR_API(SrvReadConsoleOutput)
{
NTSTATUS Status;
PCONSOLE_READOUTPUT ReadOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
ULONG NumCells;
PCHAR_INFO CharInfo;
DPRINT("SrvReadConsoleOutput\n");
NumCells = (ReadOutputRequest->ReadRegion.Right - ReadOutputRequest->ReadRegion.Left + 1) *
(ReadOutputRequest->ReadRegion.Bottom - ReadOutputRequest->ReadRegion.Top + 1);
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than one
* cell is read. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
if (NumCells <= 1)
{
/*
* Adjust the internal pointer, because its old value points to
* the static buffer in the original ApiMessage structure.
*/
// ReadOutputRequest->CharInfo = &ReadOutputRequest->StaticBuffer;
CharInfo = &ReadOutputRequest->StaticBuffer;
}
else
{
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ReadOutputRequest->CharInfo,
NumCells,
sizeof(CHAR_INFO)))
{
return STATUS_INVALID_PARAMETER;
}
CharInfo = ReadOutputRequest->CharInfo;
}
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ReadOutputRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvReadConsoleOutput(Buffer->Header.Console,
Buffer,
ReadOutputRequest->Unicode,
CharInfo,
&ReadOutputRequest->ReadRegion);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvWriteConsoleOutput(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN BOOLEAN Unicode,
IN PCHAR_INFO CharInfo/*Buffer*/,
IN OUT PSMALL_RECT WriteRegion);
CSR_API(SrvWriteConsoleOutput)
{
NTSTATUS Status;
PCONSOLE_WRITEOUTPUT WriteOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
PCSR_PROCESS Process = CsrGetClientThread()->Process;
ULONG NumCells;
PCHAR_INFO CharInfo;
DPRINT("SrvWriteConsoleOutput\n");
NumCells = (WriteOutputRequest->WriteRegion.Right - WriteOutputRequest->WriteRegion.Left + 1) *
(WriteOutputRequest->WriteRegion.Bottom - WriteOutputRequest->WriteRegion.Top + 1);
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(Process),
WriteOutputRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
/*
* Validate the message buffer if we do not use a process' heap buffer
* (CsrAllocateCaptureBuffer succeeded because we haven't allocated
* a too large (>= 64 kB, size of the CSR heap) data buffer).
*/
if (!WriteOutputRequest->UseVirtualMemory)
{
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than one
* cell is written. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
if (NumCells <= 1)
{
/*
* Adjust the internal pointer, because its old value points to
* the static buffer in the original ApiMessage structure.
*/
// WriteOutputRequest->CharInfo = &WriteOutputRequest->StaticBuffer;
CharInfo = &WriteOutputRequest->StaticBuffer;
}
else
{
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&WriteOutputRequest->CharInfo,
NumCells,
sizeof(CHAR_INFO)))
{
Status = STATUS_INVALID_PARAMETER;
goto Quit;
}
CharInfo = WriteOutputRequest->CharInfo;
}
}
else
{
/*
* This was not the case: we use a heap buffer. Retrieve its contents.
*/
ULONG Size = NumCells * sizeof(CHAR_INFO);
CharInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size);
if (CharInfo == NULL)
{
Status = STATUS_NO_MEMORY;
goto Quit;
}
Status = NtReadVirtualMemory(Process->ProcessHandle,
WriteOutputRequest->CharInfo,
CharInfo,
Size,
NULL);
if (!NT_SUCCESS(Status))
{
ConsoleFreeHeap(CharInfo);
// Status = STATUS_NO_MEMORY;
goto Quit;
}
}
Status = ConDrvWriteConsoleOutput(Buffer->Header.Console,
Buffer,
WriteOutputRequest->Unicode,
CharInfo,
&WriteOutputRequest->WriteRegion);
/* Free the temporary buffer if we used the process' heap buffer */
if (WriteOutputRequest->UseVirtualMemory && CharInfo)
ConsoleFreeHeap(CharInfo);
Quit:
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
CSR_API(SrvWriteConsole)
{
NTSTATUS Status;
PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
DPRINT("SrvWriteConsole\n");
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than eighty
* bytes are written. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
if (WriteConsoleRequest->UsingStaticBuffer &&
WriteConsoleRequest->NumBytes <= sizeof(WriteConsoleRequest->StaticBuffer))
{
/*
* Adjust the internal pointer, because its old value points to
* the static buffer in the original ApiMessage structure.
*/
// WriteConsoleRequest->Buffer = WriteConsoleRequest->StaticBuffer;
}
else
{
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&WriteConsoleRequest->Buffer,
WriteConsoleRequest->NumBytes,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
}
Status = DoWriteConsole(ApiMessage, CsrGetClientThread(), TRUE);
if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
return Status;
}
NTSTATUS NTAPI
ConDrvReadConsoleOutputString(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN CODE_TYPE CodeType,
OUT PVOID StringBuffer,
IN ULONG NumCodesToRead,
IN PCOORD ReadCoord,
// OUT PCOORD EndCoord,
OUT PULONG NumCodesRead OPTIONAL);
CSR_API(SrvReadConsoleOutputString)
{
NTSTATUS Status;
PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputCodeRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
ULONG CodeSize;
PVOID pCode;
DPRINT("SrvReadConsoleOutputString\n");
switch (ReadOutputCodeRequest->CodeType)
{
case CODE_ASCII:
CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
break;
case CODE_UNICODE:
CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
break;
case CODE_ATTRIBUTE:
CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
break;
default:
return STATUS_INVALID_PARAMETER;
}
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than eighty
* bytes are read. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
if (ReadOutputCodeRequest->NumCodes * CodeSize <= sizeof(ReadOutputCodeRequest->CodeStaticBuffer))
{
/*
* Adjust the internal pointer, because its old value points to
* the static buffer in the original ApiMessage structure.
*/
// ReadOutputCodeRequest->pCode = ReadOutputCodeRequest->CodeStaticBuffer;
pCode = ReadOutputCodeRequest->CodeStaticBuffer;
}
else
{
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ReadOutputCodeRequest->pCode,
ReadOutputCodeRequest->NumCodes,
CodeSize))
{
return STATUS_INVALID_PARAMETER;
}
pCode = ReadOutputCodeRequest->pCode;
}
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ReadOutputCodeRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status))
{
ReadOutputCodeRequest->NumCodes = 0;
return Status;
}
Status = ConDrvReadConsoleOutputString(Buffer->Header.Console,
Buffer,
ReadOutputCodeRequest->CodeType,
pCode,
ReadOutputCodeRequest->NumCodes,
&ReadOutputCodeRequest->Coord,
// &ReadOutputCodeRequest->EndCoord,
&ReadOutputCodeRequest->NumCodes);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN CODE_TYPE CodeType,
IN PVOID StringBuffer,
IN ULONG NumCodesToWrite,
IN PCOORD WriteCoord,
// OUT PCOORD EndCoord,
OUT PULONG NumCodesWritten OPTIONAL);
CSR_API(SrvWriteConsoleOutputString)
{
NTSTATUS Status;
PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputCodeRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
ULONG CodeSize;
PVOID pCode;
DPRINT("SrvWriteConsoleOutputString\n");
switch (WriteOutputCodeRequest->CodeType)
{
case CODE_ASCII:
CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
break;
case CODE_UNICODE:
CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
break;
case CODE_ATTRIBUTE:
CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
break;
default:
return STATUS_INVALID_PARAMETER;
}
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than eighty
* bytes are written. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
if (WriteOutputCodeRequest->NumCodes * CodeSize <= sizeof(WriteOutputCodeRequest->CodeStaticBuffer))
{
/*
* Adjust the internal pointer, because its old value points to
* the static buffer in the original ApiMessage structure.
*/
// WriteOutputCodeRequest->pCode = WriteOutputCodeRequest->CodeStaticBuffer;
pCode = WriteOutputCodeRequest->CodeStaticBuffer;
}
else
{
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&WriteOutputCodeRequest->pCode,
WriteOutputCodeRequest->NumCodes,
CodeSize))
{
return STATUS_INVALID_PARAMETER;
}
pCode = WriteOutputCodeRequest->pCode;
}
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
WriteOutputCodeRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status))
{
WriteOutputCodeRequest->NumCodes = 0;
return Status;
}
Status = ConDrvWriteConsoleOutputString(Buffer->Header.Console,
Buffer,
WriteOutputCodeRequest->CodeType,
pCode,
WriteOutputCodeRequest->NumCodes,
&WriteOutputCodeRequest->Coord,
// &WriteOutputCodeRequest->EndCoord,
&WriteOutputCodeRequest->NumCodes);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvFillConsoleOutput(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN CODE_TYPE CodeType,
IN CODE_ELEMENT Code,
IN ULONG NumCodesToWrite,
IN PCOORD WriteCoord,
OUT PULONG NumCodesWritten OPTIONAL);
CSR_API(SrvFillConsoleOutput)
{
NTSTATUS Status;
PCONSOLE_FILLOUTPUTCODE FillOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
CODE_TYPE CodeType = FillOutputRequest->CodeType;
DPRINT("SrvFillConsoleOutput\n");
if ( (CodeType != CODE_ASCII ) &&
(CodeType != CODE_UNICODE ) &&
(CodeType != CODE_ATTRIBUTE) )
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
FillOutputRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status))
{
FillOutputRequest->NumCodes = 0;
return Status;
}
Status = ConDrvFillConsoleOutput(Buffer->Header.Console,
Buffer,
CodeType,
FillOutputRequest->Code,
FillOutputRequest->NumCodes,
&FillOutputRequest->WriteCoord,
&FillOutputRequest->NumCodes);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
OUT PCOORD ScreenBufferSize,
OUT PCOORD CursorPosition,
OUT PCOORD ViewOrigin,
OUT PCOORD ViewSize,
OUT PCOORD MaximumViewSize,
OUT PWORD Attributes);
CSR_API(SrvGetConsoleScreenBufferInfo)
{
NTSTATUS Status;
PCONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScreenBufferInfoRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvGetConsoleScreenBufferInfo\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ScreenBufferInfoRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleScreenBufferInfo(Buffer->Header.Console,
Buffer,
&ScreenBufferInfoRequest->ScreenBufferSize,
&ScreenBufferInfoRequest->CursorPosition,
&ScreenBufferInfoRequest->ViewOrigin,
&ScreenBufferInfoRequest->ViewSize,
&ScreenBufferInfoRequest->MaximumViewSize,
&ScreenBufferInfoRequest->Attributes);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN WORD Attributes);
CSR_API(SrvSetConsoleTextAttribute)
{
NTSTATUS Status;
PCONSOLE_SETTEXTATTRIB SetTextAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetTextAttribRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvSetConsoleTextAttribute\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetTextAttribRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleTextAttribute(Buffer->Header.Console,
Buffer,
SetTextAttribRequest->Attributes);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN PCOORD Size);
CSR_API(SrvSetConsoleScreenBufferSize)
{
NTSTATUS Status;
PCONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferSizeRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvSetConsoleScreenBufferSize\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetScreenBufferSizeRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleScreenBufferSize(Buffer->Header.Console,
Buffer,
&SetScreenBufferSizeRequest->Size);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN BOOLEAN Unicode,
IN PSMALL_RECT ScrollRectangle,
IN BOOLEAN UseClipRectangle,
IN PSMALL_RECT ClipRectangle OPTIONAL,
IN PCOORD DestinationOrigin,
IN CHAR_INFO FillChar);
CSR_API(SrvScrollConsoleScreenBuffer)
{
NTSTATUS Status;
PCONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScrollScreenBufferRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvScrollConsoleScreenBuffer\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ScrollScreenBufferRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvScrollConsoleScreenBuffer(Buffer->Header.Console,
Buffer,
ScrollScreenBufferRequest->Unicode,
&ScrollScreenBufferRequest->ScrollRectangle,
ScrollScreenBufferRequest->UseClipRectangle,
&ScrollScreenBufferRequest->ClipRectangle,
&ScrollScreenBufferRequest->DestinationOrigin,
ScrollScreenBufferRequest->Fill);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleWindowInfo(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN BOOLEAN Absolute,
IN PSMALL_RECT WindowRect);
CSR_API(SrvSetConsoleWindowInfo)
{
NTSTATUS Status;
PCONSOLE_SETWINDOWINFO SetWindowInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetWindowInfoRequest;
// PCONSOLE_SCREEN_BUFFER Buffer;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT1("SrvSetConsoleWindowInfo(0x%08x, %d, {L%d, T%d, R%d, B%d}) called\n",
SetWindowInfoRequest->OutputHandle, SetWindowInfoRequest->Absolute,
SetWindowInfoRequest->WindowRect.Left ,
SetWindowInfoRequest->WindowRect.Top ,
SetWindowInfoRequest->WindowRect.Right,
SetWindowInfoRequest->WindowRect.Bottom);
// ConSrvGetScreenBuffer
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetWindowInfoRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleWindowInfo(Buffer->Header.Console,
Buffer,
SetWindowInfoRequest->Absolute,
&SetWindowInfoRequest->WindowRect);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
/* EOF */