2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/conoutput.c
5 * PURPOSE: Console I/O functions
9 /* INCLUDES *******************************************************************/
18 /* GLOBALS ********************************************************************/
20 #define ConioInitRect(Rect, top, left, bottom, right) \
22 ((Rect)->Top) = top; \
23 ((Rect)->Left) = left; \
24 ((Rect)->Bottom) = bottom; \
25 ((Rect)->Right) = right; \
28 #define ConioIsRectEmpty(Rect) \
29 (((Rect)->Left > (Rect)->Right) || ((Rect)->Top > (Rect)->Bottom))
31 #define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \
32 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
34 #define ConsoleAnsiCharToUnicodeChar(Console, dWChar, sChar) \
35 MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1)
38 /* PRIVATE FUNCTIONS **********************************************************/
41 ConioCoordToPointer(PCONSOLE_SCREEN_BUFFER Buff
, ULONG X
, ULONG Y
)
43 return &Buff
->Buffer
[2 * (((Y
+ Buff
->VirtualY
) % Buff
->MaxY
) * Buff
->MaxX
+ X
)];
47 ClearLineBuffer(PCONSOLE_SCREEN_BUFFER Buff
)
49 PBYTE Ptr
= ConioCoordToPointer(Buff
, 0, Buff
->CurrentY
);
52 for (Pos
= 0; Pos
< Buff
->MaxX
; Pos
++)
56 *Ptr
++ = Buff
->DefaultAttrib
;
61 CsrInitConsoleScreenBuffer(PCONSOLE Console
,
62 PCONSOLE_SCREEN_BUFFER Buffer
)
64 DPRINT("CsrInitConsoleScreenBuffer Size X %d Size Y %d\n", Buffer
->MaxX
, Buffer
->MaxY
);
66 Buffer
->Header
.Type
= CONIO_SCREEN_BUFFER_MAGIC
;
67 Buffer
->Header
.Console
= Console
;
68 Buffer
->Header
.HandleCount
= 0;
72 Buffer
->Buffer
= RtlAllocateHeap(ConSrvHeap
, HEAP_ZERO_MEMORY
, Buffer
->MaxX
* Buffer
->MaxY
* 2);
73 if (NULL
== Buffer
->Buffer
)
75 return STATUS_INSUFFICIENT_RESOURCES
;
77 ConioInitScreenBuffer(Console
, Buffer
);
78 /* initialize buffer to be empty with default attributes */
79 for (Buffer
->CurrentY
= 0 ; Buffer
->CurrentY
< Buffer
->MaxY
; Buffer
->CurrentY
++)
81 ClearLineBuffer(Buffer
);
83 Buffer
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
87 InsertHeadList(&Console
->BufferList
, &Buffer
->ListEntry
);
88 return STATUS_SUCCESS
;
92 ConioNextLine(PCONSOLE_SCREEN_BUFFER Buff
, SMALL_RECT
* UpdateRect
, UINT
*ScrolledLines
)
94 /* If we hit bottom, slide the viewable screen */
95 if (++Buff
->CurrentY
== Buff
->MaxY
)
98 if (++Buff
->VirtualY
== Buff
->MaxY
)
103 ClearLineBuffer(Buff
);
104 if (UpdateRect
->Top
!= 0)
109 UpdateRect
->Left
= 0;
110 UpdateRect
->Right
= Buff
->MaxX
- 1;
111 UpdateRect
->Bottom
= Buff
->CurrentY
;
115 ConioWriteConsole(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER Buff
,
116 CHAR
*Buffer
, DWORD Length
, BOOL Attrib
)
120 SMALL_RECT UpdateRect
;
121 LONG CursorStartX
, CursorStartY
;
124 CursorStartX
= Buff
->CurrentX
;
125 CursorStartY
= Buff
->CurrentY
;
126 UpdateRect
.Left
= Buff
->MaxX
;
127 UpdateRect
.Top
= Buff
->CurrentY
;
128 UpdateRect
.Right
= -1;
129 UpdateRect
.Bottom
= Buff
->CurrentY
;
132 for (i
= 0; i
< Length
; i
++)
134 if (Buff
->Mode
& ENABLE_PROCESSED_OUTPUT
)
137 if (Buffer
[i
] == '\n')
140 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
144 else if (Buffer
[i
] == '\b')
146 /* Only handle BS if we're not on the first pos of the first line */
147 if (0 != Buff
->CurrentX
|| 0 != Buff
->CurrentY
)
149 if (0 == Buff
->CurrentX
)
151 /* slide virtual position up */
152 Buff
->CurrentX
= Buff
->MaxX
- 1;
154 UpdateRect
.Top
= min(UpdateRect
.Top
, (LONG
)Buff
->CurrentY
);
160 Ptr
= ConioCoordToPointer(Buff
, Buff
->CurrentX
, Buff
->CurrentY
);
162 Ptr
[1] = Buff
->DefaultAttrib
;
163 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
) Buff
->CurrentX
);
164 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
) Buff
->CurrentX
);
169 else if (Buffer
[i
] == '\r')
172 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
) Buff
->CurrentX
);
173 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
) Buff
->CurrentX
);
177 else if (Buffer
[i
] == '\t')
181 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
)Buff
->CurrentX
);
182 EndX
= (Buff
->CurrentX
+ 8) & ~7;
183 if (EndX
> Buff
->MaxX
)
187 Ptr
= ConioCoordToPointer(Buff
, Buff
->CurrentX
, Buff
->CurrentY
);
188 while (Buff
->CurrentX
< EndX
)
191 *Ptr
++ = Buff
->DefaultAttrib
;
194 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
) Buff
->CurrentX
- 1);
195 if (Buff
->CurrentX
== Buff
->MaxX
)
197 if (Buff
->Mode
& ENABLE_WRAP_AT_EOL_OUTPUT
)
200 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
210 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
)Buff
->CurrentX
);
211 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
) Buff
->CurrentX
);
212 Ptr
= ConioCoordToPointer(Buff
, Buff
->CurrentX
, Buff
->CurrentY
);
216 Ptr
[1] = Buff
->DefaultAttrib
;
219 if (Buff
->CurrentX
== Buff
->MaxX
)
221 if (Buff
->Mode
& ENABLE_WRAP_AT_EOL_OUTPUT
)
224 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
228 Buff
->CurrentX
= CursorStartX
;
233 if (!ConioIsRectEmpty(&UpdateRect
) && Buff
== Console
->ActiveBuffer
)
235 ConioWriteStream(Console
, &UpdateRect
, CursorStartX
, CursorStartY
, ScrolledLines
,
239 return STATUS_SUCCESS
;
242 __inline BOOLEAN
ConioGetIntersection(
243 SMALL_RECT
* Intersection
,
247 if (ConioIsRectEmpty(Rect1
) ||
248 (ConioIsRectEmpty(Rect2
)) ||
249 (Rect1
->Top
> Rect2
->Bottom
) ||
250 (Rect1
->Left
> Rect2
->Right
) ||
251 (Rect1
->Bottom
< Rect2
->Top
) ||
252 (Rect1
->Right
< Rect2
->Left
))
254 /* The rectangles do not intersect */
255 ConioInitRect(Intersection
, 0, -1, 0, -1);
259 ConioInitRect(Intersection
,
260 max(Rect1
->Top
, Rect2
->Top
),
261 max(Rect1
->Left
, Rect2
->Left
),
262 min(Rect1
->Bottom
, Rect2
->Bottom
),
263 min(Rect1
->Right
, Rect2
->Right
));
268 __inline BOOLEAN
ConioGetUnion(
273 if (ConioIsRectEmpty(Rect1
))
275 if (ConioIsRectEmpty(Rect2
))
277 ConioInitRect(Union
, 0, -1, 0, -1);
285 else if (ConioIsRectEmpty(Rect2
))
292 min(Rect1
->Top
, Rect2
->Top
),
293 min(Rect1
->Left
, Rect2
->Left
),
294 max(Rect1
->Bottom
, Rect2
->Bottom
),
295 max(Rect1
->Right
, Rect2
->Right
));
302 * Move from one rectangle to another. We must be careful about the order that
303 * this is done, to avoid overwriting parts of the source before they are moved.
306 ConioMoveRegion(PCONSOLE_SCREEN_BUFFER ScreenBuffer
,
307 SMALL_RECT
* SrcRegion
,
308 SMALL_RECT
* DstRegion
,
309 SMALL_RECT
* ClipRegion
,
312 int Width
= ConioRectWidth(SrcRegion
);
313 int Height
= ConioRectHeight(SrcRegion
);
324 /* Moving down: work from bottom up */
325 SY
= SrcRegion
->Bottom
;
326 DY
= DstRegion
->Bottom
;
329 for (i
= 0; i
< Height
; i
++)
331 PWORD SRow
= (PWORD
)ConioCoordToPointer(ScreenBuffer
, 0, SY
);
332 PWORD DRow
= (PWORD
)ConioCoordToPointer(ScreenBuffer
, 0, DY
);
334 SX
= SrcRegion
->Left
;
335 DX
= DstRegion
->Left
;
339 /* Moving right: work from right to left */
340 SX
= SrcRegion
->Right
;
341 DX
= DstRegion
->Right
;
344 for (j
= 0; j
< Width
; j
++)
346 WORD Cell
= SRow
[SX
];
347 if (SX
>= ClipRegion
->Left
&& SX
<= ClipRegion
->Right
348 && SY
>= ClipRegion
->Top
&& SY
<= ClipRegion
->Bottom
)
352 if (DX
>= ClipRegion
->Left
&& DX
<= ClipRegion
->Right
353 && DY
>= ClipRegion
->Top
&& DY
<= ClipRegion
->Bottom
)
366 ConioDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer
)
368 PCONSOLE Console
= Buffer
->Header
.Console
;
370 RemoveEntryList(&Buffer
->ListEntry
);
371 if (Buffer
== Console
->ActiveBuffer
)
373 /* Deleted active buffer; switch to most recently created */
374 Console
->ActiveBuffer
= NULL
;
375 if (!IsListEmpty(&Console
->BufferList
))
377 Console
->ActiveBuffer
= CONTAINING_RECORD(Console
->BufferList
.Flink
, CONSOLE_SCREEN_BUFFER
, ListEntry
);
378 ConioDrawConsole(Console
);
382 RtlFreeHeap(ConSrvHeap
, 0, Buffer
->Buffer
);
383 RtlFreeHeap(ConSrvHeap
, 0, Buffer
);
387 ConioDrawConsole(PCONSOLE Console
)
391 ConioInitRect(&Region
, 0, 0, Console
->Size
.Y
- 1, Console
->Size
.X
- 1);
393 ConioDrawRegion(Console
, &Region
);
397 ConioComputeUpdateRect(PCONSOLE_SCREEN_BUFFER Buff
, SMALL_RECT
* UpdateRect
, PCOORD Start
, UINT Length
)
399 if (Buff
->MaxX
<= Start
->X
+ Length
)
401 UpdateRect
->Left
= 0;
405 UpdateRect
->Left
= Start
->X
;
407 if (Buff
->MaxX
<= Start
->X
+ Length
)
409 UpdateRect
->Right
= Buff
->MaxX
- 1;
413 UpdateRect
->Right
= Start
->X
+ Length
- 1;
415 UpdateRect
->Top
= Start
->Y
;
416 UpdateRect
->Bottom
= Start
->Y
+ (Start
->X
+ Length
- 1) / Buff
->MaxX
;
417 if (Buff
->MaxY
<= UpdateRect
->Bottom
)
419 UpdateRect
->Bottom
= Buff
->MaxY
- 1;
424 ConioEffectiveCursorSize(PCONSOLE Console
, DWORD Scale
)
426 DWORD Size
= (Console
->ActiveBuffer
->CursorInfo
.dwSize
* Scale
+ 99) / 100;
427 /* If line input in progress, perhaps adjust for insert toggle */
428 if (Console
->LineBuffer
&& !Console
->LineComplete
&& Console
->LineInsertToggle
)
429 return (Size
* 2 <= Scale
) ? (Size
* 2) : (Size
/ 2);
434 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage
,
435 IN PCSR_THREAD ClientThread
,
436 IN BOOL CreateWaitBlock OPTIONAL
);
438 // Wait function CSR_WAIT_FUNCTION
440 WriteConsoleThread(IN PLIST_ENTRY WaitList
,
441 IN PCSR_THREAD WaitThread
,
442 IN PCSR_API_MESSAGE WaitApiMessage
,
443 IN PVOID WaitContext
,
444 IN PVOID WaitArgument1
,
445 IN PVOID WaitArgument2
,
450 DPRINT1("WriteConsoleThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
453 * If we are notified of the process termination via a call
454 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
455 * CsrDestroyThread, just return.
457 if (WaitFlags
& CsrProcessTerminating
)
459 Status
= STATUS_THREAD_IS_TERMINATING
;
463 Status
= DoWriteConsole(WaitApiMessage
,
468 if (Status
!= STATUS_PENDING
)
470 WaitApiMessage
->Status
= Status
;
473 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
477 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage
,
478 IN PCSR_THREAD ClientThread
,
479 IN BOOL CreateWaitBlock OPTIONAL
)
481 NTSTATUS Status
= STATUS_SUCCESS
;
482 PCONSOLE_WRITECONSOLE WriteConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteConsoleRequest
;
484 PCONSOLE_SCREEN_BUFFER Buff
;
489 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(ClientThread
->Process
), WriteConsoleRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, FALSE
);
490 if (!NT_SUCCESS(Status
)) return Status
;
492 Console
= Buff
->Header
.Console
;
494 // if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION))
495 if (Console
->PauseFlags
&& Console
->UnpauseEvent
!= NULL
)
499 if (!CsrCreateWait(&Console
->WriteWaitQueue
,
507 ConioReleaseScreenBuffer(Buff
, FALSE
);
508 return STATUS_NO_MEMORY
;
512 /* Wait until we un-pause the console */
513 Status
= STATUS_PENDING
;
517 if (WriteConsoleRequest
->Unicode
)
519 Length
= WideCharToMultiByte(Console
->OutputCodePage
, 0,
520 (PWCHAR
)WriteConsoleRequest
->Buffer
,
521 WriteConsoleRequest
->NrCharactersToWrite
,
522 NULL
, 0, NULL
, NULL
);
523 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
);
526 WideCharToMultiByte(Console
->OutputCodePage
, 0,
527 (PWCHAR
)WriteConsoleRequest
->Buffer
,
528 WriteConsoleRequest
->NrCharactersToWrite
,
529 Buffer
, Length
, NULL
, NULL
);
533 Status
= STATUS_NO_MEMORY
;
538 Buffer
= (PCHAR
)WriteConsoleRequest
->Buffer
;
543 if (NT_SUCCESS(Status
))
545 Status
= ConioWriteConsole(Console
, Buff
, Buffer
,
546 WriteConsoleRequest
->NrCharactersToWrite
, TRUE
);
547 if (NT_SUCCESS(Status
))
549 Written
= WriteConsoleRequest
->NrCharactersToWrite
;
552 if (WriteConsoleRequest
->Unicode
)
554 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
558 WriteConsoleRequest
->NrCharactersWritten
= Written
;
561 ConioReleaseScreenBuffer(Buff
, FALSE
);
566 /* PUBLIC APIS ****************************************************************/
568 CSR_API(SrvReadConsoleOutput
)
570 PCONSOLE_READOUTPUT ReadOutputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadOutputRequest
;
571 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
573 PCHAR_INFO CurCharInfo
;
574 PCONSOLE_SCREEN_BUFFER Buff
;
579 SMALL_RECT ReadRegion
;
580 SMALL_RECT ScreenRect
;
586 DPRINT("SrvReadConsoleOutput\n");
588 CharInfo
= ReadOutputRequest
->CharInfo
;
589 ReadRegion
= ReadOutputRequest
->ReadRegion
;
590 BufferSize
= ReadOutputRequest
->BufferSize
;
591 BufferCoord
= ReadOutputRequest
->BufferCoord
;
593 if (!CsrValidateMessageBuffer(ApiMessage
,
594 (PVOID
*)&ReadOutputRequest
->CharInfo
,
595 BufferSize
.X
* BufferSize
.Y
,
598 return STATUS_INVALID_PARAMETER
;
601 Status
= ConioGetScreenBuffer(ProcessData
, ReadOutputRequest
->OutputHandle
, &Buff
, GENERIC_READ
, TRUE
);
602 if (!NT_SUCCESS(Status
)) return Status
;
604 /* FIXME: Is this correct? */
605 CodePage
= ProcessData
->Console
->OutputCodePage
;
607 SizeY
= min(BufferSize
.Y
- BufferCoord
.Y
, ConioRectHeight(&ReadRegion
));
608 SizeX
= min(BufferSize
.X
- BufferCoord
.X
, ConioRectWidth(&ReadRegion
));
609 ReadRegion
.Bottom
= ReadRegion
.Top
+ SizeY
;
610 ReadRegion
.Right
= ReadRegion
.Left
+ SizeX
;
612 ConioInitRect(&ScreenRect
, 0, 0, Buff
->MaxY
, Buff
->MaxX
);
613 if (!ConioGetIntersection(&ReadRegion
, &ScreenRect
, &ReadRegion
))
615 ConioReleaseScreenBuffer(Buff
, TRUE
);
616 return STATUS_SUCCESS
;
619 for (i
= 0, Y
= ReadRegion
.Top
; Y
< ReadRegion
.Bottom
; ++i
, ++Y
)
621 CurCharInfo
= CharInfo
+ (i
* BufferSize
.X
);
623 Ptr
= ConioCoordToPointer(Buff
, ReadRegion
.Left
, Y
);
624 for (X
= ReadRegion
.Left
; X
< ReadRegion
.Right
; ++X
)
626 if (ReadOutputRequest
->Unicode
)
628 // ConsoleAnsiCharToUnicodeChar(ProcessData->Console, (PCHAR)Ptr++, &CurCharInfo->Char.UnicodeChar);
629 MultiByteToWideChar(CodePage
, 0,
631 &CurCharInfo
->Char
.UnicodeChar
, 1);
635 CurCharInfo
->Char
.AsciiChar
= *Ptr
++;
637 CurCharInfo
->Attributes
= *Ptr
++;
642 ConioReleaseScreenBuffer(Buff
, TRUE
);
644 ReadOutputRequest
->ReadRegion
.Right
= ReadRegion
.Left
+ SizeX
- 1;
645 ReadOutputRequest
->ReadRegion
.Bottom
= ReadRegion
.Top
+ SizeY
- 1;
646 ReadOutputRequest
->ReadRegion
.Left
= ReadRegion
.Left
;
647 ReadOutputRequest
->ReadRegion
.Top
= ReadRegion
.Top
;
649 return STATUS_SUCCESS
;
652 CSR_API(SrvWriteConsole
)
655 PCONSOLE_WRITECONSOLE WriteConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteConsoleRequest
;
657 DPRINT("SrvWriteConsole\n");
659 if (!CsrValidateMessageBuffer(ApiMessage
,
660 (PVOID
)&WriteConsoleRequest
->Buffer
,
661 WriteConsoleRequest
->BufferSize
,
664 return STATUS_INVALID_PARAMETER
;
667 Status
= DoWriteConsole(ApiMessage
,
668 CsrGetClientThread(),
671 if (Status
== STATUS_PENDING
)
672 *ReplyCode
= CsrReplyPending
;
677 CSR_API(SrvWriteConsoleOutput
)
679 PCONSOLE_WRITEOUTPUT WriteOutputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteOutputRequest
;
680 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
681 SHORT i
, X
, Y
, SizeX
, SizeY
;
683 PCONSOLE_SCREEN_BUFFER Buff
;
684 SMALL_RECT ScreenBuffer
;
685 CHAR_INFO
* CurCharInfo
;
686 SMALL_RECT WriteRegion
;
693 DPRINT("SrvWriteConsoleOutput\n");
695 BufferSize
= WriteOutputRequest
->BufferSize
;
696 BufferCoord
= WriteOutputRequest
->BufferCoord
;
697 CharInfo
= WriteOutputRequest
->CharInfo
;
699 if (!CsrValidateMessageBuffer(ApiMessage
,
700 (PVOID
*)&WriteOutputRequest
->CharInfo
,
701 BufferSize
.X
* BufferSize
.Y
,
704 return STATUS_INVALID_PARAMETER
;
707 Status
= ConioGetScreenBuffer(ProcessData
,
708 WriteOutputRequest
->OutputHandle
,
712 if (!NT_SUCCESS(Status
)) return Status
;
714 Console
= Buff
->Header
.Console
;
716 WriteRegion
= WriteOutputRequest
->WriteRegion
;
718 SizeY
= min(BufferSize
.Y
- BufferCoord
.Y
, ConioRectHeight(&WriteRegion
));
719 SizeX
= min(BufferSize
.X
- BufferCoord
.X
, ConioRectWidth(&WriteRegion
));
720 WriteRegion
.Bottom
= WriteRegion
.Top
+ SizeY
- 1;
721 WriteRegion
.Right
= WriteRegion
.Left
+ SizeX
- 1;
723 /* Make sure WriteRegion is inside the screen buffer */
724 ConioInitRect(&ScreenBuffer
, 0, 0, Buff
->MaxY
- 1, Buff
->MaxX
- 1);
725 if (!ConioGetIntersection(&WriteRegion
, &ScreenBuffer
, &WriteRegion
))
727 ConioReleaseScreenBuffer(Buff
, TRUE
);
729 /* It is okay to have a WriteRegion completely outside the screen buffer.
730 No data is written then. */
731 return STATUS_SUCCESS
;
734 for (i
= 0, Y
= WriteRegion
.Top
; Y
<= WriteRegion
.Bottom
; i
++, Y
++)
736 CurCharInfo
= CharInfo
+ (i
+ BufferCoord
.Y
) * BufferSize
.X
+ BufferCoord
.X
;
737 Ptr
= ConioCoordToPointer(Buff
, WriteRegion
.Left
, Y
);
738 for (X
= WriteRegion
.Left
; X
<= WriteRegion
.Right
; X
++)
741 if (WriteOutputRequest
->Unicode
)
743 ConsoleUnicodeCharToAnsiChar(Console
, &AsciiChar
, &CurCharInfo
->Char
.UnicodeChar
);
747 AsciiChar
= CurCharInfo
->Char
.AsciiChar
;
750 *Ptr
++ = CurCharInfo
->Attributes
;
755 ConioDrawRegion(Console
, &WriteRegion
);
757 ConioReleaseScreenBuffer(Buff
, TRUE
);
759 WriteOutputRequest
->WriteRegion
.Right
= WriteRegion
.Left
+ SizeX
- 1;
760 WriteOutputRequest
->WriteRegion
.Bottom
= WriteRegion
.Top
+ SizeY
- 1;
761 WriteOutputRequest
->WriteRegion
.Left
= WriteRegion
.Left
;
762 WriteOutputRequest
->WriteRegion
.Top
= WriteRegion
.Top
;
764 return STATUS_SUCCESS
;
767 CSR_API(SrvReadConsoleOutputString
)
770 PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadOutputCodeRequest
;
772 PCONSOLE_SCREEN_BUFFER Buff
;
780 DPRINT("SrvReadConsoleOutputString\n");
782 CodeType
= ReadOutputCodeRequest
->CodeType
;
786 CodeSize
= sizeof(CHAR
);
790 CodeSize
= sizeof(WCHAR
);
794 CodeSize
= sizeof(WORD
);
798 return STATUS_INVALID_PARAMETER
;
801 if (!CsrValidateMessageBuffer(ApiMessage
,
802 (PVOID
*)&ReadOutputCodeRequest
->pCode
.pCode
,
803 ReadOutputCodeRequest
->NumCodesToRead
,
806 return STATUS_INVALID_PARAMETER
;
809 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), ReadOutputCodeRequest
->OutputHandle
, &Buff
, GENERIC_READ
, TRUE
);
810 if (!NT_SUCCESS(Status
)) return Status
;
812 Console
= Buff
->Header
.Console
;
814 ReadBuffer
= ReadOutputCodeRequest
->pCode
.pCode
;
815 Xpos
= ReadOutputCodeRequest
->ReadCoord
.X
;
816 Ypos
= (ReadOutputCodeRequest
->ReadCoord
.Y
+ Buff
->VirtualY
) % Buff
->MaxY
;
819 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
821 * If the number of attributes (resp. characters) to be read from extends
822 * beyond the end of the specified screen buffer row, attributes (resp.
823 * characters) are read from the next row. If the number of attributes
824 * (resp. characters) to be read from extends beyond the end of the console
825 * screen buffer, attributes (resp. characters) up to the end of the console
826 * screen buffer are read.
828 * TODO: Do NOT loop up to NumCodesToRead, but stop before
829 * if we are going to overflow...
831 for (i
= 0; i
< ReadOutputCodeRequest
->NumCodesToRead
; ++i
)
833 Code
= Buff
->Buffer
[2 * (Xpos
+ Ypos
* Buff
->MaxX
) + (CodeType
== CODE_ATTRIBUTE
? 1 : 0)];
838 ConsoleAnsiCharToUnicodeChar(Console
, (PWCHAR
)ReadBuffer
, (PCHAR
)&Code
);
842 *(PCHAR
)ReadBuffer
= (CHAR
)Code
;
846 *(PWORD
)ReadBuffer
= (WORD
)Code
;
849 ReadBuffer
= (PVOID
)((ULONG_PTR
)ReadBuffer
+ CodeSize
);
853 if (Xpos
== Buff
->MaxX
)
858 if (Ypos
== Buff
->MaxY
)
868 *(PWCHAR
)ReadBuffer
= 0;
872 *(PCHAR
)ReadBuffer
= 0;
876 *(PWORD
)ReadBuffer
= 0;
880 ReadOutputCodeRequest
->EndCoord
.X
= Xpos
;
881 ReadOutputCodeRequest
->EndCoord
.Y
= (Ypos
- Buff
->VirtualY
+ Buff
->MaxY
) % Buff
->MaxY
;
883 ConioReleaseScreenBuffer(Buff
, TRUE
);
885 ReadOutputCodeRequest
->CodesRead
= (DWORD
)((ULONG_PTR
)ReadBuffer
- (ULONG_PTR
)ReadOutputCodeRequest
->pCode
.pCode
) / CodeSize
;
886 // <= ReadOutputCodeRequest->NumCodesToRead
888 return STATUS_SUCCESS
;
891 CSR_API(SrvWriteConsoleOutputString
)
894 PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteOutputCodeRequest
;
896 PCONSOLE_SCREEN_BUFFER Buff
;
898 PBYTE Buffer
; // PUCHAR
899 PCHAR String
, tmpString
= NULL
;
900 DWORD X
, Y
, Length
; // , Written = 0;
902 SMALL_RECT UpdateRect
;
904 DPRINT("SrvWriteConsoleOutputString\n");
906 CodeType
= WriteOutputCodeRequest
->CodeType
;
910 CodeSize
= sizeof(CHAR
);
914 CodeSize
= sizeof(WCHAR
);
918 CodeSize
= sizeof(WORD
);
922 return STATUS_INVALID_PARAMETER
;
925 if (!CsrValidateMessageBuffer(ApiMessage
,
926 (PVOID
*)&WriteOutputCodeRequest
->pCode
.pCode
,
927 WriteOutputCodeRequest
->Length
,
930 return STATUS_INVALID_PARAMETER
;
933 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
934 WriteOutputCodeRequest
->OutputHandle
,
938 if (!NT_SUCCESS(Status
)) return Status
;
940 Console
= Buff
->Header
.Console
;
946 Length
= WideCharToMultiByte(Console
->OutputCodePage
, 0,
947 (PWCHAR
)WriteOutputCodeRequest
->pCode
.UnicodeChar
,
948 WriteOutputCodeRequest
->Length
,
949 NULL
, 0, NULL
, NULL
);
950 tmpString
= String
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
);
953 WideCharToMultiByte(Console
->OutputCodePage
, 0,
954 (PWCHAR
)WriteOutputCodeRequest
->pCode
.UnicodeChar
,
955 WriteOutputCodeRequest
->Length
,
956 String
, Length
, NULL
, NULL
);
960 Status
= STATUS_NO_MEMORY
;
967 String
= (PCHAR
)WriteOutputCodeRequest
->pCode
.AsciiChar
;
972 // *(ReadBuffer++) = Code;
973 String
= (PCHAR
)WriteOutputCodeRequest
->pCode
.Attribute
;
977 if (String
&& NT_SUCCESS(Status
))
979 X
= WriteOutputCodeRequest
->Coord
.X
;
980 Y
= (WriteOutputCodeRequest
->Coord
.Y
+ Buff
->VirtualY
) % Buff
->MaxY
;
981 Length
= WriteOutputCodeRequest
->Length
;
982 Buffer
= &Buff
->Buffer
[2 * (Y
* Buff
->MaxX
+ X
) + (CodeType
== CODE_ATTRIBUTE
? 1 : 0)];
987 // ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
988 String
= (PCHAR
)((ULONG_PTR
)String
+ CodeSize
);
991 if (++X
== Buff
->MaxX
)
993 if (++Y
== Buff
->MaxY
)
996 Buffer
= Buff
->Buffer
+ (CodeType
== CODE_ATTRIBUTE
? 1 : 0);
1002 if (Buff
== Console
->ActiveBuffer
)
1004 ConioComputeUpdateRect(Buff
, &UpdateRect
, &WriteOutputCodeRequest
->Coord
,
1005 WriteOutputCodeRequest
->Length
);
1006 ConioDrawRegion(Console
, &UpdateRect
);
1009 WriteOutputCodeRequest
->EndCoord
.X
= X
;
1010 WriteOutputCodeRequest
->EndCoord
.Y
= (Y
+ Buff
->MaxY
- Buff
->VirtualY
) % Buff
->MaxY
;
1015 RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString
);
1018 ConioReleaseScreenBuffer(Buff
, TRUE
);
1020 // WriteOutputCodeRequest->NrCharactersWritten = Written;
1024 CSR_API(SrvFillConsoleOutput
)
1027 PCONSOLE_FILLOUTPUTCODE FillOutputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.FillOutputRequest
;
1029 PCONSOLE_SCREEN_BUFFER Buff
;
1030 DWORD X
, Y
, Length
; // , Written = 0;
1034 SMALL_RECT UpdateRect
;
1036 DPRINT("SrvFillConsoleOutput\n");
1038 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), FillOutputRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1039 if (!NT_SUCCESS(Status
)) return Status
;
1041 Console
= Buff
->Header
.Console
;
1043 CodeType
= FillOutputRequest
->CodeType
;
1045 X
= FillOutputRequest
->Coord
.X
;
1046 Y
= (FillOutputRequest
->Coord
.Y
+ Buff
->VirtualY
) % Buff
->MaxY
;
1047 Length
= FillOutputRequest
->Length
;
1048 Buffer
= &Buff
->Buffer
[2 * (Y
* Buff
->MaxX
+ X
) + (CodeType
== CODE_ATTRIBUTE
? 1 : 0)];
1053 Code
= (BYTE
)FillOutputRequest
->Code
.AsciiChar
;
1057 ConsoleUnicodeCharToAnsiChar(Console
, (PCHAR
)&Code
, &FillOutputRequest
->Code
.UnicodeChar
);
1060 case CODE_ATTRIBUTE
:
1061 Code
= (BYTE
)FillOutputRequest
->Code
.Attribute
;
1065 ConioReleaseScreenBuffer(Buff
, TRUE
);
1066 return STATUS_INVALID_PARAMETER
;
1074 if (++X
== Buff
->MaxX
)
1076 if (++Y
== Buff
->MaxY
)
1079 Buffer
= Buff
->Buffer
+ (CodeType
== CODE_ATTRIBUTE
? 1 : 0);
1085 if (Buff
== Console
->ActiveBuffer
)
1087 ConioComputeUpdateRect(Buff
, &UpdateRect
, &FillOutputRequest
->Coord
,
1088 FillOutputRequest
->Length
);
1089 ConioDrawRegion(Console
, &UpdateRect
);
1092 ConioReleaseScreenBuffer(Buff
, TRUE
);
1094 Length = FillOutputRequest->Length;
1095 FillOutputRequest->NrCharactersWritten = Length;
1097 return STATUS_SUCCESS
;
1100 CSR_API(SrvGetConsoleCursorInfo
)
1103 PCONSOLE_GETSETCURSORINFO CursorInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.CursorInfoRequest
;
1104 PCONSOLE_SCREEN_BUFFER Buff
;
1106 DPRINT("SrvGetConsoleCursorInfo\n");
1108 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), CursorInfoRequest
->OutputHandle
, &Buff
, GENERIC_READ
, TRUE
);
1109 if (!NT_SUCCESS(Status
)) return Status
;
1111 CursorInfoRequest
->Info
.bVisible
= Buff
->CursorInfo
.bVisible
;
1112 CursorInfoRequest
->Info
.dwSize
= Buff
->CursorInfo
.dwSize
;
1113 ConioReleaseScreenBuffer(Buff
, TRUE
);
1115 return STATUS_SUCCESS
;
1118 CSR_API(SrvSetConsoleCursorInfo
)
1121 PCONSOLE_GETSETCURSORINFO CursorInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.CursorInfoRequest
;
1123 PCONSOLE_SCREEN_BUFFER Buff
;
1127 DPRINT("SrvSetConsoleCursorInfo\n");
1129 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), CursorInfoRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1130 if (!NT_SUCCESS(Status
)) return Status
;
1132 Console
= Buff
->Header
.Console
;
1134 Size
= CursorInfoRequest
->Info
.dwSize
;
1135 Visible
= CursorInfoRequest
->Info
.bVisible
;
1145 if ( (Size
!= Buff
->CursorInfo
.dwSize
) ||
1146 (Visible
&& ! Buff
->CursorInfo
.bVisible
) ||
1147 (! Visible
&& Buff
->CursorInfo
.bVisible
) )
1149 Buff
->CursorInfo
.dwSize
= Size
;
1150 Buff
->CursorInfo
.bVisible
= Visible
;
1152 if (!ConioSetCursorInfo(Console
, Buff
))
1154 ConioReleaseScreenBuffer(Buff
, TRUE
);
1155 return STATUS_UNSUCCESSFUL
;
1159 ConioReleaseScreenBuffer(Buff
, TRUE
);
1161 return STATUS_SUCCESS
;
1164 CSR_API(SrvSetConsoleCursorPosition
)
1167 PCONSOLE_SETCURSORPOSITION SetCursorPositionRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetCursorPositionRequest
;
1169 PCONSOLE_SCREEN_BUFFER Buff
;
1170 LONG OldCursorX
, OldCursorY
;
1171 LONG NewCursorX
, NewCursorY
;
1173 DPRINT("SrvSetConsoleCursorPosition\n");
1175 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), SetCursorPositionRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1176 if (!NT_SUCCESS(Status
)) return Status
;
1178 Console
= Buff
->Header
.Console
;
1180 NewCursorX
= SetCursorPositionRequest
->Position
.X
;
1181 NewCursorY
= SetCursorPositionRequest
->Position
.Y
;
1182 if ( NewCursorX
< 0 || NewCursorX
>= Buff
->MaxX
||
1183 NewCursorY
< 0 || NewCursorY
>= Buff
->MaxY
)
1185 ConioReleaseScreenBuffer(Buff
, TRUE
);
1186 return STATUS_INVALID_PARAMETER
;
1188 OldCursorX
= Buff
->CurrentX
;
1189 OldCursorY
= Buff
->CurrentY
;
1190 Buff
->CurrentX
= NewCursorX
;
1191 Buff
->CurrentY
= NewCursorY
;
1192 if (Buff
== Console
->ActiveBuffer
)
1194 if (!ConioSetScreenInfo(Console
, Buff
, OldCursorX
, OldCursorY
))
1196 ConioReleaseScreenBuffer(Buff
, TRUE
);
1197 return STATUS_UNSUCCESSFUL
;
1201 ConioReleaseScreenBuffer(Buff
, TRUE
);
1203 return STATUS_SUCCESS
;
1206 CSR_API(SrvSetConsoleTextAttribute
)
1209 PCONSOLE_SETTEXTATTRIB SetTextAttribRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetTextAttribRequest
;
1211 PCONSOLE_SCREEN_BUFFER Buff
;
1213 DPRINT("SrvSetConsoleTextAttribute\n");
1215 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), SetTextAttribRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1216 if (!NT_SUCCESS(Status
)) return Status
;
1218 Console
= Buff
->Header
.Console
;
1220 Buff
->DefaultAttrib
= SetTextAttribRequest
->Attrib
;
1221 if (Buff
== Console
->ActiveBuffer
)
1223 if (!ConioUpdateScreenInfo(Console
, Buff
))
1225 ConioReleaseScreenBuffer(Buff
, TRUE
);
1226 return STATUS_UNSUCCESSFUL
;
1230 ConioReleaseScreenBuffer(Buff
, TRUE
);
1232 return STATUS_SUCCESS
;
1235 CSR_API(SrvCreateConsoleScreenBuffer
)
1238 PCONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.CreateScreenBufferRequest
;
1239 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
1241 PCONSOLE_SCREEN_BUFFER Buff
;
1243 DPRINT("SrvCreateConsoleScreenBuffer\n");
1245 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
1247 Status
= ConioGetConsole(ProcessData
, &Console
, TRUE
);
1248 if (!NT_SUCCESS(Status
))
1250 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
1254 Buff
= RtlAllocateHeap(ConSrvHeap
, HEAP_ZERO_MEMORY
, sizeof(CONSOLE_SCREEN_BUFFER
));
1257 if (Console
->ActiveBuffer
)
1259 Buff
->MaxX
= Console
->ActiveBuffer
->MaxX
;
1260 Buff
->MaxY
= Console
->ActiveBuffer
->MaxY
;
1261 Buff
->CursorInfo
.bVisible
= Console
->ActiveBuffer
->CursorInfo
.bVisible
;
1262 Buff
->CursorInfo
.dwSize
= Console
->ActiveBuffer
->CursorInfo
.dwSize
;
1266 Buff
->CursorInfo
.bVisible
= TRUE
;
1267 Buff
->CursorInfo
.dwSize
= CSR_DEFAULT_CURSOR_SIZE
;
1270 if (Buff
->MaxX
== 0)
1275 if (Buff
->MaxY
== 0)
1280 Status
= CsrInitConsoleScreenBuffer(Console
, Buff
);
1281 if (NT_SUCCESS(Status
))
1283 Status
= Win32CsrInsertObject(ProcessData
,
1284 &CreateScreenBufferRequest
->OutputHandle
,
1286 CreateScreenBufferRequest
->Access
,
1287 CreateScreenBufferRequest
->Inheritable
,
1288 CreateScreenBufferRequest
->ShareMode
);
1293 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1296 ConioReleaseConsole(Console
, TRUE
);
1298 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
1303 CSR_API(SrvGetConsoleScreenBufferInfo
)
1306 PCONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ScreenBufferInfoRequest
;
1308 PCONSOLE_SCREEN_BUFFER Buff
;
1309 PCONSOLE_SCREEN_BUFFER_INFO pInfo
= &ScreenBufferInfoRequest
->Info
;
1311 DPRINT("SrvGetConsoleScreenBufferInfo\n");
1313 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), ScreenBufferInfoRequest
->OutputHandle
, &Buff
, GENERIC_READ
, TRUE
);
1314 if (!NT_SUCCESS(Status
)) return Status
;
1316 Console
= Buff
->Header
.Console
;
1318 pInfo
->dwSize
.X
= Buff
->MaxX
;
1319 pInfo
->dwSize
.Y
= Buff
->MaxY
;
1320 pInfo
->dwCursorPosition
.X
= Buff
->CurrentX
;
1321 pInfo
->dwCursorPosition
.Y
= Buff
->CurrentY
;
1322 pInfo
->wAttributes
= Buff
->DefaultAttrib
;
1323 pInfo
->srWindow
.Left
= Buff
->ShowX
;
1324 pInfo
->srWindow
.Right
= Buff
->ShowX
+ Console
->Size
.X
- 1;
1325 pInfo
->srWindow
.Top
= Buff
->ShowY
;
1326 pInfo
->srWindow
.Bottom
= Buff
->ShowY
+ Console
->Size
.Y
- 1;
1327 pInfo
->dwMaximumWindowSize
.X
= Buff
->MaxX
;
1328 pInfo
->dwMaximumWindowSize
.Y
= Buff
->MaxY
;
1330 ConioReleaseScreenBuffer(Buff
, TRUE
);
1332 return STATUS_SUCCESS
;
1335 CSR_API(SrvSetConsoleActiveScreenBuffer
)
1338 PCONSOLE_SETACTIVESCREENBUFFER SetScreenBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetScreenBufferRequest
;
1340 PCONSOLE_SCREEN_BUFFER Buff
;
1342 DPRINT("SrvSetConsoleActiveScreenBuffer\n");
1344 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), SetScreenBufferRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1345 if (!NT_SUCCESS(Status
)) return Status
;
1347 Console
= Buff
->Header
.Console
;
1349 if (Buff
== Console
->ActiveBuffer
)
1351 ConioReleaseScreenBuffer(Buff
, TRUE
);
1352 return STATUS_SUCCESS
;
1355 /* If old buffer has no handles, it's now unreferenced */
1356 if (Console
->ActiveBuffer
->Header
.HandleCount
== 0)
1358 ConioDeleteScreenBuffer(Console
->ActiveBuffer
);
1361 /* Tie console to new buffer */
1362 Console
->ActiveBuffer
= Buff
;
1364 /* Redraw the console */
1365 ConioDrawConsole(Console
);
1367 ConioReleaseScreenBuffer(Buff
, TRUE
);
1369 return STATUS_SUCCESS
;
1372 CSR_API(SrvScrollConsoleScreenBuffer
)
1374 PCONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ScrollScreenBufferRequest
;
1376 PCONSOLE_SCREEN_BUFFER Buff
;
1377 SMALL_RECT ScreenBuffer
;
1378 SMALL_RECT SrcRegion
;
1379 SMALL_RECT DstRegion
;
1380 SMALL_RECT UpdateRegion
;
1381 SMALL_RECT ScrollRectangle
;
1382 SMALL_RECT ClipRectangle
;
1384 HANDLE OutputHandle
;
1385 BOOLEAN UseClipRectangle
;
1386 COORD DestinationOrigin
;
1390 DPRINT("SrvScrollConsoleScreenBuffer\n");
1392 OutputHandle
= ScrollScreenBufferRequest
->OutputHandle
;
1393 UseClipRectangle
= ScrollScreenBufferRequest
->UseClipRectangle
;
1394 DestinationOrigin
= ScrollScreenBufferRequest
->DestinationOrigin
;
1395 Fill
= ScrollScreenBufferRequest
->Fill
;
1397 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1398 if (!NT_SUCCESS(Status
)) return Status
;
1400 Console
= Buff
->Header
.Console
;
1402 ScrollRectangle
= ScrollScreenBufferRequest
->ScrollRectangle
;
1404 /* Make sure source rectangle is inside the screen buffer */
1405 ConioInitRect(&ScreenBuffer
, 0, 0, Buff
->MaxY
- 1, Buff
->MaxX
- 1);
1406 if (!ConioGetIntersection(&SrcRegion
, &ScreenBuffer
, &ScrollRectangle
))
1408 ConioReleaseScreenBuffer(Buff
, TRUE
);
1409 return STATUS_SUCCESS
;
1412 /* If the source was clipped on the left or top, adjust the destination accordingly */
1413 if (ScrollRectangle
.Left
< 0)
1415 DestinationOrigin
.X
-= ScrollRectangle
.Left
;
1417 if (ScrollRectangle
.Top
< 0)
1419 DestinationOrigin
.Y
-= ScrollRectangle
.Top
;
1422 if (UseClipRectangle
)
1424 ClipRectangle
= ScrollScreenBufferRequest
->ClipRectangle
;
1425 if (!ConioGetIntersection(&ClipRectangle
, &ClipRectangle
, &ScreenBuffer
))
1427 ConioReleaseScreenBuffer(Buff
, TRUE
);
1428 return STATUS_SUCCESS
;
1433 ClipRectangle
= ScreenBuffer
;
1436 ConioInitRect(&DstRegion
,
1437 DestinationOrigin
.Y
,
1438 DestinationOrigin
.X
,
1439 DestinationOrigin
.Y
+ ConioRectHeight(&SrcRegion
) - 1,
1440 DestinationOrigin
.X
+ ConioRectWidth(&SrcRegion
) - 1);
1442 if (ScrollScreenBufferRequest
->Unicode
)
1443 ConsoleUnicodeCharToAnsiChar(Console
, &FillChar
, &Fill
.Char
.UnicodeChar
);
1445 FillChar
= Fill
.Char
.AsciiChar
;
1447 ConioMoveRegion(Buff
, &SrcRegion
, &DstRegion
, &ClipRectangle
, Fill
.Attributes
<< 8 | (BYTE
)FillChar
);
1449 if (Buff
== Console
->ActiveBuffer
)
1451 ConioGetUnion(&UpdateRegion
, &SrcRegion
, &DstRegion
);
1452 if (ConioGetIntersection(&UpdateRegion
, &UpdateRegion
, &ClipRectangle
))
1454 /* Draw update region */
1455 ConioDrawRegion(Console
, &UpdateRegion
);
1459 ConioReleaseScreenBuffer(Buff
, TRUE
);
1461 return STATUS_SUCCESS
;
1464 CSR_API(SrvSetConsoleScreenBufferSize
)
1467 PCONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetScreenBufferSizeRequest
;
1468 PCONSOLE_SCREEN_BUFFER Buff
;
1470 Status
= ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), SetScreenBufferSizeRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1471 if (!NT_SUCCESS(Status
)) return Status
;
1473 Status
= ConioResizeBuffer(Buff
->Header
.Console
, Buff
, SetScreenBufferSizeRequest
->Size
);
1474 ConioReleaseScreenBuffer(Buff
, TRUE
);