[KERNEL32][CONSRV]
[reactos.git] / win32ss / user / winsrv / consrv / conoutput.c
index f5dac64..acf2ca1 100644 (file)
@@ -373,17 +373,45 @@ DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
     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)
     {
@@ -404,6 +432,11 @@ DoWriteConsole(IN PCSR_API_MESSAGE 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);
@@ -502,12 +535,30 @@ CSR_API(SrvWriteConsole)
 
     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);
@@ -524,8 +575,8 @@ ConDrvReadConsoleOutputString(IN PCONSOLE Console,
                               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;
@@ -533,47 +584,73 @@ CSR_API(SrvReadConsoleOutputString)
     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;
@@ -585,9 +662,9 @@ ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
                                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;
@@ -595,49 +672,73 @@ CSR_API(SrvWriteConsoleOutputString)
     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;
@@ -647,16 +748,16 @@ NTSTATUS NTAPI
 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");
 
@@ -670,17 +771,19 @@ CSR_API(SrvFillConsoleOutput)
     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;