xref: /reactos/win32ss/user/winsrv/consrv/conoutput.c (revision 4561998a)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Console Server DLL
4  * FILE:            win32ss/user/winsrv/consrv/conoutput.c
5  * PURPOSE:         General Console Output Functions
6  * PROGRAMMERS:     Jeffrey Morlan
7  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #include "consrv.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* PUBLIC SERVER APIS *********************************************************/
18 
19 /*
20  * FIXME: This function MUST be moved fro condrv/conoutput.c because only
21  * consrv knows how to manipulate VDM screenbuffers.
22  */
23 NTSTATUS NTAPI
24 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console,
25                             IN PTEXTMODE_SCREEN_BUFFER Buffer,
26                             IN PCHAR_CELL CharInfo/*Buffer*/,
27                             IN COORD CharInfoSize,
28                             IN PSMALL_RECT WriteRegion);
29 NTSTATUS NTAPI
30 ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
31                            IN PCONSOLE_SCREEN_BUFFER Buffer,
32                            IN PSMALL_RECT Region);
33 CSR_API(SrvInvalidateBitMapRect)
34 {
35     NTSTATUS Status;
36     PCONSOLE_INVALIDATEDIBITS InvalidateDIBitsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.InvalidateDIBitsRequest;
37     PCONSOLE_SCREEN_BUFFER Buffer;
38 
39     DPRINT("SrvInvalidateBitMapRect\n");
40 
41     Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
42                                    InvalidateDIBitsRequest->OutputHandle,
43                                    &Buffer, GENERIC_READ, TRUE);
44     if (!NT_SUCCESS(Status)) return Status;
45 
46     /* In text-mode only, draw the VDM buffer if present */
47     if (GetType(Buffer) == TEXTMODE_BUFFER && Buffer->Header.Console->VDMBuffer)
48     {
49         PTEXTMODE_SCREEN_BUFFER TextBuffer = (PTEXTMODE_SCREEN_BUFFER)Buffer;
50 
51         /*Status =*/ ConDrvWriteConsoleOutputVDM(Buffer->Header.Console,
52                                                  TextBuffer,
53                                                  Buffer->Header.Console->VDMBuffer,
54                                                  Buffer->Header.Console->VDMBufferSize,
55                                                  &InvalidateDIBitsRequest->Region);
56     }
57 
58     Status = ConDrvInvalidateBitMapRect(Buffer->Header.Console,
59                                         Buffer,
60                                         &InvalidateDIBitsRequest->Region);
61 
62     ConSrvReleaseScreenBuffer(Buffer, TRUE);
63     return Status;
64 }
65 
66 NTSTATUS NTAPI
67 ConDrvSetConsolePalette(IN PCONSOLE Console,
68                         // IN PGRAPHICS_SCREEN_BUFFER Buffer,
69                         IN PCONSOLE_SCREEN_BUFFER Buffer,
70                         IN HPALETTE PaletteHandle,
71                         IN UINT PaletteUsage);
72 CSR_API(SrvSetConsolePalette)
73 {
74     NTSTATUS Status;
75     PCONSOLE_SETPALETTE SetPaletteRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetPaletteRequest;
76     // PGRAPHICS_SCREEN_BUFFER Buffer;
77     PCONSOLE_SCREEN_BUFFER Buffer;
78 
79     DPRINT("SrvSetConsolePalette\n");
80 
81     // NOTE: Tests show that this function is used only for graphics screen buffers
82     // and otherwise it returns FALSE + sets last error to invalid handle.
83     // I think it's ridiculous, because if you are in text mode, simulating
84     // a change of VGA palette via DAC registers (done by a call to SetConsolePalette)
85     // cannot be done... So I allow it in ReactOS !
86     /*
87     Status = ConSrvGetGraphicsBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
88                                      SetPaletteRequest->OutputHandle,
89                                      &Buffer, GENERIC_WRITE, TRUE);
90     */
91     Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
92                                    SetPaletteRequest->OutputHandle,
93                                    &Buffer, GENERIC_WRITE, TRUE);
94     if (!NT_SUCCESS(Status)) return Status;
95 
96     /*
97      * Make the palette handle public, so that it can be
98      * used by other threads calling GDI functions on it.
99      * Indeed, the palette handle comes from a console app
100      * calling ourselves, running in CSRSS.
101      */
102     NtUserConsoleControl(ConsoleMakePalettePublic,
103                          &SetPaletteRequest->PaletteHandle,
104                          sizeof(SetPaletteRequest->PaletteHandle));
105 
106     Status = ConDrvSetConsolePalette(Buffer->Header.Console,
107                                      Buffer,
108                                      SetPaletteRequest->PaletteHandle,
109                                      SetPaletteRequest->Usage);
110 
111     ConSrvReleaseScreenBuffer(Buffer, TRUE);
112     return Status;
113 }
114 
115 NTSTATUS NTAPI
116 ConDrvGetConsoleCursorInfo(IN PCONSOLE Console,
117                            IN PTEXTMODE_SCREEN_BUFFER Buffer,
118                            OUT PCONSOLE_CURSOR_INFO CursorInfo);
119 CSR_API(SrvGetConsoleCursorInfo)
120 {
121     NTSTATUS Status;
122     PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
123     PTEXTMODE_SCREEN_BUFFER Buffer;
124 
125     DPRINT("SrvGetConsoleCursorInfo\n");
126 
127     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
128                                      CursorInfoRequest->OutputHandle,
129                                      &Buffer, GENERIC_READ, TRUE);
130     if (!NT_SUCCESS(Status)) return Status;
131 
132     Status = ConDrvGetConsoleCursorInfo(Buffer->Header.Console,
133                                         Buffer,
134                                         &CursorInfoRequest->Info);
135 
136     ConSrvReleaseScreenBuffer(Buffer, TRUE);
137     return Status;
138 }
139 
140 NTSTATUS NTAPI
141 ConDrvSetConsoleCursorInfo(IN PCONSOLE Console,
142                            IN PTEXTMODE_SCREEN_BUFFER Buffer,
143                            IN PCONSOLE_CURSOR_INFO CursorInfo);
144 CSR_API(SrvSetConsoleCursorInfo)
145 {
146     NTSTATUS Status;
147     PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
148     PTEXTMODE_SCREEN_BUFFER Buffer;
149 
150     DPRINT("SrvSetConsoleCursorInfo\n");
151 
152     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
153                                      CursorInfoRequest->OutputHandle,
154                                      &Buffer, GENERIC_WRITE, TRUE);
155     if (!NT_SUCCESS(Status)) return Status;
156 
157     Status = ConDrvSetConsoleCursorInfo(Buffer->Header.Console,
158                                         Buffer,
159                                         &CursorInfoRequest->Info);
160 
161     ConSrvReleaseScreenBuffer(Buffer, TRUE);
162     return Status;
163 }
164 
165 NTSTATUS NTAPI
166 ConDrvSetConsoleCursorPosition(IN PCONSOLE Console,
167                                IN PTEXTMODE_SCREEN_BUFFER Buffer,
168                                IN PCOORD Position);
169 CSR_API(SrvSetConsoleCursorPosition)
170 {
171     NTSTATUS Status;
172     PCONSOLE_SETCURSORPOSITION SetCursorPositionRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorPositionRequest;
173     PTEXTMODE_SCREEN_BUFFER Buffer;
174 
175     DPRINT("SrvSetConsoleCursorPosition\n");
176 
177     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
178                                      SetCursorPositionRequest->OutputHandle,
179                                      &Buffer, GENERIC_WRITE, TRUE);
180     if (!NT_SUCCESS(Status)) return Status;
181 
182     Status = ConDrvSetConsoleCursorPosition(Buffer->Header.Console,
183                                             Buffer,
184                                             &SetCursorPositionRequest->Position);
185 
186     ConSrvReleaseScreenBuffer(Buffer, TRUE);
187     return Status;
188 }
189 
190 CSR_API(SrvCreateConsoleScreenBuffer)
191 {
192     NTSTATUS Status = STATUS_INVALID_PARAMETER;
193     PCONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CreateScreenBufferRequest;
194     PCSR_PROCESS Process = CsrGetClientThread()->Process;
195     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
196     PCONSRV_CONSOLE Console;
197     PCONSOLE_SCREEN_BUFFER Buff;
198 
199     PVOID ScreenBufferInfo = NULL;
200     TEXTMODE_BUFFER_INFO TextModeInfo = {{80, 25},
201                                          DEFAULT_SCREEN_ATTRIB,
202                                          DEFAULT_POPUP_ATTRIB ,
203                                          TRUE,
204                                          CSR_DEFAULT_CURSOR_SIZE};
205     GRAPHICS_BUFFER_INFO GraphicsInfo;
206     GraphicsInfo.Info = CreateScreenBufferRequest->GraphicsBufferInfo; // HACK for MSVC
207 
208     DPRINT("SrvCreateConsoleScreenBuffer\n");
209 
210     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
211     if (!NT_SUCCESS(Status)) return Status;
212 
213     if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_TEXTMODE_BUFFER)
214     {
215         ScreenBufferInfo = &TextModeInfo;
216 
217         /*
218         if (Console->ActiveBuffer)
219         {
220             TextModeInfo.ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize;
221             if (TextModeInfo.ScreenBufferSize.X == 0) TextModeInfo.ScreenBufferSize.X = 80;
222             if (TextModeInfo.ScreenBufferSize.Y == 0) TextModeInfo.ScreenBufferSize.Y = 25;
223 
224             TextModeInfo.ScreenAttrib = Console->ActiveBuffer->ScreenBuffer.TextBuffer.ScreenDefaultAttrib;
225             TextModeInfo.PopupAttrib  = Console->ActiveBuffer->ScreenBuffer.TextBuffer.PopupDefaultAttrib;
226 
227             TextModeInfo.IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible;
228             TextModeInfo.CursorSize      = Console->ActiveBuffer->CursorInfo.dwSize;
229         }
230         */
231 
232         /*
233          * This is Windows' behaviour
234          */
235 
236         /* Use the current console size. Regularize it if needed. */
237         TextModeInfo.ScreenBufferSize = Console->ConsoleSize;
238         if (TextModeInfo.ScreenBufferSize.X == 0) TextModeInfo.ScreenBufferSize.X = 1;
239         if (TextModeInfo.ScreenBufferSize.Y == 0) TextModeInfo.ScreenBufferSize.Y = 1;
240 
241         /* If we have an active screen buffer, use its attributes as the new ones */
242         if (Console->ActiveBuffer && GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER)
243         {
244             PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)Console->ActiveBuffer;
245 
246             TextModeInfo.ScreenAttrib = Buffer->ScreenDefaultAttrib;
247             TextModeInfo.PopupAttrib  = Buffer->PopupDefaultAttrib;
248 
249             TextModeInfo.IsCursorVisible = Buffer->CursorInfo.bVisible;
250             TextModeInfo.CursorSize      = Buffer->CursorInfo.dwSize;
251         }
252     }
253     else if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_GRAPHICS_BUFFER)
254     {
255         /* Get infos from the graphics buffer information structure */
256         if (!CsrValidateMessageBuffer(ApiMessage,
257                                       (PVOID*)&CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMapInfo,
258                                       CreateScreenBufferRequest->GraphicsBufferInfo.dwBitMapInfoLength,
259                                       sizeof(BYTE)))
260         {
261             Status = STATUS_INVALID_PARAMETER;
262             goto Quit;
263         }
264 
265         ScreenBufferInfo = &GraphicsInfo;
266 
267         /* Initialize shared variables */
268         // CreateScreenBufferRequest->GraphicsBufferInfo.hMutex
269         CreateScreenBufferRequest->hMutex   = GraphicsInfo.Info.hMutex   = INVALID_HANDLE_VALUE;
270         // CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap
271         CreateScreenBufferRequest->lpBitMap = GraphicsInfo.Info.lpBitMap = NULL;
272 
273         /* A graphics screen buffer is never inheritable */
274         CreateScreenBufferRequest->InheritHandle = FALSE;
275     }
276 
277     Status = ConDrvCreateScreenBuffer(&Buff,
278                                       (PCONSOLE)Console,
279                                       Process->ProcessHandle,
280                                       CreateScreenBufferRequest->ScreenBufferType,
281                                       ScreenBufferInfo);
282     if (!NT_SUCCESS(Status)) goto Quit;
283 
284     /* Insert the new handle inside the process handles table */
285     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
286 
287     Status = ConSrvInsertObject(ProcessData,
288                                 &CreateScreenBufferRequest->OutputHandle,
289                                 &Buff->Header,
290                                 CreateScreenBufferRequest->DesiredAccess,
291                                 CreateScreenBufferRequest->InheritHandle,
292                                 CreateScreenBufferRequest->ShareMode);
293 
294     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
295 
296     if (!NT_SUCCESS(Status)) goto Quit;
297 
298     if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_GRAPHICS_BUFFER)
299     {
300         PGRAPHICS_SCREEN_BUFFER Buffer = (PGRAPHICS_SCREEN_BUFFER)Buff;
301         /*
302          * Initialize the graphics buffer information structure
303          * and give it back to the client.
304          */
305         // CreateScreenBufferRequest->GraphicsBufferInfo.hMutex
306         CreateScreenBufferRequest->hMutex   = Buffer->ClientMutex;
307         // CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap
308         CreateScreenBufferRequest->lpBitMap = Buffer->ClientBitMap;
309     }
310 
311 Quit:
312     ConSrvReleaseConsole(Console, TRUE);
313     return Status;
314 }
315 
316 NTSTATUS NTAPI
317 ConDrvSetConsoleActiveScreenBuffer(IN PCONSOLE Console,
318                                    IN PCONSOLE_SCREEN_BUFFER Buffer);
319 CSR_API(SrvSetConsoleActiveScreenBuffer)
320 {
321     NTSTATUS Status;
322     PCONSOLE_SETACTIVESCREENBUFFER SetScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferRequest;
323     PCONSOLE_SCREEN_BUFFER Buffer;
324 
325     DPRINT("SrvSetConsoleActiveScreenBuffer\n");
326 
327     Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
328                                    SetScreenBufferRequest->OutputHandle,
329                                    &Buffer, GENERIC_WRITE, TRUE);
330     if (!NT_SUCCESS(Status)) return Status;
331 
332     Status = ConDrvSetConsoleActiveScreenBuffer(Buffer->Header.Console,
333                                                 Buffer);
334 
335     ConSrvReleaseScreenBuffer(Buffer, TRUE);
336     return Status;
337 }
338 
339 
340 /* CSR THREADS FOR WriteConsole ***********************************************/
341 
342 static NTSTATUS
343 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
344                IN PCSR_THREAD ClientThread,
345                IN BOOLEAN CreateWaitBlock OPTIONAL);
346 
347 // Wait function CSR_WAIT_FUNCTION
348 static BOOLEAN
349 NTAPI
350 WriteConsoleThread(IN PLIST_ENTRY WaitList,
351                    IN PCSR_THREAD WaitThread,
352                    IN PCSR_API_MESSAGE WaitApiMessage,
353                    IN PVOID WaitContext,
354                    IN PVOID WaitArgument1,
355                    IN PVOID WaitArgument2,
356                    IN ULONG WaitFlags)
357 {
358     NTSTATUS Status;
359 
360     DPRINT("WriteConsoleThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
361 
362     /*
363      * If we are notified of the process termination via a call
364      * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
365      * CsrDestroyThread, just return.
366      */
367     if (WaitFlags & CsrProcessTerminating)
368     {
369         Status = STATUS_THREAD_IS_TERMINATING;
370         goto Quit;
371     }
372 
373     Status = DoWriteConsole(WaitApiMessage, WaitThread, FALSE);
374 
375 Quit:
376     if (Status != STATUS_PENDING)
377     {
378         WaitApiMessage->Status = Status;
379     }
380 
381     return (Status == STATUS_PENDING ? FALSE : TRUE);
382 }
383 
384 NTSTATUS NTAPI
385 ConDrvWriteConsole(IN PCONSOLE Console,
386                    IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
387                    IN BOOLEAN Unicode,
388                    IN PVOID StringBuffer,
389                    IN ULONG NumCharsToWrite,
390                    OUT PULONG NumCharsWritten OPTIONAL);
391 static NTSTATUS
392 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
393                IN PCSR_THREAD ClientThread,
394                IN BOOLEAN CreateWaitBlock OPTIONAL)
395 {
396     NTSTATUS Status;
397     PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
398     PTEXTMODE_SCREEN_BUFFER ScreenBuffer;
399 
400     PVOID Buffer;
401     ULONG NrCharactersWritten = 0;
402     ULONG CharSize = (WriteConsoleRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
403 
404     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(ClientThread->Process),
405                                      WriteConsoleRequest->OutputHandle,
406                                      &ScreenBuffer, GENERIC_WRITE, FALSE);
407     if (!NT_SUCCESS(Status)) return Status;
408 
409     /*
410      * For optimization purposes, Windows (and hence ReactOS, too, for
411      * compatibility reasons) uses a static buffer if no more than eighty
412      * bytes are written. Otherwise a new buffer is used.
413      * The client-side expects that we know this behaviour.
414      */
415     if (WriteConsoleRequest->UsingStaticBuffer &&
416         WriteConsoleRequest->NumBytes <= sizeof(WriteConsoleRequest->StaticBuffer))
417     {
418         /*
419          * Adjust the internal pointer, because its old value points to
420          * the static buffer in the original ApiMessage structure.
421          */
422         // WriteConsoleRequest->Buffer = WriteConsoleRequest->StaticBuffer;
423         Buffer = WriteConsoleRequest->StaticBuffer;
424     }
425     else
426     {
427         Buffer = WriteConsoleRequest->Buffer;
428     }
429 
430     DPRINT("Calling ConDrvWriteConsole\n");
431     Status = ConDrvWriteConsole(ScreenBuffer->Header.Console,
432                                 ScreenBuffer,
433                                 WriteConsoleRequest->Unicode,
434                                 Buffer,
435                                 WriteConsoleRequest->NumBytes / CharSize, // NrCharactersToWrite
436                                 &NrCharactersWritten);
437     DPRINT("ConDrvWriteConsole returned (%d ; Status = 0x%08x)\n",
438            NrCharactersWritten, Status);
439 
440     if (Status == STATUS_PENDING)
441     {
442         if (CreateWaitBlock)
443         {
444             PCONSRV_CONSOLE Console = (PCONSRV_CONSOLE)ScreenBuffer->Header.Console;
445 
446             if (!CsrCreateWait(&Console->WriteWaitQueue,
447                                WriteConsoleThread,
448                                ClientThread,
449                                ApiMessage,
450                                NULL))
451             {
452                 /* Fail */
453                 Status = STATUS_NO_MEMORY;
454                 goto Quit;
455             }
456         }
457 
458         /* Wait until we un-pause the console */
459         // Status = STATUS_PENDING;
460     }
461     else
462     {
463         /* We read all what we wanted. Set the number of bytes written. */
464         WriteConsoleRequest->NumBytes = NrCharactersWritten * CharSize;
465     }
466 
467 Quit:
468     ConSrvReleaseScreenBuffer(ScreenBuffer, FALSE);
469     return Status;
470 }
471 
472 
473 /* TEXT OUTPUT APIS ***********************************************************/
474 
475 NTSTATUS NTAPI
476 ConDrvReadConsoleOutput(IN PCONSOLE Console,
477                         IN PTEXTMODE_SCREEN_BUFFER Buffer,
478                         IN BOOLEAN Unicode,
479                         OUT PCHAR_INFO CharInfo/*Buffer*/,
480                         IN OUT PSMALL_RECT ReadRegion);
481 CSR_API(SrvReadConsoleOutput)
482 {
483     NTSTATUS Status;
484     PCONSOLE_READOUTPUT ReadOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputRequest;
485     PTEXTMODE_SCREEN_BUFFER Buffer;
486 
487     ULONG NumCells;
488     PCHAR_INFO CharInfo;
489 
490     DPRINT("SrvReadConsoleOutput\n");
491 
492     NumCells = (ReadOutputRequest->ReadRegion.Right - ReadOutputRequest->ReadRegion.Left + 1) *
493                (ReadOutputRequest->ReadRegion.Bottom - ReadOutputRequest->ReadRegion.Top + 1);
494 
495     /*
496      * For optimization purposes, Windows (and hence ReactOS, too, for
497      * compatibility reasons) uses a static buffer if no more than one
498      * cell is read. Otherwise a new buffer is used.
499      * The client-side expects that we know this behaviour.
500      */
501     if (NumCells <= 1)
502     {
503         /*
504          * Adjust the internal pointer, because its old value points to
505          * the static buffer in the original ApiMessage structure.
506          */
507         // ReadOutputRequest->CharInfo = &ReadOutputRequest->StaticBuffer;
508         CharInfo = &ReadOutputRequest->StaticBuffer;
509     }
510     else
511     {
512         if (!CsrValidateMessageBuffer(ApiMessage,
513                                       (PVOID*)&ReadOutputRequest->CharInfo,
514                                       NumCells,
515                                       sizeof(CHAR_INFO)))
516         {
517             return STATUS_INVALID_PARAMETER;
518         }
519 
520         CharInfo = ReadOutputRequest->CharInfo;
521     }
522 
523     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
524                                      ReadOutputRequest->OutputHandle,
525                                      &Buffer, GENERIC_READ, TRUE);
526     if (!NT_SUCCESS(Status)) return Status;
527 
528     Status = ConDrvReadConsoleOutput(Buffer->Header.Console,
529                                      Buffer,
530                                      ReadOutputRequest->Unicode,
531                                      CharInfo,
532                                      &ReadOutputRequest->ReadRegion);
533 
534     ConSrvReleaseScreenBuffer(Buffer, TRUE);
535     return Status;
536 }
537 
538 NTSTATUS NTAPI
539 ConDrvWriteConsoleOutput(IN PCONSOLE Console,
540                          IN PTEXTMODE_SCREEN_BUFFER Buffer,
541                          IN BOOLEAN Unicode,
542                          IN PCHAR_INFO CharInfo/*Buffer*/,
543                          IN OUT PSMALL_RECT WriteRegion);
544 CSR_API(SrvWriteConsoleOutput)
545 {
546     NTSTATUS Status;
547     PCONSOLE_WRITEOUTPUT WriteOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputRequest;
548     PTEXTMODE_SCREEN_BUFFER Buffer;
549     PCSR_PROCESS Process = CsrGetClientThread()->Process;
550 
551     ULONG NumCells;
552     PCHAR_INFO CharInfo;
553 
554     DPRINT("SrvWriteConsoleOutput\n");
555 
556     NumCells = (WriteOutputRequest->WriteRegion.Right - WriteOutputRequest->WriteRegion.Left + 1) *
557                (WriteOutputRequest->WriteRegion.Bottom - WriteOutputRequest->WriteRegion.Top + 1);
558 
559     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(Process),
560                                      WriteOutputRequest->OutputHandle,
561                                      &Buffer, GENERIC_WRITE, TRUE);
562     if (!NT_SUCCESS(Status)) return Status;
563 
564     /*
565      * Validate the message buffer if we do not use a process' heap buffer
566      * (CsrAllocateCaptureBuffer succeeded because we haven't allocated
567      * a too large (>= 64 kB, size of the CSR heap) data buffer).
568      */
569     if (!WriteOutputRequest->UseVirtualMemory)
570     {
571         /*
572          * For optimization purposes, Windows (and hence ReactOS, too, for
573          * compatibility reasons) uses a static buffer if no more than one
574          * cell is written. Otherwise a new buffer is used.
575          * The client-side expects that we know this behaviour.
576          */
577         if (NumCells <= 1)
578         {
579             /*
580              * Adjust the internal pointer, because its old value points to
581              * the static buffer in the original ApiMessage structure.
582              */
583             // WriteOutputRequest->CharInfo = &WriteOutputRequest->StaticBuffer;
584             CharInfo = &WriteOutputRequest->StaticBuffer;
585         }
586         else
587         {
588             if (!CsrValidateMessageBuffer(ApiMessage,
589                                           (PVOID*)&WriteOutputRequest->CharInfo,
590                                           NumCells,
591                                           sizeof(CHAR_INFO)))
592             {
593                 Status = STATUS_INVALID_PARAMETER;
594                 goto Quit;
595             }
596 
597             CharInfo = WriteOutputRequest->CharInfo;
598         }
599     }
600     else
601     {
602         /*
603          * This was not the case: we use a heap buffer. Retrieve its contents.
604          */
605         ULONG Size = NumCells * sizeof(CHAR_INFO);
606 
607         CharInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size);
608         if (CharInfo == NULL)
609         {
610             Status = STATUS_NO_MEMORY;
611             goto Quit;
612         }
613 
614         Status = NtReadVirtualMemory(Process->ProcessHandle,
615                                      WriteOutputRequest->CharInfo,
616                                      CharInfo,
617                                      Size,
618                                      NULL);
619         if (!NT_SUCCESS(Status))
620         {
621             ConsoleFreeHeap(CharInfo);
622             // Status = STATUS_NO_MEMORY;
623             goto Quit;
624         }
625     }
626 
627     Status = ConDrvWriteConsoleOutput(Buffer->Header.Console,
628                                       Buffer,
629                                       WriteOutputRequest->Unicode,
630                                       CharInfo,
631                                       &WriteOutputRequest->WriteRegion);
632 
633     /* Free the temporary buffer if we used the process' heap buffer */
634     if (WriteOutputRequest->UseVirtualMemory && CharInfo)
635         ConsoleFreeHeap(CharInfo);
636 
637 Quit:
638     ConSrvReleaseScreenBuffer(Buffer, TRUE);
639     return Status;
640 }
641 
642 CSR_API(SrvWriteConsole)
643 {
644     NTSTATUS Status;
645     PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
646 
647     DPRINT("SrvWriteConsole\n");
648 
649     /*
650      * For optimization purposes, Windows (and hence ReactOS, too, for
651      * compatibility reasons) uses a static buffer if no more than eighty
652      * bytes are written. Otherwise a new buffer is used.
653      * The client-side expects that we know this behaviour.
654      */
655     if (WriteConsoleRequest->UsingStaticBuffer &&
656         WriteConsoleRequest->NumBytes <= sizeof(WriteConsoleRequest->StaticBuffer))
657     {
658         /*
659          * Adjust the internal pointer, because its old value points to
660          * the static buffer in the original ApiMessage structure.
661          */
662         // WriteConsoleRequest->Buffer = WriteConsoleRequest->StaticBuffer;
663     }
664     else
665     {
666         if (!CsrValidateMessageBuffer(ApiMessage,
667                                       (PVOID)&WriteConsoleRequest->Buffer,
668                                       WriteConsoleRequest->NumBytes,
669                                       sizeof(BYTE)))
670         {
671             return STATUS_INVALID_PARAMETER;
672         }
673     }
674 
675     Status = DoWriteConsole(ApiMessage, CsrGetClientThread(), TRUE);
676 
677     if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
678 
679     return Status;
680 }
681 
682 NTSTATUS NTAPI
683 ConDrvReadConsoleOutputString(IN PCONSOLE Console,
684                               IN PTEXTMODE_SCREEN_BUFFER Buffer,
685                               IN CODE_TYPE CodeType,
686                               OUT PVOID StringBuffer,
687                               IN ULONG NumCodesToRead,
688                               IN PCOORD ReadCoord,
689                               // OUT PCOORD EndCoord,
690                               OUT PULONG NumCodesRead OPTIONAL);
691 CSR_API(SrvReadConsoleOutputString)
692 {
693     NTSTATUS Status;
694     PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputCodeRequest;
695     PTEXTMODE_SCREEN_BUFFER Buffer;
696     ULONG CodeSize;
697 
698     PVOID pCode;
699 
700     DPRINT("SrvReadConsoleOutputString\n");
701 
702     switch (ReadOutputCodeRequest->CodeType)
703     {
704         case CODE_ASCII:
705             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
706             break;
707 
708         case CODE_UNICODE:
709             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
710             break;
711 
712         case CODE_ATTRIBUTE:
713             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
714             break;
715 
716         default:
717             return STATUS_INVALID_PARAMETER;
718     }
719 
720     /*
721      * For optimization purposes, Windows (and hence ReactOS, too, for
722      * compatibility reasons) uses a static buffer if no more than eighty
723      * bytes are read. Otherwise a new buffer is used.
724      * The client-side expects that we know this behaviour.
725      */
726     if (ReadOutputCodeRequest->NumCodes * CodeSize <= sizeof(ReadOutputCodeRequest->CodeStaticBuffer))
727     {
728         /*
729          * Adjust the internal pointer, because its old value points to
730          * the static buffer in the original ApiMessage structure.
731          */
732         // ReadOutputCodeRequest->pCode = ReadOutputCodeRequest->CodeStaticBuffer;
733         pCode = ReadOutputCodeRequest->CodeStaticBuffer;
734     }
735     else
736     {
737         if (!CsrValidateMessageBuffer(ApiMessage,
738                                       (PVOID*)&ReadOutputCodeRequest->pCode,
739                                       ReadOutputCodeRequest->NumCodes,
740                                       CodeSize))
741         {
742             return STATUS_INVALID_PARAMETER;
743         }
744 
745         pCode = ReadOutputCodeRequest->pCode;
746     }
747 
748     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
749                                      ReadOutputCodeRequest->OutputHandle,
750                                      &Buffer, GENERIC_READ, TRUE);
751     if (!NT_SUCCESS(Status))
752     {
753         ReadOutputCodeRequest->NumCodes = 0;
754         return Status;
755     }
756 
757     Status = ConDrvReadConsoleOutputString(Buffer->Header.Console,
758                                            Buffer,
759                                            ReadOutputCodeRequest->CodeType,
760                                            pCode,
761                                            ReadOutputCodeRequest->NumCodes,
762                                            &ReadOutputCodeRequest->Coord,
763                                            // &ReadOutputCodeRequest->EndCoord,
764                                            &ReadOutputCodeRequest->NumCodes);
765 
766     ConSrvReleaseScreenBuffer(Buffer, TRUE);
767     return Status;
768 }
769 
770 NTSTATUS NTAPI
771 ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
772                                IN PTEXTMODE_SCREEN_BUFFER Buffer,
773                                IN CODE_TYPE CodeType,
774                                IN PVOID StringBuffer,
775                                IN ULONG NumCodesToWrite,
776                                IN PCOORD WriteCoord,
777                                // OUT PCOORD EndCoord,
778                                OUT PULONG NumCodesWritten OPTIONAL);
779 CSR_API(SrvWriteConsoleOutputString)
780 {
781     NTSTATUS Status;
782     PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputCodeRequest;
783     PTEXTMODE_SCREEN_BUFFER Buffer;
784     ULONG CodeSize;
785 
786     PVOID pCode;
787 
788     DPRINT("SrvWriteConsoleOutputString\n");
789 
790     switch (WriteOutputCodeRequest->CodeType)
791     {
792         case CODE_ASCII:
793             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
794             break;
795 
796         case CODE_UNICODE:
797             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
798             break;
799 
800         case CODE_ATTRIBUTE:
801             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
802             break;
803 
804         default:
805             return STATUS_INVALID_PARAMETER;
806     }
807 
808     /*
809      * For optimization purposes, Windows (and hence ReactOS, too, for
810      * compatibility reasons) uses a static buffer if no more than eighty
811      * bytes are written. Otherwise a new buffer is used.
812      * The client-side expects that we know this behaviour.
813      */
814     if (WriteOutputCodeRequest->NumCodes * CodeSize <= sizeof(WriteOutputCodeRequest->CodeStaticBuffer))
815     {
816         /*
817          * Adjust the internal pointer, because its old value points to
818          * the static buffer in the original ApiMessage structure.
819          */
820         // WriteOutputCodeRequest->pCode = WriteOutputCodeRequest->CodeStaticBuffer;
821         pCode = WriteOutputCodeRequest->CodeStaticBuffer;
822     }
823     else
824     {
825         if (!CsrValidateMessageBuffer(ApiMessage,
826                                       (PVOID*)&WriteOutputCodeRequest->pCode,
827                                       WriteOutputCodeRequest->NumCodes,
828                                       CodeSize))
829         {
830             return STATUS_INVALID_PARAMETER;
831         }
832 
833         pCode = WriteOutputCodeRequest->pCode;
834     }
835 
836     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
837                                      WriteOutputCodeRequest->OutputHandle,
838                                      &Buffer, GENERIC_WRITE, TRUE);
839     if (!NT_SUCCESS(Status))
840     {
841         WriteOutputCodeRequest->NumCodes = 0;
842         return Status;
843     }
844 
845     Status = ConDrvWriteConsoleOutputString(Buffer->Header.Console,
846                                             Buffer,
847                                             WriteOutputCodeRequest->CodeType,
848                                             pCode,
849                                             WriteOutputCodeRequest->NumCodes,
850                                             &WriteOutputCodeRequest->Coord,
851                                             // &WriteOutputCodeRequest->EndCoord,
852                                             &WriteOutputCodeRequest->NumCodes);
853 
854     ConSrvReleaseScreenBuffer(Buffer, TRUE);
855     return Status;
856 }
857 
858 NTSTATUS NTAPI
859 ConDrvFillConsoleOutput(IN PCONSOLE Console,
860                         IN PTEXTMODE_SCREEN_BUFFER Buffer,
861                         IN CODE_TYPE CodeType,
862                         IN CODE_ELEMENT Code,
863                         IN ULONG NumCodesToWrite,
864                         IN PCOORD WriteCoord,
865                         OUT PULONG NumCodesWritten OPTIONAL);
866 CSR_API(SrvFillConsoleOutput)
867 {
868     NTSTATUS Status;
869     PCONSOLE_FILLOUTPUTCODE FillOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputRequest;
870     PTEXTMODE_SCREEN_BUFFER Buffer;
871     CODE_TYPE CodeType = FillOutputRequest->CodeType;
872 
873     DPRINT("SrvFillConsoleOutput\n");
874 
875     if ( (CodeType != CODE_ASCII    ) &&
876          (CodeType != CODE_UNICODE  ) &&
877          (CodeType != CODE_ATTRIBUTE) )
878     {
879         return STATUS_INVALID_PARAMETER;
880     }
881 
882     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
883                                      FillOutputRequest->OutputHandle,
884                                      &Buffer, GENERIC_WRITE, TRUE);
885     if (!NT_SUCCESS(Status))
886     {
887         FillOutputRequest->NumCodes = 0;
888         return Status;
889     }
890 
891     Status = ConDrvFillConsoleOutput(Buffer->Header.Console,
892                                      Buffer,
893                                      CodeType,
894                                      FillOutputRequest->Code,
895                                      FillOutputRequest->NumCodes,
896                                      &FillOutputRequest->WriteCoord,
897                                      &FillOutputRequest->NumCodes);
898 
899     ConSrvReleaseScreenBuffer(Buffer, TRUE);
900     return Status;
901 }
902 
903 NTSTATUS NTAPI
904 ConDrvGetConsoleScreenBufferInfo(IN  PCONSOLE Console,
905                                  IN  PTEXTMODE_SCREEN_BUFFER Buffer,
906                                  OUT PCOORD ScreenBufferSize,
907                                  OUT PCOORD CursorPosition,
908                                  OUT PCOORD ViewOrigin,
909                                  OUT PCOORD ViewSize,
910                                  OUT PCOORD MaximumViewSize,
911                                  OUT PWORD  Attributes);
912 CSR_API(SrvGetConsoleScreenBufferInfo)
913 {
914     NTSTATUS Status;
915     PCONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScreenBufferInfoRequest;
916     PTEXTMODE_SCREEN_BUFFER Buffer;
917 
918     DPRINT("SrvGetConsoleScreenBufferInfo\n");
919 
920     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
921                                      ScreenBufferInfoRequest->OutputHandle,
922                                      &Buffer, GENERIC_READ, TRUE);
923     if (!NT_SUCCESS(Status)) return Status;
924 
925     Status = ConDrvGetConsoleScreenBufferInfo(Buffer->Header.Console,
926                                               Buffer,
927                                               &ScreenBufferInfoRequest->ScreenBufferSize,
928                                               &ScreenBufferInfoRequest->CursorPosition,
929                                               &ScreenBufferInfoRequest->ViewOrigin,
930                                               &ScreenBufferInfoRequest->ViewSize,
931                                               &ScreenBufferInfoRequest->MaximumViewSize,
932                                               &ScreenBufferInfoRequest->Attributes);
933 
934     ConSrvReleaseScreenBuffer(Buffer, TRUE);
935     return Status;
936 }
937 
938 NTSTATUS NTAPI
939 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
940                               IN PTEXTMODE_SCREEN_BUFFER Buffer,
941                               IN WORD Attributes);
942 CSR_API(SrvSetConsoleTextAttribute)
943 {
944     NTSTATUS Status;
945     PCONSOLE_SETTEXTATTRIB SetTextAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetTextAttribRequest;
946     PTEXTMODE_SCREEN_BUFFER Buffer;
947 
948     DPRINT("SrvSetConsoleTextAttribute\n");
949 
950     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
951                                      SetTextAttribRequest->OutputHandle,
952                                      &Buffer, GENERIC_WRITE, TRUE);
953     if (!NT_SUCCESS(Status)) return Status;
954 
955     Status = ConDrvSetConsoleTextAttribute(Buffer->Header.Console,
956                                            Buffer,
957                                            SetTextAttribRequest->Attributes);
958 
959     ConSrvReleaseScreenBuffer(Buffer, TRUE);
960     return Status;
961 }
962 
963 NTSTATUS NTAPI
964 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
965                                  IN PTEXTMODE_SCREEN_BUFFER Buffer,
966                                  IN PCOORD Size);
967 CSR_API(SrvSetConsoleScreenBufferSize)
968 {
969     NTSTATUS Status;
970     PCONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferSizeRequest;
971     PTEXTMODE_SCREEN_BUFFER Buffer;
972 
973     DPRINT("SrvSetConsoleScreenBufferSize\n");
974 
975     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
976                                      SetScreenBufferSizeRequest->OutputHandle,
977                                      &Buffer, GENERIC_WRITE, TRUE);
978     if (!NT_SUCCESS(Status)) return Status;
979 
980     Status = ConDrvSetConsoleScreenBufferSize(Buffer->Header.Console,
981                                               Buffer,
982                                               &SetScreenBufferSizeRequest->Size);
983 
984     ConSrvReleaseScreenBuffer(Buffer, TRUE);
985     return Status;
986 }
987 
988 NTSTATUS NTAPI
989 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
990                                 IN PTEXTMODE_SCREEN_BUFFER Buffer,
991                                 IN BOOLEAN Unicode,
992                                 IN PSMALL_RECT ScrollRectangle,
993                                 IN BOOLEAN UseClipRectangle,
994                                 IN PSMALL_RECT ClipRectangle OPTIONAL,
995                                 IN PCOORD DestinationOrigin,
996                                 IN CHAR_INFO FillChar);
997 CSR_API(SrvScrollConsoleScreenBuffer)
998 {
999     NTSTATUS Status;
1000     PCONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScrollScreenBufferRequest;
1001     PTEXTMODE_SCREEN_BUFFER Buffer;
1002 
1003     DPRINT("SrvScrollConsoleScreenBuffer\n");
1004 
1005     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1006                                      ScrollScreenBufferRequest->OutputHandle,
1007                                      &Buffer, GENERIC_WRITE, TRUE);
1008     if (!NT_SUCCESS(Status)) return Status;
1009 
1010     Status = ConDrvScrollConsoleScreenBuffer(Buffer->Header.Console,
1011                                              Buffer,
1012                                              ScrollScreenBufferRequest->Unicode,
1013                                              &ScrollScreenBufferRequest->ScrollRectangle,
1014                                              ScrollScreenBufferRequest->UseClipRectangle,
1015                                              &ScrollScreenBufferRequest->ClipRectangle,
1016                                              &ScrollScreenBufferRequest->DestinationOrigin,
1017                                              ScrollScreenBufferRequest->Fill);
1018 
1019     ConSrvReleaseScreenBuffer(Buffer, TRUE);
1020     return Status;
1021 }
1022 
1023 NTSTATUS NTAPI
1024 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console,
1025                            IN PTEXTMODE_SCREEN_BUFFER Buffer,
1026                            IN BOOLEAN Absolute,
1027                            IN PSMALL_RECT WindowRect);
1028 CSR_API(SrvSetConsoleWindowInfo)
1029 {
1030     NTSTATUS Status;
1031     PCONSOLE_SETWINDOWINFO SetWindowInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetWindowInfoRequest;
1032     // PCONSOLE_SCREEN_BUFFER Buffer;
1033     PTEXTMODE_SCREEN_BUFFER Buffer;
1034 
1035     DPRINT1("SrvSetConsoleWindowInfo(0x%08x, %d, {L%d, T%d, R%d, B%d}) called\n",
1036             SetWindowInfoRequest->OutputHandle, SetWindowInfoRequest->Absolute,
1037             SetWindowInfoRequest->WindowRect.Left ,
1038             SetWindowInfoRequest->WindowRect.Top  ,
1039             SetWindowInfoRequest->WindowRect.Right,
1040             SetWindowInfoRequest->WindowRect.Bottom);
1041 
1042     // ConSrvGetScreenBuffer
1043     Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1044                                      SetWindowInfoRequest->OutputHandle,
1045                                      &Buffer, GENERIC_READ, TRUE);
1046     if (!NT_SUCCESS(Status)) return Status;
1047 
1048     Status = ConDrvSetConsoleWindowInfo(Buffer->Header.Console,
1049                                         Buffer,
1050                                         SetWindowInfoRequest->Absolute,
1051                                         &SetWindowInfoRequest->WindowRect);
1052 
1053     ConSrvReleaseScreenBuffer(Buffer, TRUE);
1054     return Status;
1055 }
1056 
1057 /* EOF */
1058