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 Output functions
6 * PROGRAMMERS: Jeffrey Morlan
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *******************************************************************/
14 #include "include/conio.h"
16 #include "conoutput.h"
23 // Define wmemset(...)
29 /* GLOBALS ********************************************************************/
33 #define ConioInitRect(Rect, top, left, bottom, right) \
35 ((Rect)->Top) = top; \
36 ((Rect)->Left) = left; \
37 ((Rect)->Bottom) = bottom; \
38 ((Rect)->Right) = right; \
41 #define ConioIsRectEmpty(Rect) \
42 (((Rect)->Left > (Rect)->Right) || ((Rect)->Top > (Rect)->Bottom))
44 #define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \
45 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
47 #define ConsoleAnsiCharToUnicodeChar(Console, dWChar, sChar) \
48 MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1)
51 /* PRIVATE FUNCTIONS **********************************************************/
54 ConioCoordToPointer(PCONSOLE_SCREEN_BUFFER Buff
, ULONG X
, ULONG Y
)
56 return &Buff
->Buffer
[2 * (((Y
+ Buff
->VirtualY
) % Buff
->ScreenBufferSize
.Y
) * Buff
->ScreenBufferSize
.X
+ X
)];
60 ClearLineBuffer(PCONSOLE_SCREEN_BUFFER Buff
)
62 PBYTE Ptr
= ConioCoordToPointer(Buff
, 0, Buff
->CursorPosition
.Y
);
65 for (Pos
= 0; Pos
< Buff
->ScreenBufferSize
.X
; Pos
++)
69 *Ptr
++ = Buff
->ScreenDefaultAttrib
;
74 ConSrvCreateScreenBuffer(IN OUT PCONSOLE Console
,
75 OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
76 IN COORD ScreenBufferSize
,
77 IN USHORT ScreenAttrib
,
78 IN USHORT PopupAttrib
,
80 IN BOOLEAN IsCursorVisible
,
83 if (Console
== NULL
|| Buffer
== NULL
)
84 return STATUS_INVALID_PARAMETER
;
86 *Buffer
= RtlAllocateHeap(ConSrvHeap
, HEAP_ZERO_MEMORY
, sizeof(CONSOLE_SCREEN_BUFFER
));
89 return STATUS_INSUFFICIENT_RESOURCES
;
92 (*Buffer
)->Header
.Type
= SCREEN_BUFFER
;
93 (*Buffer
)->Header
.Console
= Console
;
94 (*Buffer
)->Header
.HandleCount
= 0;
95 (*Buffer
)->ScreenBufferSize
= ScreenBufferSize
;
97 (*Buffer
)->Buffer
= RtlAllocateHeap(ConSrvHeap
, HEAP_ZERO_MEMORY
, (*Buffer
)->ScreenBufferSize
.X
* (*Buffer
)->ScreenBufferSize
.Y
* 2);
98 if (NULL
== (*Buffer
)->Buffer
)
100 RtlFreeHeap(ConSrvHeap
, 0, *Buffer
);
101 return STATUS_INSUFFICIENT_RESOURCES
;
104 (*Buffer
)->ShowX
= 0;
105 (*Buffer
)->ShowY
= 0;
106 (*Buffer
)->VirtualY
= 0;
108 (*Buffer
)->CursorInfo
.bVisible
= (IsCursorVisible
&& (CursorSize
!= 0));
109 (*Buffer
)->CursorInfo
.dwSize
= min(max(CursorSize
, 0), 100);
111 (*Buffer
)->ScreenDefaultAttrib
= ScreenAttrib
;
112 (*Buffer
)->PopupDefaultAttrib
= PopupAttrib
;
113 /* initialize buffer to be empty with default attributes */
114 for ((*Buffer
)->CursorPosition
.Y
= 0 ; (*Buffer
)->CursorPosition
.Y
< (*Buffer
)->ScreenBufferSize
.Y
; (*Buffer
)->CursorPosition
.Y
++)
116 ClearLineBuffer(*Buffer
);
118 (*Buffer
)->CursorPosition
.X
= 0;
119 (*Buffer
)->CursorPosition
.Y
= 0;
121 (*Buffer
)->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
122 (*Buffer
)->DisplayMode
= DisplayMode
;
124 InsertHeadList(&Console
->BufferList
, &(*Buffer
)->ListEntry
);
125 return STATUS_SUCCESS
;
129 ConioNextLine(PCONSOLE_SCREEN_BUFFER Buff
, SMALL_RECT
* UpdateRect
, UINT
*ScrolledLines
)
131 /* If we hit bottom, slide the viewable screen */
132 if (++Buff
->CursorPosition
.Y
== Buff
->ScreenBufferSize
.Y
)
134 Buff
->CursorPosition
.Y
--;
135 if (++Buff
->VirtualY
== Buff
->ScreenBufferSize
.Y
)
140 ClearLineBuffer(Buff
);
141 if (UpdateRect
->Top
!= 0)
146 UpdateRect
->Left
= 0;
147 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
148 UpdateRect
->Bottom
= Buff
->CursorPosition
.Y
;
152 ConioWriteConsole(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER Buff
,
153 CHAR
*Buffer
, DWORD Length
, BOOL Attrib
)
157 SMALL_RECT UpdateRect
;
158 LONG CursorStartX
, CursorStartY
;
161 CursorStartX
= Buff
->CursorPosition
.X
;
162 CursorStartY
= Buff
->CursorPosition
.Y
;
163 UpdateRect
.Left
= Buff
->ScreenBufferSize
.X
;
164 UpdateRect
.Top
= Buff
->CursorPosition
.Y
;
165 UpdateRect
.Right
= -1;
166 UpdateRect
.Bottom
= Buff
->CursorPosition
.Y
;
169 for (i
= 0; i
< Length
; i
++)
172 * If we are in processed mode, interpret special characters and
173 * display them correctly. Otherwise, just put them into the buffer.
175 if (Buff
->Mode
& ENABLE_PROCESSED_OUTPUT
)
178 if (Buffer
[i
] == '\r')
180 Buff
->CursorPosition
.X
= 0;
181 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
)Buff
->CursorPosition
.X
);
182 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
)Buff
->CursorPosition
.X
);
186 else if (Buffer
[i
] == '\n')
188 Buff
->CursorPosition
.X
= 0;
189 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
193 else if (Buffer
[i
] == '\b')
195 /* Only handle BS if we're not on the first pos of the first line */
196 if (0 != Buff
->CursorPosition
.X
|| 0 != Buff
->CursorPosition
.Y
)
198 if (0 == Buff
->CursorPosition
.X
)
200 /* slide virtual position up */
201 Buff
->CursorPosition
.X
= Buff
->ScreenBufferSize
.X
- 1;
202 Buff
->CursorPosition
.Y
--;
203 UpdateRect
.Top
= min(UpdateRect
.Top
, (LONG
)Buff
->CursorPosition
.Y
);
207 Buff
->CursorPosition
.X
--;
209 Ptr
= ConioCoordToPointer(Buff
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
211 Ptr
[1] = Buff
->ScreenDefaultAttrib
;
212 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
)Buff
->CursorPosition
.X
);
213 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
)Buff
->CursorPosition
.X
);
218 else if (Buffer
[i
] == '\t')
222 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
)Buff
->CursorPosition
.X
);
223 EndX
= (Buff
->CursorPosition
.X
+ TAB_WIDTH
) & ~(TAB_WIDTH
- 1);
224 EndX
= min(EndX
, Buff
->ScreenBufferSize
.X
);
225 Ptr
= ConioCoordToPointer(Buff
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
226 while (Buff
->CursorPosition
.X
< EndX
)
229 *Ptr
++ = Buff
->ScreenDefaultAttrib
;
230 Buff
->CursorPosition
.X
++;
232 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
)Buff
->CursorPosition
.X
- 1);
233 if (Buff
->CursorPosition
.X
== Buff
->ScreenBufferSize
.X
)
235 if (Buff
->Mode
& ENABLE_WRAP_AT_EOL_OUTPUT
)
237 Buff
->CursorPosition
.X
= 0;
238 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
242 Buff
->CursorPosition
.X
--;
248 // else if (Buffer[i] == '\a')
250 // // FIXME: This MUST BE moved to the terminal emulator frontend!!
251 // DPRINT1("Bell\n");
252 // // SendNotifyMessage(Console->hWindow, PM_CONSOLE_BEEP, 0, 0);
256 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
)Buff
->CursorPosition
.X
);
257 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
)Buff
->CursorPosition
.X
);
258 Ptr
= ConioCoordToPointer(Buff
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
262 Ptr
[1] = Buff
->ScreenDefaultAttrib
;
264 Buff
->CursorPosition
.X
++;
265 if (Buff
->CursorPosition
.X
== Buff
->ScreenBufferSize
.X
)
267 if (Buff
->Mode
& ENABLE_WRAP_AT_EOL_OUTPUT
)
269 Buff
->CursorPosition
.X
= 0;
270 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
274 Buff
->CursorPosition
.X
= CursorStartX
;
279 if (!ConioIsRectEmpty(&UpdateRect
) && Buff
== Console
->ActiveBuffer
)
281 ConioWriteStream(Console
, &UpdateRect
, CursorStartX
, CursorStartY
, ScrolledLines
,
285 return STATUS_SUCCESS
;
288 __inline BOOLEAN
ConioGetIntersection(
289 SMALL_RECT
* Intersection
,
293 if (ConioIsRectEmpty(Rect1
) ||
294 (ConioIsRectEmpty(Rect2
)) ||
295 (Rect1
->Top
> Rect2
->Bottom
) ||
296 (Rect1
->Left
> Rect2
->Right
) ||
297 (Rect1
->Bottom
< Rect2
->Top
) ||
298 (Rect1
->Right
< Rect2
->Left
))
300 /* The rectangles do not intersect */
301 ConioInitRect(Intersection
, 0, -1, 0, -1);
305 ConioInitRect(Intersection
,
306 max(Rect1
->Top
, Rect2
->Top
),
307 max(Rect1
->Left
, Rect2
->Left
),
308 min(Rect1
->Bottom
, Rect2
->Bottom
),
309 min(Rect1
->Right
, Rect2
->Right
));
314 __inline BOOLEAN
ConioGetUnion(
319 if (ConioIsRectEmpty(Rect1
))
321 if (ConioIsRectEmpty(Rect2
))
323 ConioInitRect(Union
, 0, -1, 0, -1);
331 else if (ConioIsRectEmpty(Rect2
))
338 min(Rect1
->Top
, Rect2
->Top
),
339 min(Rect1
->Left
, Rect2
->Left
),
340 max(Rect1
->Bottom
, Rect2
->Bottom
),
341 max(Rect1
->Right
, Rect2
->Right
));
348 * Move from one rectangle to another. We must be careful about the order that
349 * this is done, to avoid overwriting parts of the source before they are moved.
352 ConioMoveRegion(PCONSOLE_SCREEN_BUFFER ScreenBuffer
,
353 SMALL_RECT
* SrcRegion
,
354 SMALL_RECT
* DstRegion
,
355 SMALL_RECT
* ClipRegion
,
358 int Width
= ConioRectWidth(SrcRegion
);
359 int Height
= ConioRectHeight(SrcRegion
);
370 /* Moving down: work from bottom up */
371 SY
= SrcRegion
->Bottom
;
372 DY
= DstRegion
->Bottom
;
375 for (i
= 0; i
< Height
; i
++)
377 PWORD SRow
= (PWORD
)ConioCoordToPointer(ScreenBuffer
, 0, SY
);
378 PWORD DRow
= (PWORD
)ConioCoordToPointer(ScreenBuffer
, 0, DY
);
380 SX
= SrcRegion
->Left
;
381 DX
= DstRegion
->Left
;
385 /* Moving right: work from right to left */
386 SX
= SrcRegion
->Right
;
387 DX
= DstRegion
->Right
;
390 for (j
= 0; j
< Width
; j
++)
392 WORD Cell
= SRow
[SX
];
393 if (SX
>= ClipRegion
->Left
&& SX
<= ClipRegion
->Right
394 && SY
>= ClipRegion
->Top
&& SY
<= ClipRegion
->Bottom
)
398 if (DX
>= ClipRegion
->Left
&& DX
<= ClipRegion
->Right
399 && DY
>= ClipRegion
->Top
&& DY
<= ClipRegion
->Bottom
)
412 ConioResizeBuffer(PCONSOLE Console
,
413 PCONSOLE_SCREEN_BUFFER ScreenBuffer
,
422 USHORT value
= MAKEWORD(' ', ScreenBuffer
->ScreenDefaultAttrib
);
428 /* Buffer size is not allowed to be smaller than window size */
429 if (Size
.X
< Console
->ConsoleSize
.X
|| Size
.Y
< Console
->ConsoleSize
.Y
)
430 return STATUS_INVALID_PARAMETER
;
432 if (Size
.X
== ScreenBuffer
->ScreenBufferSize
.X
&& Size
.Y
== ScreenBuffer
->ScreenBufferSize
.Y
)
434 // FIXME: Trigger a buffer resize event ??
435 return STATUS_SUCCESS
;
438 if (!ConioIsBufferResizeSupported(Console
)) return STATUS_NOT_SUPPORTED
;
440 Buffer
= RtlAllocateHeap(ConSrvHeap
, 0, Size
.X
* Size
.Y
* 2);
441 if (!Buffer
) return STATUS_NO_MEMORY
;
443 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer
->ScreenBufferSize
.X
, ScreenBuffer
->ScreenBufferSize
.Y
, Size
.X
, Size
.Y
);
444 OldBuffer
= ScreenBuffer
->Buffer
;
446 for (CurrentY
= 0; CurrentY
< ScreenBuffer
->ScreenBufferSize
.Y
&& CurrentY
< Size
.Y
; CurrentY
++)
448 OldPtr
= ConioCoordToPointer(ScreenBuffer
, 0, CurrentY
);
449 if (Size
.X
<= ScreenBuffer
->ScreenBufferSize
.X
)
452 RtlCopyMemory(&Buffer
[Offset
], OldPtr
, Size
.X
* 2);
453 Offset
+= (Size
.X
* 2);
458 RtlCopyMemory(&Buffer
[Offset
], OldPtr
, ScreenBuffer
->ScreenBufferSize
.X
* 2);
459 Offset
+= (ScreenBuffer
->ScreenBufferSize
.X
* 2);
461 diff
= Size
.X
- ScreenBuffer
->ScreenBufferSize
.X
;
462 /* zero new part of it */
464 wmemset((PWCHAR
)&Buffer
[Offset
], value
, diff
);
466 for (i
= 0; i
< diff
; i
++)
468 Buffer
[Offset
++] = ' ';
469 Buffer
[Offset
++] = ScreenBuffer
->ScreenDefaultAttrib
;
475 if (Size
.Y
> ScreenBuffer
->ScreenBufferSize
.Y
)
477 diff
= Size
.X
* (Size
.Y
- ScreenBuffer
->ScreenBufferSize
.Y
);
479 wmemset((PWCHAR
)&Buffer
[Offset
], value
, diff
);
481 for (i
= 0; i
< diff
; i
++)
483 Buffer
[Offset
++] = ' ';
484 Buffer
[Offset
++] = ScreenBuffer
->ScreenDefaultAttrib
;
489 (void)InterlockedExchangePointer((PVOID
volatile*)&ScreenBuffer
->Buffer
, Buffer
);
490 RtlFreeHeap(ConSrvHeap
, 0, OldBuffer
);
491 ScreenBuffer
->ScreenBufferSize
= Size
;
492 ScreenBuffer
->VirtualY
= 0;
494 /* Ensure cursor and window are within buffer */
495 if (ScreenBuffer
->CursorPosition
.X
>= Size
.X
)
496 ScreenBuffer
->CursorPosition
.X
= Size
.X
- 1;
497 if (ScreenBuffer
->CursorPosition
.Y
>= Size
.Y
)
498 ScreenBuffer
->CursorPosition
.Y
= Size
.Y
- 1;
499 if (ScreenBuffer
->ShowX
> Size
.X
- Console
->ConsoleSize
.X
)
500 ScreenBuffer
->ShowX
= Size
.X
- Console
->ConsoleSize
.X
;
501 if (ScreenBuffer
->ShowY
> Size
.Y
- Console
->ConsoleSize
.Y
)
502 ScreenBuffer
->ShowY
= Size
.Y
- Console
->ConsoleSize
.Y
;
505 * Trigger a buffer resize event
507 if (Console
->InputBuffer
.Mode
& ENABLE_WINDOW_INPUT
)
511 er
.EventType
= WINDOW_BUFFER_SIZE_EVENT
;
512 er
.Event
.WindowBufferSizeEvent
.dwSize
= ScreenBuffer
->ScreenBufferSize
;
514 ConioProcessInputEvent(Console
, &er
);
517 /* TODO: Should update scrollbar, but can't use anything that
518 * calls SendMessage or it could cause deadlock --> Use PostMessage */
519 // TODO: Tell the terminal to resize its scrollbars.
521 return STATUS_SUCCESS
;
525 ConioDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer
)
527 PCONSOLE Console
= Buffer
->Header
.Console
;
529 RemoveEntryList(&Buffer
->ListEntry
);
530 if (Buffer
== Console
->ActiveBuffer
)
532 /* Deleted active buffer; switch to most recently created */
533 Console
->ActiveBuffer
= NULL
;
534 if (!IsListEmpty(&Console
->BufferList
))
536 Console
->ActiveBuffer
= CONTAINING_RECORD(Console
->BufferList
.Flink
, CONSOLE_SCREEN_BUFFER
, ListEntry
);
537 ConioDrawConsole(Console
);
541 RtlFreeHeap(ConSrvHeap
, 0, Buffer
->Buffer
);
542 RtlFreeHeap(ConSrvHeap
, 0, Buffer
);
546 ConioDrawConsole(PCONSOLE Console
)
550 ConioInitRect(&Region
, 0, 0, Console
->ConsoleSize
.Y
- 1, Console
->ConsoleSize
.X
- 1);
551 ConioDrawRegion(Console
, &Region
);
555 ConioComputeUpdateRect(PCONSOLE_SCREEN_BUFFER Buff
, SMALL_RECT
* UpdateRect
, PCOORD Start
, UINT Length
)
557 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
559 UpdateRect
->Left
= 0;
563 UpdateRect
->Left
= Start
->X
;
565 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
567 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
571 UpdateRect
->Right
= Start
->X
+ Length
- 1;
573 UpdateRect
->Top
= Start
->Y
;
574 UpdateRect
->Bottom
= Start
->Y
+ (Start
->X
+ Length
- 1) / Buff
->ScreenBufferSize
.X
;
575 if (Buff
->ScreenBufferSize
.Y
<= UpdateRect
->Bottom
)
577 UpdateRect
->Bottom
= Buff
->ScreenBufferSize
.Y
- 1;
582 ConioEffectiveCursorSize(PCONSOLE Console
, DWORD Scale
)
584 DWORD Size
= (Console
->ActiveBuffer
->CursorInfo
.dwSize
* Scale
+ 99) / 100;
585 /* If line input in progress, perhaps adjust for insert toggle */
586 if (Console
->LineBuffer
&& !Console
->LineComplete
&& Console
->LineInsertToggle
)
587 return (Size
* 2 <= Scale
) ? (Size
* 2) : (Size
/ 2);
592 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage
,
593 IN PCSR_THREAD ClientThread
,
594 IN BOOL CreateWaitBlock OPTIONAL
);
596 // Wait function CSR_WAIT_FUNCTION
598 WriteConsoleThread(IN PLIST_ENTRY WaitList
,
599 IN PCSR_THREAD WaitThread
,
600 IN PCSR_API_MESSAGE WaitApiMessage
,
601 IN PVOID WaitContext
,
602 IN PVOID WaitArgument1
,
603 IN PVOID WaitArgument2
,
608 DPRINT("WriteConsoleThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
611 * If we are notified of the process termination via a call
612 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
613 * CsrDestroyThread, just return.
615 if (WaitFlags
& CsrProcessTerminating
)
617 Status
= STATUS_THREAD_IS_TERMINATING
;
621 Status
= DoWriteConsole(WaitApiMessage
,
626 if (Status
!= STATUS_PENDING
)
628 WaitApiMessage
->Status
= Status
;
631 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
635 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage
,
636 IN PCSR_THREAD ClientThread
,
637 IN BOOL CreateWaitBlock OPTIONAL
)
639 NTSTATUS Status
= STATUS_SUCCESS
;
640 PCONSOLE_WRITECONSOLE WriteConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteConsoleRequest
;
642 PCONSOLE_SCREEN_BUFFER Buff
;
647 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(ClientThread
->Process
), WriteConsoleRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, FALSE
);
648 if (!NT_SUCCESS(Status
)) return Status
;
650 Console
= Buff
->Header
.Console
;
652 // if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION))
653 if (Console
->PauseFlags
&& Console
->UnpauseEvent
!= NULL
)
657 if (!CsrCreateWait(&Console
->WriteWaitQueue
,
665 ConSrvReleaseScreenBuffer(Buff
, FALSE
);
666 return STATUS_NO_MEMORY
;
670 /* Wait until we un-pause the console */
671 Status
= STATUS_PENDING
;
675 if (WriteConsoleRequest
->Unicode
)
677 Length
= WideCharToMultiByte(Console
->OutputCodePage
, 0,
678 (PWCHAR
)WriteConsoleRequest
->Buffer
,
679 WriteConsoleRequest
->NrCharactersToWrite
,
680 NULL
, 0, NULL
, NULL
);
681 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
);
684 WideCharToMultiByte(Console
->OutputCodePage
, 0,
685 (PWCHAR
)WriteConsoleRequest
->Buffer
,
686 WriteConsoleRequest
->NrCharactersToWrite
,
687 Buffer
, Length
, NULL
, NULL
);
691 Status
= STATUS_NO_MEMORY
;
696 Buffer
= (PCHAR
)WriteConsoleRequest
->Buffer
;
701 if (NT_SUCCESS(Status
))
703 Status
= ConioWriteConsole(Console
, Buff
, Buffer
,
704 WriteConsoleRequest
->NrCharactersToWrite
, TRUE
);
705 if (NT_SUCCESS(Status
))
707 Written
= WriteConsoleRequest
->NrCharactersToWrite
;
710 if (WriteConsoleRequest
->Unicode
)
712 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
716 WriteConsoleRequest
->NrCharactersWritten
= Written
;
719 ConSrvReleaseScreenBuffer(Buff
, FALSE
);
724 /* PUBLIC SERVER APIS *********************************************************/
726 CSR_API(SrvReadConsoleOutput
)
728 PCONSOLE_READOUTPUT ReadOutputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadOutputRequest
;
729 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
731 PCHAR_INFO CurCharInfo
;
732 PCONSOLE_SCREEN_BUFFER Buff
;
737 SMALL_RECT ReadRegion
;
738 SMALL_RECT ScreenRect
;
744 DPRINT("SrvReadConsoleOutput\n");
746 CharInfo
= ReadOutputRequest
->CharInfo
;
747 ReadRegion
= ReadOutputRequest
->ReadRegion
;
748 BufferSize
= ReadOutputRequest
->BufferSize
;
749 BufferCoord
= ReadOutputRequest
->BufferCoord
;
751 if (!CsrValidateMessageBuffer(ApiMessage
,
752 (PVOID
*)&ReadOutputRequest
->CharInfo
,
753 BufferSize
.X
* BufferSize
.Y
,
756 return STATUS_INVALID_PARAMETER
;
759 Status
= ConSrvGetScreenBuffer(ProcessData
, ReadOutputRequest
->OutputHandle
, &Buff
, GENERIC_READ
, TRUE
);
760 if (!NT_SUCCESS(Status
)) return Status
;
762 /* FIXME: Is this correct? */
763 CodePage
= ProcessData
->Console
->OutputCodePage
;
765 SizeY
= min(BufferSize
.Y
- BufferCoord
.Y
, ConioRectHeight(&ReadRegion
));
766 SizeX
= min(BufferSize
.X
- BufferCoord
.X
, ConioRectWidth(&ReadRegion
));
767 ReadRegion
.Bottom
= ReadRegion
.Top
+ SizeY
;
768 ReadRegion
.Right
= ReadRegion
.Left
+ SizeX
;
770 ConioInitRect(&ScreenRect
, 0, 0, Buff
->ScreenBufferSize
.Y
, Buff
->ScreenBufferSize
.X
);
771 if (!ConioGetIntersection(&ReadRegion
, &ScreenRect
, &ReadRegion
))
773 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
774 return STATUS_SUCCESS
;
777 for (i
= 0, Y
= ReadRegion
.Top
; Y
< ReadRegion
.Bottom
; ++i
, ++Y
)
779 CurCharInfo
= CharInfo
+ (i
* BufferSize
.X
);
781 Ptr
= ConioCoordToPointer(Buff
, ReadRegion
.Left
, Y
);
782 for (X
= ReadRegion
.Left
; X
< ReadRegion
.Right
; ++X
)
784 if (ReadOutputRequest
->Unicode
)
786 // ConsoleAnsiCharToUnicodeChar(ProcessData->Console, (PCHAR)Ptr++, &CurCharInfo->Char.UnicodeChar);
787 MultiByteToWideChar(CodePage
, 0,
789 &CurCharInfo
->Char
.UnicodeChar
, 1);
793 CurCharInfo
->Char
.AsciiChar
= *Ptr
++;
795 CurCharInfo
->Attributes
= *Ptr
++;
800 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
802 ReadOutputRequest
->ReadRegion
.Right
= ReadRegion
.Left
+ SizeX
- 1;
803 ReadOutputRequest
->ReadRegion
.Bottom
= ReadRegion
.Top
+ SizeY
- 1;
804 ReadOutputRequest
->ReadRegion
.Left
= ReadRegion
.Left
;
805 ReadOutputRequest
->ReadRegion
.Top
= ReadRegion
.Top
;
807 return STATUS_SUCCESS
;
810 CSR_API(SrvWriteConsole
)
813 PCONSOLE_WRITECONSOLE WriteConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteConsoleRequest
;
815 DPRINT("SrvWriteConsole\n");
817 if (!CsrValidateMessageBuffer(ApiMessage
,
818 (PVOID
)&WriteConsoleRequest
->Buffer
,
819 WriteConsoleRequest
->BufferSize
,
822 return STATUS_INVALID_PARAMETER
;
825 Status
= DoWriteConsole(ApiMessage
,
826 CsrGetClientThread(),
829 if (Status
== STATUS_PENDING
)
830 *ReplyCode
= CsrReplyPending
;
835 CSR_API(SrvWriteConsoleOutput
)
837 PCONSOLE_WRITEOUTPUT WriteOutputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteOutputRequest
;
838 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
839 SHORT i
, X
, Y
, SizeX
, SizeY
;
841 PCONSOLE_SCREEN_BUFFER Buff
;
842 SMALL_RECT ScreenBuffer
;
843 CHAR_INFO
* CurCharInfo
;
844 SMALL_RECT WriteRegion
;
851 DPRINT("SrvWriteConsoleOutput\n");
853 BufferSize
= WriteOutputRequest
->BufferSize
;
854 BufferCoord
= WriteOutputRequest
->BufferCoord
;
855 CharInfo
= WriteOutputRequest
->CharInfo
;
857 if (!CsrValidateMessageBuffer(ApiMessage
,
858 (PVOID
*)&WriteOutputRequest
->CharInfo
,
859 BufferSize
.X
* BufferSize
.Y
,
862 return STATUS_INVALID_PARAMETER
;
865 Status
= ConSrvGetScreenBuffer(ProcessData
,
866 WriteOutputRequest
->OutputHandle
,
870 if (!NT_SUCCESS(Status
)) return Status
;
872 Console
= Buff
->Header
.Console
;
874 WriteRegion
= WriteOutputRequest
->WriteRegion
;
876 SizeY
= min(BufferSize
.Y
- BufferCoord
.Y
, ConioRectHeight(&WriteRegion
));
877 SizeX
= min(BufferSize
.X
- BufferCoord
.X
, ConioRectWidth(&WriteRegion
));
878 WriteRegion
.Bottom
= WriteRegion
.Top
+ SizeY
- 1;
879 WriteRegion
.Right
= WriteRegion
.Left
+ SizeX
- 1;
881 /* Make sure WriteRegion is inside the screen buffer */
882 ConioInitRect(&ScreenBuffer
, 0, 0, Buff
->ScreenBufferSize
.Y
- 1, Buff
->ScreenBufferSize
.X
- 1);
883 if (!ConioGetIntersection(&WriteRegion
, &ScreenBuffer
, &WriteRegion
))
885 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
887 /* It is okay to have a WriteRegion completely outside the screen buffer.
888 No data is written then. */
889 return STATUS_SUCCESS
;
892 for (i
= 0, Y
= WriteRegion
.Top
; Y
<= WriteRegion
.Bottom
; i
++, Y
++)
894 CurCharInfo
= CharInfo
+ (i
+ BufferCoord
.Y
) * BufferSize
.X
+ BufferCoord
.X
;
895 Ptr
= ConioCoordToPointer(Buff
, WriteRegion
.Left
, Y
);
896 for (X
= WriteRegion
.Left
; X
<= WriteRegion
.Right
; X
++)
899 if (WriteOutputRequest
->Unicode
)
901 ConsoleUnicodeCharToAnsiChar(Console
, &AsciiChar
, &CurCharInfo
->Char
.UnicodeChar
);
905 AsciiChar
= CurCharInfo
->Char
.AsciiChar
;
908 *Ptr
++ = CurCharInfo
->Attributes
;
913 ConioDrawRegion(Console
, &WriteRegion
);
915 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
917 WriteOutputRequest
->WriteRegion
.Right
= WriteRegion
.Left
+ SizeX
- 1;
918 WriteOutputRequest
->WriteRegion
.Bottom
= WriteRegion
.Top
+ SizeY
- 1;
919 WriteOutputRequest
->WriteRegion
.Left
= WriteRegion
.Left
;
920 WriteOutputRequest
->WriteRegion
.Top
= WriteRegion
.Top
;
922 return STATUS_SUCCESS
;
925 CSR_API(SrvReadConsoleOutputString
)
928 PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadOutputCodeRequest
;
930 PCONSOLE_SCREEN_BUFFER Buff
;
938 DPRINT("SrvReadConsoleOutputString\n");
940 CodeType
= ReadOutputCodeRequest
->CodeType
;
944 CodeSize
= sizeof(CHAR
);
948 CodeSize
= sizeof(WCHAR
);
952 CodeSize
= sizeof(WORD
);
956 return STATUS_INVALID_PARAMETER
;
959 if (!CsrValidateMessageBuffer(ApiMessage
,
960 (PVOID
*)&ReadOutputCodeRequest
->pCode
.pCode
,
961 ReadOutputCodeRequest
->NumCodesToRead
,
964 return STATUS_INVALID_PARAMETER
;
967 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), ReadOutputCodeRequest
->OutputHandle
, &Buff
, GENERIC_READ
, TRUE
);
968 if (!NT_SUCCESS(Status
)) return Status
;
970 Console
= Buff
->Header
.Console
;
972 ReadBuffer
= ReadOutputCodeRequest
->pCode
.pCode
;
973 Xpos
= ReadOutputCodeRequest
->ReadCoord
.X
;
974 Ypos
= (ReadOutputCodeRequest
->ReadCoord
.Y
+ Buff
->VirtualY
) % Buff
->ScreenBufferSize
.Y
;
977 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
979 * If the number of attributes (resp. characters) to be read from extends
980 * beyond the end of the specified screen buffer row, attributes (resp.
981 * characters) are read from the next row. If the number of attributes
982 * (resp. characters) to be read from extends beyond the end of the console
983 * screen buffer, attributes (resp. characters) up to the end of the console
984 * screen buffer are read.
986 * TODO: Do NOT loop up to NumCodesToRead, but stop before
987 * if we are going to overflow...
989 for (i
= 0; i
< ReadOutputCodeRequest
->NumCodesToRead
; ++i
)
991 Code
= Buff
->Buffer
[2 * (Xpos
+ Ypos
* Buff
->ScreenBufferSize
.X
) + (CodeType
== CODE_ATTRIBUTE
? 1 : 0)];
996 ConsoleAnsiCharToUnicodeChar(Console
, (PWCHAR
)ReadBuffer
, (PCHAR
)&Code
);
1000 *(PCHAR
)ReadBuffer
= (CHAR
)Code
;
1003 case CODE_ATTRIBUTE
:
1004 *(PWORD
)ReadBuffer
= (WORD
)Code
;
1007 ReadBuffer
= (PVOID
)((ULONG_PTR
)ReadBuffer
+ CodeSize
);
1011 if (Xpos
== Buff
->ScreenBufferSize
.X
)
1016 if (Ypos
== Buff
->ScreenBufferSize
.Y
)
1023 // switch (CodeType)
1025 // case CODE_UNICODE:
1026 // *(PWCHAR)ReadBuffer = 0;
1030 // *(PCHAR)ReadBuffer = 0;
1033 // case CODE_ATTRIBUTE:
1034 // *(PWORD)ReadBuffer = 0;
1038 ReadOutputCodeRequest
->EndCoord
.X
= Xpos
;
1039 ReadOutputCodeRequest
->EndCoord
.Y
= (Ypos
- Buff
->VirtualY
+ Buff
->ScreenBufferSize
.Y
) % Buff
->ScreenBufferSize
.Y
;
1041 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1043 ReadOutputCodeRequest
->CodesRead
= (DWORD
)((ULONG_PTR
)ReadBuffer
- (ULONG_PTR
)ReadOutputCodeRequest
->pCode
.pCode
) / CodeSize
;
1044 // <= ReadOutputCodeRequest->NumCodesToRead
1046 return STATUS_SUCCESS
;
1049 CSR_API(SrvWriteConsoleOutputString
)
1052 PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteOutputCodeRequest
;
1054 PCONSOLE_SCREEN_BUFFER Buff
;
1056 PBYTE Buffer
; // PUCHAR
1057 PCHAR String
, tmpString
= NULL
;
1058 DWORD X
, Y
, Length
; // , Written = 0;
1060 SMALL_RECT UpdateRect
;
1062 DPRINT("SrvWriteConsoleOutputString\n");
1064 CodeType
= WriteOutputCodeRequest
->CodeType
;
1068 CodeSize
= sizeof(CHAR
);
1072 CodeSize
= sizeof(WCHAR
);
1075 case CODE_ATTRIBUTE
:
1076 CodeSize
= sizeof(WORD
);
1080 return STATUS_INVALID_PARAMETER
;
1083 if (!CsrValidateMessageBuffer(ApiMessage
,
1084 (PVOID
*)&WriteOutputCodeRequest
->pCode
.pCode
,
1085 WriteOutputCodeRequest
->Length
,
1088 return STATUS_INVALID_PARAMETER
;
1091 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1092 WriteOutputCodeRequest
->OutputHandle
,
1096 if (!NT_SUCCESS(Status
)) return Status
;
1098 Console
= Buff
->Header
.Console
;
1104 Length
= WideCharToMultiByte(Console
->OutputCodePage
, 0,
1105 (PWCHAR
)WriteOutputCodeRequest
->pCode
.UnicodeChar
,
1106 WriteOutputCodeRequest
->Length
,
1107 NULL
, 0, NULL
, NULL
);
1108 tmpString
= String
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
);
1111 WideCharToMultiByte(Console
->OutputCodePage
, 0,
1112 (PWCHAR
)WriteOutputCodeRequest
->pCode
.UnicodeChar
,
1113 WriteOutputCodeRequest
->Length
,
1114 String
, Length
, NULL
, NULL
);
1118 Status
= STATUS_NO_MEMORY
;
1125 String
= (PCHAR
)WriteOutputCodeRequest
->pCode
.AsciiChar
;
1128 case CODE_ATTRIBUTE
:
1130 // *(ReadBuffer++) = Code;
1131 String
= (PCHAR
)WriteOutputCodeRequest
->pCode
.Attribute
;
1135 if (String
&& NT_SUCCESS(Status
))
1137 X
= WriteOutputCodeRequest
->Coord
.X
;
1138 Y
= (WriteOutputCodeRequest
->Coord
.Y
+ Buff
->VirtualY
) % Buff
->ScreenBufferSize
.Y
;
1139 Length
= WriteOutputCodeRequest
->Length
;
1140 Buffer
= &Buff
->Buffer
[2 * (Y
* Buff
->ScreenBufferSize
.X
+ X
) + (CodeType
== CODE_ATTRIBUTE
? 1 : 0)];
1144 *Buffer
= *String
++;
1145 // ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
1146 String
= (PCHAR
)((ULONG_PTR
)String
+ CodeSize
);
1149 if (++X
== Buff
->ScreenBufferSize
.X
)
1151 if (++Y
== Buff
->ScreenBufferSize
.Y
)
1154 Buffer
= Buff
->Buffer
+ (CodeType
== CODE_ATTRIBUTE
? 1 : 0);
1160 if (Buff
== Console
->ActiveBuffer
)
1162 ConioComputeUpdateRect(Buff
, &UpdateRect
, &WriteOutputCodeRequest
->Coord
,
1163 WriteOutputCodeRequest
->Length
);
1164 ConioDrawRegion(Console
, &UpdateRect
);
1167 // WriteOutputCodeRequest->EndCoord.X = X;
1168 // WriteOutputCodeRequest->EndCoord.Y = (Y + Buff->ScreenBufferSize.Y - Buff->VirtualY) % Buff->ScreenBufferSize.Y;
1173 RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString
);
1176 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1178 // WriteOutputCodeRequest->NrCharactersWritten = Written;
1182 CSR_API(SrvFillConsoleOutput
)
1185 PCONSOLE_FILLOUTPUTCODE FillOutputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.FillOutputRequest
;
1187 PCONSOLE_SCREEN_BUFFER Buff
;
1188 DWORD X
, Y
, Length
; // , Written = 0;
1192 SMALL_RECT UpdateRect
;
1194 DPRINT("SrvFillConsoleOutput\n");
1196 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), FillOutputRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1197 if (!NT_SUCCESS(Status
)) return Status
;
1199 Console
= Buff
->Header
.Console
;
1201 CodeType
= FillOutputRequest
->CodeType
;
1203 X
= FillOutputRequest
->Coord
.X
;
1204 Y
= (FillOutputRequest
->Coord
.Y
+ Buff
->VirtualY
) % Buff
->ScreenBufferSize
.Y
;
1205 Length
= FillOutputRequest
->Length
;
1206 Buffer
= &Buff
->Buffer
[2 * (Y
* Buff
->ScreenBufferSize
.X
+ X
) + (CodeType
== CODE_ATTRIBUTE
? 1 : 0)];
1211 Code
= (BYTE
)FillOutputRequest
->Code
.AsciiChar
;
1215 ConsoleUnicodeCharToAnsiChar(Console
, (PCHAR
)&Code
, &FillOutputRequest
->Code
.UnicodeChar
);
1218 case CODE_ATTRIBUTE
:
1219 Code
= (BYTE
)FillOutputRequest
->Code
.Attribute
;
1223 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1224 return STATUS_INVALID_PARAMETER
;
1232 if (++X
== Buff
->ScreenBufferSize
.X
)
1234 if (++Y
== Buff
->ScreenBufferSize
.Y
)
1237 Buffer
= Buff
->Buffer
+ (CodeType
== CODE_ATTRIBUTE
? 1 : 0);
1243 if (Buff
== Console
->ActiveBuffer
)
1245 ConioComputeUpdateRect(Buff
, &UpdateRect
, &FillOutputRequest
->Coord
,
1246 FillOutputRequest
->Length
);
1247 ConioDrawRegion(Console
, &UpdateRect
);
1250 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1252 Length = FillOutputRequest->Length;
1253 FillOutputRequest->NrCharactersWritten = Length;
1255 return STATUS_SUCCESS
;
1258 CSR_API(SrvGetConsoleCursorInfo
)
1261 PCONSOLE_GETSETCURSORINFO CursorInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.CursorInfoRequest
;
1262 PCONSOLE_SCREEN_BUFFER Buff
;
1264 DPRINT("SrvGetConsoleCursorInfo\n");
1266 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), CursorInfoRequest
->OutputHandle
, &Buff
, GENERIC_READ
, TRUE
);
1267 if (!NT_SUCCESS(Status
)) return Status
;
1269 CursorInfoRequest
->Info
.bVisible
= Buff
->CursorInfo
.bVisible
;
1270 CursorInfoRequest
->Info
.dwSize
= Buff
->CursorInfo
.dwSize
;
1272 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1273 return STATUS_SUCCESS
;
1276 CSR_API(SrvSetConsoleCursorInfo
)
1279 PCONSOLE_GETSETCURSORINFO CursorInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.CursorInfoRequest
;
1281 PCONSOLE_SCREEN_BUFFER Buff
;
1285 DPRINT("SrvSetConsoleCursorInfo\n");
1287 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), CursorInfoRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1288 if (!NT_SUCCESS(Status
)) return Status
;
1290 Console
= Buff
->Header
.Console
;
1292 Size
= CursorInfoRequest
->Info
.dwSize
;
1293 Visible
= CursorInfoRequest
->Info
.bVisible
;
1303 if ( (Size
!= Buff
->CursorInfo
.dwSize
) ||
1304 (Visible
&& ! Buff
->CursorInfo
.bVisible
) ||
1305 (! Visible
&& Buff
->CursorInfo
.bVisible
) )
1307 Buff
->CursorInfo
.dwSize
= Size
;
1308 Buff
->CursorInfo
.bVisible
= Visible
;
1310 if (!ConioSetCursorInfo(Console
, Buff
))
1312 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1313 return STATUS_UNSUCCESSFUL
;
1317 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1318 return STATUS_SUCCESS
;
1321 CSR_API(SrvSetConsoleCursorPosition
)
1324 PCONSOLE_SETCURSORPOSITION SetCursorPositionRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetCursorPositionRequest
;
1326 PCONSOLE_SCREEN_BUFFER Buff
;
1327 LONG OldCursorX
, OldCursorY
;
1328 LONG NewCursorX
, NewCursorY
;
1330 DPRINT("SrvSetConsoleCursorPosition\n");
1332 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), SetCursorPositionRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1333 if (!NT_SUCCESS(Status
)) return Status
;
1335 Console
= Buff
->Header
.Console
;
1337 NewCursorX
= SetCursorPositionRequest
->Position
.X
;
1338 NewCursorY
= SetCursorPositionRequest
->Position
.Y
;
1339 if ( NewCursorX
< 0 || NewCursorX
>= Buff
->ScreenBufferSize
.X
||
1340 NewCursorY
< 0 || NewCursorY
>= Buff
->ScreenBufferSize
.Y
)
1342 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1343 return STATUS_INVALID_PARAMETER
;
1345 OldCursorX
= Buff
->CursorPosition
.X
;
1346 OldCursorY
= Buff
->CursorPosition
.Y
;
1347 Buff
->CursorPosition
.X
= NewCursorX
;
1348 Buff
->CursorPosition
.Y
= NewCursorY
;
1349 if (Buff
== Console
->ActiveBuffer
)
1351 if (!ConioSetScreenInfo(Console
, Buff
, OldCursorX
, OldCursorY
))
1353 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1354 return STATUS_UNSUCCESSFUL
;
1358 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1359 return STATUS_SUCCESS
;
1362 CSR_API(SrvSetConsoleTextAttribute
)
1365 PCONSOLE_SETTEXTATTRIB SetTextAttribRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetTextAttribRequest
;
1367 PCONSOLE_SCREEN_BUFFER Buff
;
1369 DPRINT("SrvSetConsoleTextAttribute\n");
1371 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), SetTextAttribRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1372 if (!NT_SUCCESS(Status
)) return Status
;
1374 Console
= Buff
->Header
.Console
;
1376 Buff
->ScreenDefaultAttrib
= SetTextAttribRequest
->Attrib
;
1377 if (Buff
== Console
->ActiveBuffer
)
1379 if (!ConioUpdateScreenInfo(Console
, Buff
))
1381 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1382 return STATUS_UNSUCCESSFUL
;
1386 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1387 return STATUS_SUCCESS
;
1390 CSR_API(SrvCreateConsoleScreenBuffer
)
1393 PCONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.CreateScreenBufferRequest
;
1394 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
1396 PCONSOLE_SCREEN_BUFFER Buff
;
1398 COORD ScreenBufferSize
= {80, 25};
1399 USHORT ScreenAttrib
= DEFAULT_SCREEN_ATTRIB
;
1400 USHORT PopupAttrib
= DEFAULT_POPUP_ATTRIB
;
1401 ULONG DisplayMode
= CONSOLE_WINDOWED_MODE
;
1402 BOOLEAN IsCursorVisible
= TRUE
;
1403 ULONG CursorSize
= CSR_DEFAULT_CURSOR_SIZE
;
1405 DPRINT("SrvCreateConsoleScreenBuffer\n");
1407 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
1408 if (!NT_SUCCESS(Status
)) return Status
;
1411 if (Console->ActiveBuffer)
1413 ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize;
1414 if (ScreenBufferSize.X == 0) ScreenBufferSize.X = 80;
1415 if (ScreenBufferSize.Y == 0) ScreenBufferSize.Y = 25;
1417 ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib;
1418 PopupAttrib = Console->ActiveBuffer->PopupDefaultAttrib;
1420 IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible;
1421 CursorSize = Console->ActiveBuffer->CursorInfo.dwSize;
1425 // This is Windows' behaviour
1427 ScreenBufferSize
= Console
->ConsoleSize
; // Use the current console size
1428 if (ScreenBufferSize
.X
== 0) ScreenBufferSize
.X
= 1;
1429 if (ScreenBufferSize
.Y
== 0) ScreenBufferSize
.Y
= 1;
1431 if (Console
->ActiveBuffer
)
1433 ScreenAttrib
= Console
->ActiveBuffer
->ScreenDefaultAttrib
;
1434 PopupAttrib
= Console
->ActiveBuffer
->PopupDefaultAttrib
;
1435 DisplayMode
= Console
->ActiveBuffer
->DisplayMode
;
1437 IsCursorVisible
= Console
->ActiveBuffer
->CursorInfo
.bVisible
;
1438 CursorSize
= Console
->ActiveBuffer
->CursorInfo
.dwSize
;
1442 Status
= ConSrvCreateScreenBuffer(Console
,
1450 if (NT_SUCCESS(Status
))
1452 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
1454 /* Insert the new handle inside the process handles table */
1455 Status
= ConSrvInsertObject(ProcessData
,
1456 &CreateScreenBufferRequest
->OutputHandle
,
1458 CreateScreenBufferRequest
->Access
,
1459 CreateScreenBufferRequest
->Inheritable
,
1460 CreateScreenBufferRequest
->ShareMode
);
1462 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
1465 ConSrvReleaseConsole(Console
, TRUE
);
1469 CSR_API(SrvGetConsoleScreenBufferInfo
)
1472 PCONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ScreenBufferInfoRequest
;
1474 PCONSOLE_SCREEN_BUFFER Buff
;
1475 PCONSOLE_SCREEN_BUFFER_INFO pInfo
= &ScreenBufferInfoRequest
->Info
;
1477 DPRINT("SrvGetConsoleScreenBufferInfo\n");
1479 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), ScreenBufferInfoRequest
->OutputHandle
, &Buff
, GENERIC_READ
, TRUE
);
1480 if (!NT_SUCCESS(Status
)) return Status
;
1482 Console
= Buff
->Header
.Console
;
1484 pInfo
->dwSize
= Buff
->ScreenBufferSize
;
1485 pInfo
->dwCursorPosition
= Buff
->CursorPosition
;
1486 pInfo
->wAttributes
= Buff
->ScreenDefaultAttrib
;
1487 pInfo
->srWindow
.Left
= Buff
->ShowX
;
1488 pInfo
->srWindow
.Right
= Buff
->ShowX
+ Console
->ConsoleSize
.X
- 1;
1489 pInfo
->srWindow
.Top
= Buff
->ShowY
;
1490 pInfo
->srWindow
.Bottom
= Buff
->ShowY
+ Console
->ConsoleSize
.Y
- 1;
1491 pInfo
->dwMaximumWindowSize
= Buff
->ScreenBufferSize
;
1493 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1494 return STATUS_SUCCESS
;
1497 CSR_API(SrvSetConsoleActiveScreenBuffer
)
1500 PCONSOLE_SETACTIVESCREENBUFFER SetScreenBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetScreenBufferRequest
;
1502 PCONSOLE_SCREEN_BUFFER Buff
;
1504 DPRINT("SrvSetConsoleActiveScreenBuffer\n");
1506 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), SetScreenBufferRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1507 if (!NT_SUCCESS(Status
)) return Status
;
1509 Console
= Buff
->Header
.Console
;
1511 if (Buff
== Console
->ActiveBuffer
)
1513 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1514 return STATUS_SUCCESS
;
1517 /* If old buffer has no handles, it's now unreferenced */
1518 if (Console
->ActiveBuffer
->Header
.HandleCount
== 0)
1520 ConioDeleteScreenBuffer(Console
->ActiveBuffer
);
1523 /* Tie console to new buffer */
1524 Console
->ActiveBuffer
= Buff
;
1526 /* Redraw the console */
1527 ConioDrawConsole(Console
);
1529 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1530 return STATUS_SUCCESS
;
1533 CSR_API(SrvScrollConsoleScreenBuffer
)
1535 PCONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ScrollScreenBufferRequest
;
1537 PCONSOLE_SCREEN_BUFFER Buff
;
1538 SMALL_RECT ScreenBuffer
;
1539 SMALL_RECT SrcRegion
;
1540 SMALL_RECT DstRegion
;
1541 SMALL_RECT UpdateRegion
;
1542 SMALL_RECT ScrollRectangle
;
1543 SMALL_RECT ClipRectangle
;
1545 HANDLE OutputHandle
;
1546 BOOLEAN UseClipRectangle
;
1547 COORD DestinationOrigin
;
1551 DPRINT("SrvScrollConsoleScreenBuffer\n");
1553 OutputHandle
= ScrollScreenBufferRequest
->OutputHandle
;
1554 UseClipRectangle
= ScrollScreenBufferRequest
->UseClipRectangle
;
1555 DestinationOrigin
= ScrollScreenBufferRequest
->DestinationOrigin
;
1556 Fill
= ScrollScreenBufferRequest
->Fill
;
1558 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1559 if (!NT_SUCCESS(Status
)) return Status
;
1561 Console
= Buff
->Header
.Console
;
1563 ScrollRectangle
= ScrollScreenBufferRequest
->ScrollRectangle
;
1565 /* Make sure source rectangle is inside the screen buffer */
1566 ConioInitRect(&ScreenBuffer
, 0, 0, Buff
->ScreenBufferSize
.Y
- 1, Buff
->ScreenBufferSize
.X
- 1);
1567 if (!ConioGetIntersection(&SrcRegion
, &ScreenBuffer
, &ScrollRectangle
))
1569 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1570 return STATUS_SUCCESS
;
1573 /* If the source was clipped on the left or top, adjust the destination accordingly */
1574 if (ScrollRectangle
.Left
< 0)
1576 DestinationOrigin
.X
-= ScrollRectangle
.Left
;
1578 if (ScrollRectangle
.Top
< 0)
1580 DestinationOrigin
.Y
-= ScrollRectangle
.Top
;
1583 if (UseClipRectangle
)
1585 ClipRectangle
= ScrollScreenBufferRequest
->ClipRectangle
;
1586 if (!ConioGetIntersection(&ClipRectangle
, &ClipRectangle
, &ScreenBuffer
))
1588 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1589 return STATUS_SUCCESS
;
1594 ClipRectangle
= ScreenBuffer
;
1597 ConioInitRect(&DstRegion
,
1598 DestinationOrigin
.Y
,
1599 DestinationOrigin
.X
,
1600 DestinationOrigin
.Y
+ ConioRectHeight(&SrcRegion
) - 1,
1601 DestinationOrigin
.X
+ ConioRectWidth(&SrcRegion
) - 1);
1603 if (ScrollScreenBufferRequest
->Unicode
)
1604 ConsoleUnicodeCharToAnsiChar(Console
, &FillChar
, &Fill
.Char
.UnicodeChar
);
1606 FillChar
= Fill
.Char
.AsciiChar
;
1608 ConioMoveRegion(Buff
, &SrcRegion
, &DstRegion
, &ClipRectangle
, Fill
.Attributes
<< 8 | (BYTE
)FillChar
);
1610 if (Buff
== Console
->ActiveBuffer
)
1612 ConioGetUnion(&UpdateRegion
, &SrcRegion
, &DstRegion
);
1613 if (ConioGetIntersection(&UpdateRegion
, &UpdateRegion
, &ClipRectangle
))
1615 /* Draw update region */
1616 ConioDrawRegion(Console
, &UpdateRegion
);
1620 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1621 return STATUS_SUCCESS
;
1624 CSR_API(SrvSetConsoleScreenBufferSize
)
1627 PCONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetScreenBufferSizeRequest
;
1628 PCONSOLE_SCREEN_BUFFER Buff
;
1630 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), SetScreenBufferSizeRequest
->OutputHandle
, &Buff
, GENERIC_WRITE
, TRUE
);
1631 if (!NT_SUCCESS(Status
)) return Status
;
1633 Status
= ConioResizeBuffer(Buff
->Header
.Console
, Buff
, SetScreenBufferSizeRequest
->Size
);
1635 ConSrvReleaseScreenBuffer(Buff
, TRUE
);