From 9fd5cfb5f86a51003f164bac81dbc72e1412b616 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Mon, 4 Aug 2014 16:25:12 +0000 Subject: [PATCH] [KERNEL32] Add a bunch of missing _SEH_YIELD in 'return' clues in _SEH_TRY clauses. [KERNEL32][CONSRV] Make kernel32 / winsrv console CSR structures Win2k3-compliant for Read/WriteConsoleOutput functions. The last missing ones are Alloc/Attach/FreeConsole APIs!! Part 9/10 CORE-7931 svn path=/branches/condrv_restructure/; revision=63803 --- dll/win32/kernel32/client/console/readwrite.c | 303 +++++++++++++----- include/reactos/subsys/win/conmsg.h | 34 +- win32ss/user/winsrv/consrv/condrv/conoutput.c | 3 +- win32ss/user/winsrv/consrv/condrv/text.c | 135 ++------ win32ss/user/winsrv/consrv/conoutput.c | 84 +++-- win32ss/user/winsrv/consrv/include/conio.h | 15 +- .../user/winsrv/consrv/include/conio_winsrv.h | 15 +- win32ss/user/winsrv/consrv/include/rect.h | 85 +++++ 8 files changed, 418 insertions(+), 256 deletions(-) create mode 100644 win32ss/user/winsrv/consrv/include/rect.h diff --git a/dll/win32/kernel32/client/console/readwrite.c b/dll/win32/kernel32/client/console/readwrite.c index b44b42c51a6..6dec006a0f4 100644 --- a/dll/win32/kernel32/client/console/readwrite.c +++ b/dll/win32/kernel32/client/console/readwrite.c @@ -18,6 +18,13 @@ #include +/* 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 **********************************************************/ /****************** @@ -57,7 +64,7 @@ IntReadConsole(IN HANDLE hConsoleInput, */ // 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) @@ -170,7 +177,7 @@ IntReadConsole(IN HANDLE hConsoleInput, // HACK if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer); SetLastError(ERROR_INVALID_ACCESS); - return FALSE; + _SEH2_YIELD(return FALSE); } _SEH2_END; @@ -356,41 +363,73 @@ IntReadConsoleOutput(IN HANDLE hConsoleOutput, 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, @@ -399,32 +438,56 @@ IntReadConsoleOutput(IN HANDLE hConsoleOutput, 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; } @@ -602,7 +665,7 @@ IntWriteConsole(IN HANDLE hConsoleOutput, _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { SetLastError(ERROR_INVALID_ACCESS); - return FALSE; + _SEH2_YIELD(return FALSE); } _SEH2_END; } @@ -704,7 +767,7 @@ IntWriteConsoleInput(IN HANDLE hConsoleInput, _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { SetLastError(ERROR_INVALID_ACCESS); - return FALSE; + _SEH2_YIELD(return FALSE); } _SEH2_END; } @@ -770,49 +833,107 @@ IntWriteConsoleOutput(IN HANDLE hConsoleOutput, 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, @@ -821,20 +942,28 @@ IntWriteConsoleOutput(IN HANDLE hConsoleOutput, 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; } @@ -907,7 +1036,7 @@ IntWriteConsoleOutputCode(IN HANDLE hConsoleOutput, _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { SetLastError(ERROR_INVALID_ACCESS); - return FALSE; + _SEH2_YIELD(return FALSE); } _SEH2_END; } diff --git a/include/reactos/subsys/win/conmsg.h b/include/reactos/subsys/win/conmsg.h index 5a4f59546b2..9a07d12e31f 100644 --- a/include/reactos/subsys/win/conmsg.h +++ b/include/reactos/subsys/win/conmsg.h @@ -427,17 +427,6 @@ typedef struct BOOLEAN Unicode; } CONSOLE_GETSETCONSOLETITLE, *PCONSOLE_GETSETCONSOLETITLE; -typedef struct -{ - HANDLE OutputHandle; - - BOOL Unicode; - COORD BufferSize; - COORD BufferCoord; // WriteCoord - SMALL_RECT WriteRegion; - PCHAR_INFO CharInfo; -} CONSOLE_WRITEOUTPUT, *PCONSOLE_WRITEOUTPUT; - typedef struct { HANDLE ConsoleHandle; @@ -533,15 +522,30 @@ typedef struct typedef struct { + HANDLE ConsoleHandle; HANDLE OutputHandle; - BOOL Unicode; - COORD BufferSize; - COORD BufferCoord; - SMALL_RECT ReadRegion; + CHAR_INFO StaticBuffer; PCHAR_INFO CharInfo; + + SMALL_RECT ReadRegion; + BOOLEAN Unicode; } CONSOLE_READOUTPUT, *PCONSOLE_READOUTPUT; +typedef struct +{ + HANDLE ConsoleHandle; + HANDLE OutputHandle; + + CHAR_INFO StaticBuffer; + PCHAR_INFO CharInfo; + + SMALL_RECT WriteRegion; + BOOLEAN Unicode; + + ULONG Unknown; +} CONSOLE_WRITEOUTPUT, *PCONSOLE_WRITEOUTPUT; + typedef struct { HANDLE ConsoleHandle; diff --git a/win32ss/user/winsrv/consrv/condrv/conoutput.c b/win32ss/user/winsrv/consrv/condrv/conoutput.c index 1437646b4cc..3ebcdc31b10 100644 --- a/win32ss/user/winsrv/consrv/condrv/conoutput.c +++ b/win32ss/user/winsrv/consrv/condrv/conoutput.c @@ -159,7 +159,8 @@ ConioDrawConsole(PCONSOLE Console) if (ActiveBuffer) { - ConioInitRect(&Region, 0, 0, ActiveBuffer->ViewSize.Y - 1, ActiveBuffer->ViewSize.X - 1); + ConioInitRect(&Region, 0, 0, + ActiveBuffer->ViewSize.Y - 1, ActiveBuffer->ViewSize.X - 1); TermDrawRegion(Console, &Region); } } diff --git a/win32ss/user/winsrv/consrv/condrv/text.c b/win32ss/user/winsrv/consrv/condrv/text.c index e0b0e8a1d35..a560a4e161d 100644 --- a/win32ss/user/winsrv/consrv/condrv/text.c +++ b/win32ss/user/winsrv/consrv/condrv/text.c @@ -140,65 +140,6 @@ ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff) } } -static __inline BOOLEAN -ConioGetIntersection(OUT PSMALL_RECT Intersection, - IN PSMALL_RECT Rect1, - IN PSMALL_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; -} - -static __inline BOOLEAN -ConioGetUnion(OUT PSMALL_RECT Union, - IN PSMALL_RECT Rect1, - IN PSMALL_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; -} - static VOID ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff, IN OUT PSMALL_RECT UpdateRect, @@ -669,21 +610,15 @@ ConDrvReadConsoleOutput(IN PCONSOLE Console, IN PTEXTMODE_SCREEN_BUFFER Buffer, IN BOOLEAN Unicode, OUT PCHAR_INFO CharInfo/*Buffer*/, - IN PCOORD BufferSize, - IN PCOORD BufferCoord, IN OUT PSMALL_RECT ReadRegion) { + SHORT X, Y; + SMALL_RECT ScreenBuffer; PCHAR_INFO CurCharInfo; - SHORT SizeX, SizeY; SMALL_RECT CapturedReadRegion; - SMALL_RECT ScreenRect; - DWORD i; PCHAR_INFO Ptr; - LONG X, Y; - UINT CodePage; - if (Console == NULL || Buffer == NULL || CharInfo == NULL || - BufferSize == NULL || BufferCoord == NULL || ReadRegion == NULL) + if (Console == NULL || Buffer == NULL || CharInfo == NULL || ReadRegion == NULL) { return STATUS_INVALID_PARAMETER; } @@ -693,26 +628,24 @@ ConDrvReadConsoleOutput(IN PCONSOLE Console, CapturedReadRegion = *ReadRegion; - /* FIXME: Is this correct? */ - CodePage = Console->OutputCodePage; - - SizeX = min(BufferSize->X - BufferCoord->X, ConioRectWidth(&CapturedReadRegion)); - SizeY = min(BufferSize->Y - BufferCoord->Y, ConioRectHeight(&CapturedReadRegion)); - CapturedReadRegion.Right = CapturedReadRegion.Left + SizeX; - CapturedReadRegion.Bottom = CapturedReadRegion.Top + SizeY; - - ConioInitRect(&ScreenRect, 0, 0, Buffer->ScreenBufferSize.Y, Buffer->ScreenBufferSize.X); - if (!ConioGetIntersection(&CapturedReadRegion, &ScreenRect, &CapturedReadRegion)) + /* Make sure ReadRegion is inside the screen buffer */ + ConioInitRect(&ScreenBuffer, 0, 0, + Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1); + if (!ConioGetIntersection(&CapturedReadRegion, &ScreenBuffer, &CapturedReadRegion)) { + /* + * It is okay to have a ReadRegion completely outside + * the screen buffer. No data is read then. + */ return STATUS_SUCCESS; } - for (i = 0, Y = CapturedReadRegion.Top; Y < CapturedReadRegion.Bottom; ++i, ++Y) - { - CurCharInfo = CharInfo + (i * BufferSize->X); + CurCharInfo = CharInfo; + for (Y = CapturedReadRegion.Top; Y <= CapturedReadRegion.Bottom; ++Y) + { Ptr = ConioCoordToPointer(Buffer, CapturedReadRegion.Left, Y); - for (X = CapturedReadRegion.Left; X < CapturedReadRegion.Right; ++X) + for (X = CapturedReadRegion.Left; X <= CapturedReadRegion.Right; ++X) { if (Unicode) { @@ -721,7 +654,7 @@ ConDrvReadConsoleOutput(IN PCONSOLE Console, else { // ConsoleUnicodeCharToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar); - WideCharToMultiByte(CodePage, 0, &Ptr->Char.UnicodeChar, 1, + WideCharToMultiByte(Console->OutputCodePage, 0, &Ptr->Char.UnicodeChar, 1, &CurCharInfo->Char.AsciiChar, 1, NULL, NULL); } CurCharInfo->Attributes = Ptr->Attributes; @@ -730,10 +663,7 @@ ConDrvReadConsoleOutput(IN PCONSOLE Console, } } - ReadRegion->Left = CapturedReadRegion.Left; - ReadRegion->Top = CapturedReadRegion.Top ; - ReadRegion->Right = CapturedReadRegion.Left + SizeX - 1; - ReadRegion->Bottom = CapturedReadRegion.Top + SizeY - 1; + *ReadRegion = CapturedReadRegion; return STATUS_SUCCESS; } @@ -743,18 +673,15 @@ ConDrvWriteConsoleOutput(IN PCONSOLE Console, IN PTEXTMODE_SCREEN_BUFFER Buffer, IN BOOLEAN Unicode, IN PCHAR_INFO CharInfo/*Buffer*/, - IN PCOORD BufferSize, - IN PCOORD BufferCoord, IN OUT PSMALL_RECT WriteRegion) { - SHORT i, X, Y, SizeX, SizeY; + SHORT X, Y; SMALL_RECT ScreenBuffer; PCHAR_INFO CurCharInfo; SMALL_RECT CapturedWriteRegion; PCHAR_INFO Ptr; - if (Console == NULL || Buffer == NULL || CharInfo == NULL || - BufferSize == NULL || BufferCoord == NULL || WriteRegion == NULL) + if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL) { return STATUS_INVALID_PARAMETER; } @@ -764,13 +691,9 @@ ConDrvWriteConsoleOutput(IN PCONSOLE Console, CapturedWriteRegion = *WriteRegion; - SizeX = min(BufferSize->X - BufferCoord->X, ConioRectWidth(&CapturedWriteRegion)); - SizeY = min(BufferSize->Y - BufferCoord->Y, ConioRectHeight(&CapturedWriteRegion)); - CapturedWriteRegion.Right = CapturedWriteRegion.Left + SizeX - 1; - CapturedWriteRegion.Bottom = CapturedWriteRegion.Top + SizeY - 1; - /* Make sure WriteRegion is inside the screen buffer */ - ConioInitRect(&ScreenBuffer, 0, 0, Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1); + ConioInitRect(&ScreenBuffer, 0, 0, + Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1); if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion)) { /* @@ -780,12 +703,12 @@ ConDrvWriteConsoleOutput(IN PCONSOLE Console, return STATUS_SUCCESS; } - for (i = 0, Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; i++, Y++) - { - CurCharInfo = CharInfo + (i + BufferCoord->Y) * BufferSize->X + BufferCoord->X; + CurCharInfo = CharInfo; + for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y) + { Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y); - for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; X++) + for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X) { if (Unicode) { @@ -803,10 +726,7 @@ ConDrvWriteConsoleOutput(IN PCONSOLE Console, TermDrawRegion(Console, &CapturedWriteRegion); - WriteRegion->Left = CapturedWriteRegion.Left; - WriteRegion->Top = CapturedWriteRegion.Top ; - WriteRegion->Right = CapturedWriteRegion.Left + SizeX - 1; - WriteRegion->Bottom = CapturedWriteRegion.Top + SizeY - 1; + *WriteRegion = CapturedWriteRegion; return STATUS_SUCCESS; } @@ -1293,7 +1213,8 @@ ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console, CapturedDestinationOrigin = *DestinationOrigin; /* Make sure the source rectangle is inside the screen buffer */ - ConioInitRect(&ScreenBuffer, 0, 0, Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1); + ConioInitRect(&ScreenBuffer, 0, 0, + Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1); if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, ScrollRectangle)) { return STATUS_SUCCESS; diff --git a/win32ss/user/winsrv/consrv/conoutput.c b/win32ss/user/winsrv/consrv/conoutput.c index acf2ca13f03..833b3cdbb79 100644 --- a/win32ss/user/winsrv/consrv/conoutput.c +++ b/win32ss/user/winsrv/consrv/conoutput.c @@ -451,8 +451,6 @@ ConDrvReadConsoleOutput(IN PCONSOLE Console, 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) { @@ -460,14 +458,40 @@ 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))) + /* + * 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. + */ + NumCells = (ReadOutputRequest->ReadRegion.Right - ReadOutputRequest->ReadRegion.Left + 1) * + (ReadOutputRequest->ReadRegion.Bottom - ReadOutputRequest->ReadRegion.Top + 1); + + 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), @@ -478,9 +502,7 @@ CSR_API(SrvReadConsoleOutput) Status = ConDrvReadConsoleOutput(Buffer->Header.Console, Buffer, ReadOutputRequest->Unicode, - ReadOutputRequest->CharInfo, - &ReadOutputRequest->BufferSize, - &ReadOutputRequest->BufferCoord, + CharInfo, &ReadOutputRequest->ReadRegion); ConSrvReleaseScreenBuffer(Buffer, TRUE); @@ -492,8 +514,6 @@ ConDrvWriteConsoleOutput(IN PCONSOLE Console, 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) { @@ -501,14 +521,40 @@ CSR_API(SrvWriteConsoleOutput) PCONSOLE_WRITEOUTPUT WriteOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputRequest; PTEXTMODE_SCREEN_BUFFER Buffer; + ULONG NumCells; + PCHAR_INFO CharInfo; + DPRINT("SrvWriteConsoleOutput\n"); - if (!CsrValidateMessageBuffer(ApiMessage, - (PVOID*)&WriteOutputRequest->CharInfo, - WriteOutputRequest->BufferSize.X * WriteOutputRequest->BufferSize.Y, - sizeof(CHAR_INFO))) + /* + * 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. + */ + NumCells = (WriteOutputRequest->WriteRegion.Right - WriteOutputRequest->WriteRegion.Left + 1) * + (WriteOutputRequest->WriteRegion.Bottom - WriteOutputRequest->WriteRegion.Top + 1); + + 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. + */ + // WriteOutputRequest->CharInfo = &WriteOutputRequest->StaticBuffer; + CharInfo = &WriteOutputRequest->StaticBuffer; + } + else + { + if (!CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&WriteOutputRequest->CharInfo, + NumCells, + sizeof(CHAR_INFO))) + { + return STATUS_INVALID_PARAMETER; + } + + CharInfo = WriteOutputRequest->CharInfo; } Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), @@ -519,9 +565,7 @@ CSR_API(SrvWriteConsoleOutput) Status = ConDrvWriteConsoleOutput(Buffer->Header.Console, Buffer, WriteOutputRequest->Unicode, - WriteOutputRequest->CharInfo, - &WriteOutputRequest->BufferSize, - &WriteOutputRequest->BufferCoord, + CharInfo, &WriteOutputRequest->WriteRegion); ConSrvReleaseScreenBuffer(Buffer, TRUE); diff --git a/win32ss/user/winsrv/consrv/include/conio.h b/win32ss/user/winsrv/consrv/include/conio.h index 46e3b41d71a..b4e75fda666 100644 --- a/win32ss/user/winsrv/consrv/include/conio.h +++ b/win32ss/user/winsrv/consrv/include/conio.h @@ -10,6 +10,8 @@ #pragma once +#include "rect.h" + #define CSR_DEFAULT_CURSOR_SIZE 25 /* Default attributes */ @@ -342,19 +344,6 @@ ConioProcessInputEvent(PCONSOLE Console, PINPUT_RECORD InputEvent); /* conoutput.c */ -#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 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) /* * From MSDN: diff --git a/win32ss/user/winsrv/consrv/include/conio_winsrv.h b/win32ss/user/winsrv/consrv/include/conio_winsrv.h index d239db7188d..18cefe21ccb 100644 --- a/win32ss/user/winsrv/consrv/include/conio_winsrv.h +++ b/win32ss/user/winsrv/consrv/include/conio_winsrv.h @@ -10,6 +10,8 @@ #pragma once +#include "rect.h" + #define CSR_DEFAULT_CURSOR_SIZE 25 typedef struct _FRONTEND FRONTEND, *PFRONTEND; @@ -151,19 +153,6 @@ ConioProcessInputEvent(PCONSOLE Console, PINPUT_RECORD InputEvent); /* conoutput.c */ -#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 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) /* * From MSDN: diff --git a/win32ss/user/winsrv/consrv/include/rect.h b/win32ss/user/winsrv/consrv/include/rect.h new file mode 100644 index 00000000000..8a78d90265c --- /dev/null +++ b/win32ss/user/winsrv/consrv/include/rect.h @@ -0,0 +1,85 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Console Server DLL + * FILE: consrv/include/rect.h + * PURPOSE: Rectangle helper functions + * PROGRAMMERS: Gé van Geldorp + * Jeffrey Morlan + */ + +#pragma once + +#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 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) + + +static __inline BOOLEAN +ConioGetIntersection(OUT PSMALL_RECT Intersection, + IN PSMALL_RECT Rect1, + IN PSMALL_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; +} + +static __inline BOOLEAN +ConioGetUnion(OUT PSMALL_RECT Union, + IN PSMALL_RECT Rect1, + IN PSMALL_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; +} -- 2.17.1