#include <debug.h>
+/* See consrv/include/rect.h */
+#define ConioRectHeight(Rect) \
+ (((Rect)->Top) > ((Rect)->Bottom) ? 0 : ((Rect)->Bottom) - ((Rect)->Top) + 1)
+#define ConioRectWidth(Rect) \
+ (((Rect)->Left) > ((Rect)->Right) ? 0 : ((Rect)->Right) - ((Rect)->Left) + 1)
+
+
/* PRIVATE FUNCTIONS **********************************************************/
/******************
*/
// 1- Get the exe name length in characters, including NULL character.
ReadConsoleRequest->ExeLength =
- GetConsoleInputExeNameW(0, (PWCHAR)ReadConsoleRequest->StaticBuffer);
+ (USHORT)GetConsoleInputExeNameW(0, (PWCHAR)ReadConsoleRequest->StaticBuffer);
// 2- Get the exe name (GetConsoleInputExeNameW returns 1 in case of success).
if (GetConsoleInputExeNameW(ReadConsoleRequest->ExeLength,
(PWCHAR)ReadConsoleRequest->StaticBuffer) != 1)
// HACK
if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
SetLastError(ERROR_INVALID_ACCESS);
- return FALSE;
+ _SEH2_YIELD(return FALSE);
}
_SEH2_END;
IN OUT PSMALL_RECT lpReadRegion,
IN BOOLEAN bUnicode)
{
+ BOOL Success;
CONSOLE_API_MESSAGE ApiMessage;
PCONSOLE_READOUTPUT ReadOutputRequest = &ApiMessage.Data.ReadOutputRequest;
- PCSR_CAPTURE_BUFFER CaptureBuffer;
- DWORD Size, SizeX, SizeY;
+ PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
+
+ SHORT SizeX, SizeY;
+ ULONG NumCells;
+
+ /* Set up the data to send to the Console Server */
+ ReadOutputRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+ ReadOutputRequest->OutputHandle = hConsoleOutput;
+ ReadOutputRequest->Unicode = bUnicode;
+
+ /* Update lpReadRegion */
+ _SEH2_TRY
+ {
+ SizeX = min(dwBufferSize.X - dwBufferCoord.X, ConioRectWidth(lpReadRegion));
+ SizeY = min(dwBufferSize.Y - dwBufferCoord.Y, ConioRectHeight(lpReadRegion));
+ if (SizeX <= 0 || SizeY <= 0)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ _SEH2_YIELD(return FALSE);
+ }
+ lpReadRegion->Right = lpReadRegion->Left + SizeX - 1;
+ lpReadRegion->Bottom = lpReadRegion->Top + SizeY - 1;
- if (lpBuffer == NULL)
+ ReadOutputRequest->ReadRegion = *lpReadRegion;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_ACCESS);
- return FALSE;
+ _SEH2_YIELD(return FALSE);
}
+ _SEH2_END;
- Size = dwBufferSize.X * dwBufferSize.Y * sizeof(CHAR_INFO);
-
- DPRINT("IntReadConsoleOutput: %lx %p\n", Size, lpReadRegion);
+ NumCells = SizeX * SizeY;
+ DPRINT1("IntReadConsoleOutput: (%d x %d)\n", SizeX, SizeY);
- /* Allocate a Capture Buffer */
- CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
- if (CaptureBuffer == NULL)
+ /*
+ * 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 allocated.
+ * This behaviour is also expected in the server-side.
+ */
+ if (NumCells <= 1)
{
- DPRINT1("CsrAllocateCaptureBuffer failed with size 0x%x!\n", Size);
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
+ ReadOutputRequest->CharInfo = &ReadOutputRequest->StaticBuffer;
+ // CaptureBuffer = NULL;
}
+ else
+ {
+ ULONG Size = NumCells * sizeof(CHAR_INFO);
- /* Allocate space in the Buffer */
- CsrAllocateMessagePointer(CaptureBuffer,
- Size,
- (PVOID*)&ReadOutputRequest->CharInfo);
+ /* Allocate a Capture Buffer */
+ CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
+ if (CaptureBuffer == NULL)
+ {
+ DPRINT1("CsrAllocateCaptureBuffer failed with size %ld!\n", Size);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
- /* Set up the data to send to the Console Server */
- ReadOutputRequest->OutputHandle = hConsoleOutput;
- ReadOutputRequest->Unicode = bUnicode;
- ReadOutputRequest->BufferSize = dwBufferSize;
- ReadOutputRequest->BufferCoord = dwBufferCoord;
- ReadOutputRequest->ReadRegion = *lpReadRegion;
+ /* Allocate space in the Buffer */
+ CsrAllocateMessagePointer(CaptureBuffer,
+ Size,
+ (PVOID*)&ReadOutputRequest->CharInfo);
+ }
/* Call the server */
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
sizeof(*ReadOutputRequest));
/* Check for success */
- if (NT_SUCCESS(ApiMessage.Status))
+ Success = NT_SUCCESS(ApiMessage.Status);
+
+ /* Retrieve the results */
+ _SEH2_TRY
{
- /* Copy into the buffer */
- DPRINT("Copying to buffer\n");
- SizeX = ReadOutputRequest->ReadRegion.Right -
- ReadOutputRequest->ReadRegion.Left + 1;
- SizeY = ReadOutputRequest->ReadRegion.Bottom -
- ReadOutputRequest->ReadRegion.Top + 1;
- RtlCopyMemory(lpBuffer,
- ReadOutputRequest->CharInfo,
- sizeof(CHAR_INFO) * SizeX * SizeY);
+ *lpReadRegion = ReadOutputRequest->ReadRegion;
+
+ if (Success)
+ {
+#if 0
+ SHORT x, X;
+#endif
+ SHORT y, Y;
+
+ /* Copy into the buffer */
+
+ SizeX = ReadOutputRequest->ReadRegion.Right -
+ ReadOutputRequest->ReadRegion.Left + 1;
+
+ for (y = 0, Y = ReadOutputRequest->ReadRegion.Top; Y <= ReadOutputRequest->ReadRegion.Bottom; ++y, ++Y)
+ {
+ RtlCopyMemory(lpBuffer + (y + dwBufferCoord.Y) * dwBufferSize.X + dwBufferCoord.X,
+ ReadOutputRequest->CharInfo + y * SizeX,
+ SizeX * sizeof(CHAR_INFO));
+#if 0
+ for (x = 0, X = ReadOutputRequest->ReadRegion.Left; X <= ReadOutputRequest->ReadRegion.Right; ++x, ++X)
+ {
+ *(lpBuffer + (y + dwBufferCoord.Y) * dwBufferSize.X + (x + dwBufferCoord.X)) =
+ *(ReadOutputRequest->CharInfo + y * SizeX + x);
+ }
+#endif
+ }
+ }
+ else
+ {
+ BaseSetLastNTError(ApiMessage.Status);
+ }
}
- else
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- BaseSetLastNTError(ApiMessage.Status);
+ SetLastError(ERROR_INVALID_ACCESS);
+ Success = FALSE;
}
+ _SEH2_END;
- /* Return the read region */
- DPRINT("read region: %p\n", ReadOutputRequest->ReadRegion);
- *lpReadRegion = ReadOutputRequest->ReadRegion;
-
- /* Release the capture buffer */
- CsrFreeCaptureBuffer(CaptureBuffer);
+ /* Release the capture buffer if needed */
+ if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
- /* Return TRUE or FALSE */
- return NT_SUCCESS(ApiMessage.Status);
+ /* Return success status */
+ return Success;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_ACCESS);
- return FALSE;
+ _SEH2_YIELD(return FALSE);
}
_SEH2_END;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_ACCESS);
- return FALSE;
+ _SEH2_YIELD(return FALSE);
}
_SEH2_END;
}
IN OUT PSMALL_RECT lpWriteRegion,
IN BOOLEAN bUnicode)
{
+ BOOL Success;
CONSOLE_API_MESSAGE ApiMessage;
PCONSOLE_WRITEOUTPUT WriteOutputRequest = &ApiMessage.Data.WriteOutputRequest;
- PCSR_CAPTURE_BUFFER CaptureBuffer;
- ULONG Size;
+ PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
+
+ SHORT SizeX, SizeY;
+ ULONG NumCells;
+
+ /* Set up the data to send to the Console Server */
+ WriteOutputRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+ WriteOutputRequest->OutputHandle = hConsoleOutput;
+ WriteOutputRequest->Unicode = bUnicode;
+
+ /* Update lpWriteRegion */
+ _SEH2_TRY
+ {
+ SizeX = min(dwBufferSize.X - dwBufferCoord.X, ConioRectWidth(lpWriteRegion));
+ SizeY = min(dwBufferSize.Y - dwBufferCoord.Y, ConioRectHeight(lpWriteRegion));
+ if (SizeX <= 0 || SizeY <= 0)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ _SEH2_YIELD(return FALSE);
+ }
+ lpWriteRegion->Right = lpWriteRegion->Left + SizeX - 1;
+ lpWriteRegion->Bottom = lpWriteRegion->Top + SizeY - 1;
- if ((lpBuffer == NULL) || (lpWriteRegion == NULL))
+ WriteOutputRequest->WriteRegion = *lpWriteRegion;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_ACCESS);
- return FALSE;
+ _SEH2_YIELD(return FALSE);
}
+ _SEH2_END;
+
+ NumCells = SizeX * SizeY;
+ DPRINT1("IntWriteConsoleOutput: (%d x %d)\n", SizeX, SizeY);
+
/*
- if (lpWriteRegion == NULL)
+ * 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 allocated.
+ * This behaviour is also expected in the server-side.
+ */
+ if (NumCells <= 1)
{
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
+ WriteOutputRequest->CharInfo = &WriteOutputRequest->StaticBuffer;
+ // CaptureBuffer = NULL;
}
- */
+ else
+ {
+ ULONG Size = NumCells * sizeof(CHAR_INFO);
- Size = dwBufferSize.Y * dwBufferSize.X * sizeof(CHAR_INFO);
+ /* Allocate a Capture Buffer */
+ CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
+ if (CaptureBuffer == NULL)
+ {
+ DPRINT1("CsrAllocateCaptureBuffer failed with size %ld!\n", Size);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
- DPRINT("IntWriteConsoleOutput: %lx %p\n", Size, lpWriteRegion);
+ /* Allocate space in the Buffer */
+ CsrAllocateMessagePointer(CaptureBuffer,
+ Size,
+ (PVOID*)&WriteOutputRequest->CharInfo);
+ }
- /* Allocate a Capture Buffer */
- CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
- if (CaptureBuffer == NULL)
+ /* Capture the user buffer contents */
+ _SEH2_TRY
{
- DPRINT1("CsrAllocateCaptureBuffer failed!\n");
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
+#if 0
+ SHORT x, X;
+#endif
+ SHORT y, Y;
- /* Capture the user buffer */
- CsrCaptureMessageBuffer(CaptureBuffer,
- (PVOID)lpBuffer,
- Size,
- (PVOID*)&WriteOutputRequest->CharInfo);
+ /* Copy into the buffer */
- /* Set up the data to send to the Console Server */
- WriteOutputRequest->OutputHandle = hConsoleOutput;
- WriteOutputRequest->Unicode = bUnicode;
- WriteOutputRequest->BufferSize = dwBufferSize;
- WriteOutputRequest->BufferCoord = dwBufferCoord;
- WriteOutputRequest->WriteRegion = *lpWriteRegion;
+ SizeX = WriteOutputRequest->WriteRegion.Right -
+ WriteOutputRequest->WriteRegion.Left + 1;
+
+ for (y = 0, Y = WriteOutputRequest->WriteRegion.Top; Y <= WriteOutputRequest->WriteRegion.Bottom; ++y, ++Y)
+ {
+ RtlCopyMemory(WriteOutputRequest->CharInfo + y * SizeX,
+ lpBuffer + (y + dwBufferCoord.Y) * dwBufferSize.X + dwBufferCoord.X,
+ SizeX * sizeof(CHAR_INFO));
+#if 0
+ for (x = 0, X = WriteOutputRequest->WriteRegion.Left; X <= WriteOutputRequest->WriteRegion.Right; ++x, ++X)
+ {
+ *(WriteOutputRequest->CharInfo + y * SizeX + x) =
+ *(lpBuffer + (y + dwBufferCoord.Y) * dwBufferSize.X + (x + dwBufferCoord.X));
+ }
+#endif
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastError(ERROR_INVALID_ACCESS);
+ _SEH2_YIELD(return FALSE);
+ }
+ _SEH2_END;
/* Call the server */
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
sizeof(*WriteOutputRequest));
/* Check for success */
- if (!NT_SUCCESS(ApiMessage.Status))
- {
- BaseSetLastNTError(ApiMessage.Status);
- }
+ Success = NT_SUCCESS(ApiMessage.Status);
- /* Return the read region */
- DPRINT("read region: %p\n", WriteOutputRequest->WriteRegion);
- *lpWriteRegion = WriteOutputRequest->WriteRegion;
+ /* Release the capture buffer if needed */
+ if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
- /* Release the capture buffer */
- CsrFreeCaptureBuffer(CaptureBuffer);
+ /* Retrieve the results */
+ _SEH2_TRY
+ {
+ *lpWriteRegion = WriteOutputRequest->WriteRegion;
+
+ if (!Success)
+ BaseSetLastNTError(ApiMessage.Status);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastError(ERROR_INVALID_ACCESS);
+ Success = FALSE;
+ }
+ _SEH2_END;
- /* Return TRUE or FALSE */
- return NT_SUCCESS(ApiMessage.Status);
+ /* Return success status */
+ return Success;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_ACCESS);
- return FALSE;
+ _SEH2_YIELD(return FALSE);
}
_SEH2_END;
}