/* PUBLIC SERVER APIS *********************************************************/
+/*
+ * FIXME: This function MUST be moved fro 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,
&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)
+ {
+ 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);
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PCONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CreateScreenBufferRequest;
- PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
- PCONSOLE Console;
+ PCSR_PROCESS Process = CsrGetClientThread()->Process;
+ PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
+ PCONSRV_CONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
PVOID ScreenBufferInfo = NULL;
}
Status = ConDrvCreateScreenBuffer(&Buff,
- Console,
+ (PCONSOLE)Console,
+ Process->ProcessHandle,
CreateScreenBufferRequest->ScreenBufferType,
ScreenBufferInfo);
if (!NT_SUCCESS(Status)) goto Quit;
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,
- WriteConsoleRequest->Buffer,
- WriteConsoleRequest->NrCharactersToWrite,
- &WriteConsoleRequest->NrCharactersWritten);
+ Buffer,
+ WriteConsoleRequest->NumBytes / CharSize, // NrCharactersToWrite
+ &NrCharactersWritten);
+ DPRINT("ConDrvWriteConsole returned (%d ; Status = 0x%08x)\n",
+ NrCharactersWritten, Status);
if (Status == STATUS_PENDING)
{
if (CreateWaitBlock)
{
- if (!CsrCreateWait(&ScreenBuffer->Header.Console->WriteWaitQueue,
+ PCONSRV_CONSOLE Console = (PCONSRV_CONSOLE)ScreenBuffer->Header.Console;
+
+ if (!CsrCreateWait(&Console->WriteWaitQueue,
WriteConsoleThread,
ClientThread,
ApiMessage,
/* 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);
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN BOOLEAN Unicode,
OUT PCHAR_INFO CharInfo/*Buffer*/,
- IN PCOORD BufferSize,
- IN PCOORD BufferCoord,
IN OUT PSMALL_RECT ReadRegion);
CSR_API(SrvReadConsoleOutput)
{
PCONSOLE_READOUTPUT ReadOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
+ ULONG NumCells;
+ PCHAR_INFO CharInfo;
+
DPRINT("SrvReadConsoleOutput\n");
- if (!CsrValidateMessageBuffer(ApiMessage,
- (PVOID*)&ReadOutputRequest->CharInfo,
- ReadOutputRequest->BufferSize.X * ReadOutputRequest->BufferSize.Y,
- sizeof(CHAR_INFO)))
+ 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)
{
- return STATUS_INVALID_PARAMETER;
+ /*
+ * 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),
Status = ConDrvReadConsoleOutput(Buffer->Header.Console,
Buffer,
ReadOutputRequest->Unicode,
- ReadOutputRequest->CharInfo,
- &ReadOutputRequest->BufferSize,
- &ReadOutputRequest->BufferCoord,
+ CharInfo,
&ReadOutputRequest->ReadRegion);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN BOOLEAN Unicode,
IN PCHAR_INFO CharInfo/*Buffer*/,
- IN PCOORD BufferSize,
- IN PCOORD BufferCoord,
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");
- if (!CsrValidateMessageBuffer(ApiMessage,
- (PVOID*)&WriteOutputRequest->CharInfo,
- WriteOutputRequest->BufferSize.X * WriteOutputRequest->BufferSize.Y,
- sizeof(CHAR_INFO)))
- {
- return STATUS_INVALID_PARAMETER;
- }
+ NumCells = (WriteOutputRequest->WriteRegion.Right - WriteOutputRequest->WriteRegion.Left + 1) *
+ (WriteOutputRequest->WriteRegion.Bottom - WriteOutputRequest->WriteRegion.Top + 1);
- Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+ 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,
- WriteOutputRequest->CharInfo,
- &WriteOutputRequest->BufferSize,
- &WriteOutputRequest->BufferCoord,
+ 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;
}
DPRINT("SrvWriteConsole\n");
- if (!CsrValidateMessageBuffer(ApiMessage,
- (PVOID)&WriteConsoleRequest->Buffer,
- WriteConsoleRequest->BufferSize,
- sizeof(BYTE)))
+ /*
+ * 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))
{
- return STATUS_INVALID_PARAMETER;
+ /*
+ * 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);
OUT PVOID StringBuffer,
IN ULONG NumCodesToRead,
IN PCOORD ReadCoord,
- OUT PCOORD EndCoord,
- OUT PULONG CodesRead);
+ // OUT PCOORD EndCoord,
+ OUT PULONG NumCodesRead OPTIONAL);
CSR_API(SrvReadConsoleOutputString)
{
NTSTATUS Status;
PTEXTMODE_SCREEN_BUFFER Buffer;
ULONG CodeSize;
+ PVOID pCode;
+
DPRINT("SrvReadConsoleOutputString\n");
switch (ReadOutputCodeRequest->CodeType)
{
case CODE_ASCII:
- CodeSize = sizeof(CHAR);
+ CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
break;
case CODE_UNICODE:
- CodeSize = sizeof(WCHAR);
+ CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
break;
case CODE_ATTRIBUTE:
- CodeSize = sizeof(WORD);
+ CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
break;
default:
return STATUS_INVALID_PARAMETER;
}
- if (!CsrValidateMessageBuffer(ApiMessage,
- (PVOID*)&ReadOutputCodeRequest->pCode.pCode,
- ReadOutputCodeRequest->NumCodesToRead,
- CodeSize))
+ /*
+ * 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))
{
- return STATUS_INVALID_PARAMETER;
+ /*
+ * 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)) return Status;
+ if (!NT_SUCCESS(Status))
+ {
+ ReadOutputCodeRequest->NumCodes = 0;
+ return Status;
+ }
Status = ConDrvReadConsoleOutputString(Buffer->Header.Console,
Buffer,
ReadOutputCodeRequest->CodeType,
- ReadOutputCodeRequest->pCode.pCode,
- ReadOutputCodeRequest->NumCodesToRead,
- &ReadOutputCodeRequest->ReadCoord,
- &ReadOutputCodeRequest->EndCoord,
- &ReadOutputCodeRequest->CodesRead);
+ pCode,
+ ReadOutputCodeRequest->NumCodes,
+ &ReadOutputCodeRequest->Coord,
+ // &ReadOutputCodeRequest->EndCoord,
+ &ReadOutputCodeRequest->NumCodes);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
IN CODE_TYPE CodeType,
IN PVOID StringBuffer,
IN ULONG NumCodesToWrite,
- IN PCOORD WriteCoord /*,
- OUT PCOORD EndCoord,
- OUT PULONG CodesWritten */);
+ IN PCOORD WriteCoord,
+ // OUT PCOORD EndCoord,
+ OUT PULONG NumCodesWritten OPTIONAL);
CSR_API(SrvWriteConsoleOutputString)
{
NTSTATUS Status;
PTEXTMODE_SCREEN_BUFFER Buffer;
ULONG CodeSize;
+ PVOID pCode;
+
DPRINT("SrvWriteConsoleOutputString\n");
switch (WriteOutputCodeRequest->CodeType)
{
case CODE_ASCII:
- CodeSize = sizeof(CHAR);
+ CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
break;
case CODE_UNICODE:
- CodeSize = sizeof(WCHAR);
+ CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
break;
case CODE_ATTRIBUTE:
- CodeSize = sizeof(WORD);
+ CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
break;
default:
return STATUS_INVALID_PARAMETER;
}
- if (!CsrValidateMessageBuffer(ApiMessage,
- (PVOID*)&WriteOutputCodeRequest->pCode.pCode,
- WriteOutputCodeRequest->Length,
- CodeSize))
+ /*
+ * 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))
{
- return STATUS_INVALID_PARAMETER;
+ /*
+ * 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)) return Status;
+ if (!NT_SUCCESS(Status))
+ {
+ WriteOutputCodeRequest->NumCodes = 0;
+ return Status;
+ }
Status = ConDrvWriteConsoleOutputString(Buffer->Header.Console,
Buffer,
WriteOutputCodeRequest->CodeType,
- WriteOutputCodeRequest->pCode.pCode,
- WriteOutputCodeRequest->Length, // NumCodesToWrite,
- &WriteOutputCodeRequest->Coord /*, // WriteCoord,
- &WriteOutputCodeRequest->EndCoord,
- &WriteOutputCodeRequest->NrCharactersWritten */);
-
- // WriteOutputCodeRequest->NrCharactersWritten = Written;
+ pCode,
+ WriteOutputCodeRequest->NumCodes,
+ &WriteOutputCodeRequest->Coord,
+ // &WriteOutputCodeRequest->EndCoord,
+ &WriteOutputCodeRequest->NumCodes);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
ConDrvFillConsoleOutput(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN CODE_TYPE CodeType,
- IN PVOID Code,
+ IN CODE_ELEMENT Code,
IN ULONG NumCodesToWrite,
- IN PCOORD WriteCoord /*,
- OUT PULONG CodesWritten */);
+ 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;
- USHORT CodeType = FillOutputRequest->CodeType;
+ CODE_TYPE CodeType = FillOutputRequest->CodeType;
DPRINT("SrvFillConsoleOutput\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
FillOutputRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
- if (!NT_SUCCESS(Status)) return Status;
+ if (!NT_SUCCESS(Status))
+ {
+ FillOutputRequest->NumCodes = 0;
+ return Status;
+ }
Status = ConDrvFillConsoleOutput(Buffer->Header.Console,
Buffer,
CodeType,
- &FillOutputRequest->Code,
- FillOutputRequest->Length, // NumCodesToWrite,
- &FillOutputRequest->Coord /*, // WriteCoord,
- &FillOutputRequest->NrCharactersWritten */);
-
- // FillOutputRequest->NrCharactersWritten = Written;
+ FillOutputRequest->Code,
+ FillOutputRequest->NumCodes,
+ &FillOutputRequest->WriteCoord,
+ &FillOutputRequest->NumCodes);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;