[KERNEL32]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 4 Aug 2014 16:25:12 +0000 (16:25 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 4 Aug 2014 16:25:12 +0000 (16:25 +0000)
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
include/reactos/subsys/win/conmsg.h
win32ss/user/winsrv/consrv/condrv/conoutput.c
win32ss/user/winsrv/consrv/condrv/text.c
win32ss/user/winsrv/consrv/conoutput.c
win32ss/user/winsrv/consrv/include/conio.h
win32ss/user/winsrv/consrv/include/conio_winsrv.h
win32ss/user/winsrv/consrv/include/rect.h [new file with mode: 0644]

index b44b42c..6dec006 100644 (file)
 #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 **********************************************************/
 
 /******************
@@ -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;
     }
index 5a4f595..9a07d12 100644 (file)
@@ -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;
index 1437646..3ebcdc3 100644 (file)
@@ -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);
     }
 }
index e0b0e8a..a560a4e 100644 (file)
@@ -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;
index acf2ca1..833b3cd 100644 (file)
@@ -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);
index 46e3b41..b4e75fd 100644 (file)
@@ -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:
index d239db7..18cefe2 100644 (file)
@@ -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 (file)
index 0000000..8a78d90
--- /dev/null
@@ -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;
+}