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