[CONSRV]
[reactos.git] / win32ss / user / consrv / conoutput.c
1 /*
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)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "consrv.h"
13 #include "console.h"
14 #include "include/conio.h"
15 #include "conio.h"
16 #include "conoutput.h"
17 #include "handle.h"
18
19 #define NDEBUG
20 #include <debug.h>
21
22 /*
23 // Define wmemset(...)
24 #include <wchar.h>
25 #define HAVE_WMEMSET
26 */
27
28
29 /* GLOBALS ********************************************************************/
30
31 #define TAB_WIDTH 8
32
33 #define ConioInitRect(Rect, top, left, bottom, right) \
34 do { \
35 ((Rect)->Top) = top; \
36 ((Rect)->Left) = left; \
37 ((Rect)->Bottom) = bottom; \
38 ((Rect)->Right) = right; \
39 } while (0)
40
41 #define ConioIsRectEmpty(Rect) \
42 (((Rect)->Left > (Rect)->Right) || ((Rect)->Top > (Rect)->Bottom))
43
44 #define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \
45 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
46
47 #define ConsoleAnsiCharToUnicodeChar(Console, dWChar, sChar) \
48 MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1)
49
50
51 /* PRIVATE FUNCTIONS **********************************************************/
52
53 PBYTE FASTCALL
54 ConioCoordToPointer(PCONSOLE_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
55 {
56 return &Buff->Buffer[2 * (((Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y) * Buff->ScreenBufferSize.X + X)];
57 }
58
59 static VOID FASTCALL
60 ClearLineBuffer(PCONSOLE_SCREEN_BUFFER Buff)
61 {
62 PBYTE Ptr = ConioCoordToPointer(Buff, 0, Buff->CursorPosition.Y);
63 SHORT Pos;
64
65 for (Pos = 0; Pos < Buff->ScreenBufferSize.X; Pos++)
66 {
67 /* Fill the cell */
68 *Ptr++ = ' ';
69 *Ptr++ = (BYTE)Buff->ScreenDefaultAttrib;
70 }
71 }
72
73 NTSTATUS FASTCALL
74 ConSrvCreateScreenBuffer(IN OUT PCONSOLE Console,
75 OUT PCONSOLE_SCREEN_BUFFER* Buffer,
76 IN COORD ScreenBufferSize,
77 IN USHORT ScreenAttrib,
78 IN USHORT PopupAttrib,
79 IN ULONG DisplayMode,
80 IN BOOLEAN IsCursorVisible,
81 IN ULONG CursorSize)
82 {
83 if (Console == NULL || Buffer == NULL)
84 return STATUS_INVALID_PARAMETER;
85
86 *Buffer = RtlAllocateHeap(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CONSOLE_SCREEN_BUFFER));
87 if (NULL == *Buffer)
88 {
89 return STATUS_INSUFFICIENT_RESOURCES;
90 }
91
92 (*Buffer)->Header.Type = SCREEN_BUFFER;
93 (*Buffer)->Header.Console = Console;
94 (*Buffer)->Header.HandleCount = 0;
95 (*Buffer)->ScreenBufferSize = ScreenBufferSize;
96
97 (*Buffer)->Buffer = RtlAllocateHeap(ConSrvHeap, HEAP_ZERO_MEMORY, (*Buffer)->ScreenBufferSize.X * (*Buffer)->ScreenBufferSize.Y * 2);
98 if (NULL == (*Buffer)->Buffer)
99 {
100 RtlFreeHeap(ConSrvHeap, 0, *Buffer);
101 return STATUS_INSUFFICIENT_RESOURCES;
102 }
103
104 (*Buffer)->ShowX = 0;
105 (*Buffer)->ShowY = 0;
106 (*Buffer)->VirtualY = 0;
107
108 (*Buffer)->CursorInfo.bVisible = (IsCursorVisible && (CursorSize != 0));
109 (*Buffer)->CursorInfo.dwSize = min(max(CursorSize, 0), 100);
110
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++)
115 {
116 ClearLineBuffer(*Buffer);
117 }
118 (*Buffer)->CursorPosition.X = 0;
119 (*Buffer)->CursorPosition.Y = 0;
120
121 (*Buffer)->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
122 (*Buffer)->DisplayMode = DisplayMode;
123
124 InsertHeadList(&Console->BufferList, &(*Buffer)->ListEntry);
125 return STATUS_SUCCESS;
126 }
127
128 static VOID FASTCALL
129 ConioNextLine(PCONSOLE_SCREEN_BUFFER Buff, SMALL_RECT* UpdateRect, UINT *ScrolledLines)
130 {
131 /* If we hit bottom, slide the viewable screen */
132 if (++Buff->CursorPosition.Y == Buff->ScreenBufferSize.Y)
133 {
134 Buff->CursorPosition.Y--;
135 if (++Buff->VirtualY == Buff->ScreenBufferSize.Y)
136 {
137 Buff->VirtualY = 0;
138 }
139 (*ScrolledLines)++;
140 ClearLineBuffer(Buff);
141 if (UpdateRect->Top != 0)
142 {
143 UpdateRect->Top--;
144 }
145 }
146 UpdateRect->Left = 0;
147 UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
148 UpdateRect->Bottom = Buff->CursorPosition.Y;
149 }
150
151 NTSTATUS FASTCALL
152 ConioWriteConsole(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff,
153 CHAR *Buffer, DWORD Length, BOOL Attrib)
154 {
155 UINT i;
156 PBYTE Ptr;
157 SMALL_RECT UpdateRect;
158 SHORT CursorStartX, CursorStartY;
159 UINT ScrolledLines;
160
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;
167 ScrolledLines = 0;
168
169 for (i = 0; i < Length; i++)
170 {
171 /*
172 * If we are in processed mode, interpret special characters and
173 * display them correctly. Otherwise, just put them into the buffer.
174 */
175 if (Buff->Mode & ENABLE_PROCESSED_OUTPUT)
176 {
177 /* --- CR --- */
178 if (Buffer[i] == '\r')
179 {
180 Buff->CursorPosition.X = 0;
181 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
182 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
183 continue;
184 }
185 /* --- LF --- */
186 else if (Buffer[i] == '\n')
187 {
188 Buff->CursorPosition.X = 0;
189 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
190 continue;
191 }
192 /* --- BS --- */
193 else if (Buffer[i] == '\b')
194 {
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)
197 {
198 if (0 == Buff->CursorPosition.X)
199 {
200 /* slide virtual position up */
201 Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1;
202 Buff->CursorPosition.Y--;
203 UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y);
204 }
205 else
206 {
207 Buff->CursorPosition.X--;
208 }
209 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
210 Ptr[0] = ' ';
211 Ptr[1] = (BYTE)Buff->ScreenDefaultAttrib;
212 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
213 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
214 }
215 continue;
216 }
217 /* --- TAB --- */
218 else if (Buffer[i] == '\t')
219 {
220 UINT EndX;
221
222 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
223 EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1);
224 EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X);
225 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
226 while (Buff->CursorPosition.X < EndX)
227 {
228 *Ptr++ = ' ';
229 *Ptr++ = (BYTE)Buff->ScreenDefaultAttrib;
230 Buff->CursorPosition.X++;
231 }
232 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X - 1);
233 if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X)
234 {
235 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
236 {
237 Buff->CursorPosition.X = 0;
238 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
239 }
240 else
241 {
242 Buff->CursorPosition.X--;
243 }
244 }
245 continue;
246 }
247 // /* --- BEL ---*/
248 // else if (Buffer[i] == '\a')
249 // {
250 // // FIXME: This MUST BE moved to the terminal emulator frontend!!
251 // DPRINT1("Bell\n");
252 // // SendNotifyMessage(Console->hWindow, PM_CONSOLE_BEEP, 0, 0);
253 // continue;
254 // }
255 }
256 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
257 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
258 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
259 Ptr[0] = Buffer[i];
260 if (Attrib)
261 {
262 Ptr[1] = (BYTE)Buff->ScreenDefaultAttrib;
263 }
264 Buff->CursorPosition.X++;
265 if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X)
266 {
267 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
268 {
269 Buff->CursorPosition.X = 0;
270 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
271 }
272 else
273 {
274 Buff->CursorPosition.X = CursorStartX;
275 }
276 }
277 }
278
279 if (!ConioIsRectEmpty(&UpdateRect) && Buff == Console->ActiveBuffer)
280 {
281 ConioWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY,
282 ScrolledLines, Buffer, Length);
283 }
284
285 return STATUS_SUCCESS;
286 }
287
288 __inline BOOLEAN ConioGetIntersection(
289 SMALL_RECT* Intersection,
290 SMALL_RECT* Rect1,
291 SMALL_RECT* Rect2)
292 {
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))
299 {
300 /* The rectangles do not intersect */
301 ConioInitRect(Intersection, 0, -1, 0, -1);
302 return FALSE;
303 }
304
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));
310
311 return TRUE;
312 }
313
314 __inline BOOLEAN ConioGetUnion(
315 SMALL_RECT* Union,
316 SMALL_RECT* Rect1,
317 SMALL_RECT* Rect2)
318 {
319 if (ConioIsRectEmpty(Rect1))
320 {
321 if (ConioIsRectEmpty(Rect2))
322 {
323 ConioInitRect(Union, 0, -1, 0, -1);
324 return FALSE;
325 }
326 else
327 {
328 *Union = *Rect2;
329 }
330 }
331 else if (ConioIsRectEmpty(Rect2))
332 {
333 *Union = *Rect1;
334 }
335 else
336 {
337 ConioInitRect(Union,
338 min(Rect1->Top, Rect2->Top),
339 min(Rect1->Left, Rect2->Left),
340 max(Rect1->Bottom, Rect2->Bottom),
341 max(Rect1->Right, Rect2->Right));
342 }
343
344 return TRUE;
345 }
346
347 /*
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.
350 */
351 static VOID FASTCALL
352 ConioMoveRegion(PCONSOLE_SCREEN_BUFFER ScreenBuffer,
353 SMALL_RECT* SrcRegion,
354 SMALL_RECT* DstRegion,
355 SMALL_RECT* ClipRegion,
356 WORD Fill)
357 {
358 int Width = ConioRectWidth(SrcRegion);
359 int Height = ConioRectHeight(SrcRegion);
360 int SX, SY;
361 int DX, DY;
362 int XDelta, YDelta;
363 int i, j;
364
365 SY = SrcRegion->Top;
366 DY = DstRegion->Top;
367 YDelta = 1;
368 if (SY < DY)
369 {
370 /* Moving down: work from bottom up */
371 SY = SrcRegion->Bottom;
372 DY = DstRegion->Bottom;
373 YDelta = -1;
374 }
375 for (i = 0; i < Height; i++)
376 {
377 PWORD SRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, SY);
378 PWORD DRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, DY);
379
380 SX = SrcRegion->Left;
381 DX = DstRegion->Left;
382 XDelta = 1;
383 if (SX < DX)
384 {
385 /* Moving right: work from right to left */
386 SX = SrcRegion->Right;
387 DX = DstRegion->Right;
388 XDelta = -1;
389 }
390 for (j = 0; j < Width; j++)
391 {
392 WORD Cell = SRow[SX];
393 if (SX >= ClipRegion->Left && SX <= ClipRegion->Right
394 && SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
395 {
396 SRow[SX] = Fill;
397 }
398 if (DX >= ClipRegion->Left && DX <= ClipRegion->Right
399 && DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
400 {
401 DRow[DX] = Cell;
402 }
403 SX += XDelta;
404 DX += XDelta;
405 }
406 SY += YDelta;
407 DY += YDelta;
408 }
409 }
410
411 NTSTATUS FASTCALL
412 ConioResizeBuffer(PCONSOLE Console,
413 PCONSOLE_SCREEN_BUFFER ScreenBuffer,
414 COORD Size)
415 {
416 BYTE * Buffer;
417 DWORD Offset = 0;
418 BYTE * OldPtr;
419 USHORT CurrentY;
420 BYTE * OldBuffer;
421 #ifdef HAVE_WMEMSET
422 USHORT value = MAKEWORD(' ', ScreenBuffer->ScreenDefaultAttrib);
423 #else
424 DWORD i;
425 #endif
426 DWORD diff;
427
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;
431
432 if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y)
433 {
434 // FIXME: Trigger a buffer resize event ??
435 return STATUS_SUCCESS;
436 }
437
438 if (!ConioIsBufferResizeSupported(Console)) return STATUS_NOT_SUPPORTED;
439
440 Buffer = RtlAllocateHeap(ConSrvHeap, 0, Size.X * Size.Y * 2);
441 if (!Buffer) return STATUS_NO_MEMORY;
442
443 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y);
444 OldBuffer = ScreenBuffer->Buffer;
445
446 for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++)
447 {
448 OldPtr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
449 if (Size.X <= ScreenBuffer->ScreenBufferSize.X)
450 {
451 /* reduce size */
452 RtlCopyMemory(&Buffer[Offset], OldPtr, Size.X * 2);
453 Offset += (Size.X * 2);
454 }
455 else
456 {
457 /* enlarge size */
458 RtlCopyMemory(&Buffer[Offset], OldPtr, ScreenBuffer->ScreenBufferSize.X * 2);
459 Offset += (ScreenBuffer->ScreenBufferSize.X * 2);
460
461 diff = Size.X - ScreenBuffer->ScreenBufferSize.X;
462 /* zero new part of it */
463 #ifdef HAVE_WMEMSET
464 wmemset((PWCHAR)&Buffer[Offset], value, diff);
465 #else
466 for (i = 0; i < diff; i++)
467 {
468 Buffer[Offset++] = ' ';
469 Buffer[Offset++] = (BYTE)ScreenBuffer->ScreenDefaultAttrib;
470 }
471 #endif
472 }
473 }
474
475 if (Size.Y > ScreenBuffer->ScreenBufferSize.Y)
476 {
477 diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y);
478 #ifdef HAVE_WMEMSET
479 wmemset((PWCHAR)&Buffer[Offset], value, diff);
480 #else
481 for (i = 0; i < diff; i++)
482 {
483 Buffer[Offset++] = ' ';
484 Buffer[Offset++] = (BYTE)ScreenBuffer->ScreenDefaultAttrib;
485 }
486 #endif
487 }
488
489 (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer);
490 RtlFreeHeap(ConSrvHeap, 0, OldBuffer);
491 ScreenBuffer->ScreenBufferSize = Size;
492 ScreenBuffer->VirtualY = 0;
493
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;
503
504 /*
505 * Trigger a buffer resize event
506 */
507 if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT)
508 {
509 INPUT_RECORD er;
510
511 er.EventType = WINDOW_BUFFER_SIZE_EVENT;
512 er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize;
513
514 ConioProcessInputEvent(Console, &er);
515 }
516
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.
520
521 return STATUS_SUCCESS;
522 }
523
524 VOID WINAPI
525 ConioDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
526 {
527 PCONSOLE Console = Buffer->Header.Console;
528
529 RemoveEntryList(&Buffer->ListEntry);
530 if (Buffer == Console->ActiveBuffer)
531 {
532 /* Deleted active buffer; switch to most recently created */
533 Console->ActiveBuffer = NULL;
534 if (!IsListEmpty(&Console->BufferList))
535 {
536 Console->ActiveBuffer = CONTAINING_RECORD(Console->BufferList.Flink, CONSOLE_SCREEN_BUFFER, ListEntry);
537 ConioDrawConsole(Console);
538 }
539 }
540
541 RtlFreeHeap(ConSrvHeap, 0, Buffer->Buffer);
542 RtlFreeHeap(ConSrvHeap, 0, Buffer);
543 }
544
545 VOID FASTCALL
546 ConioDrawConsole(PCONSOLE Console)
547 {
548 SMALL_RECT Region;
549
550 ConioInitRect(&Region, 0, 0, Console->ConsoleSize.Y - 1, Console->ConsoleSize.X - 1);
551 ConioDrawRegion(Console, &Region);
552 }
553
554 static VOID FASTCALL
555 ConioComputeUpdateRect(PCONSOLE_SCREEN_BUFFER Buff, SMALL_RECT* UpdateRect, PCOORD Start, UINT Length)
556 {
557 if (Buff->ScreenBufferSize.X <= Start->X + Length)
558 {
559 UpdateRect->Left = 0;
560 }
561 else
562 {
563 UpdateRect->Left = Start->X;
564 }
565 if (Buff->ScreenBufferSize.X <= Start->X + Length)
566 {
567 UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
568 }
569 else
570 {
571 UpdateRect->Right = Start->X + Length - 1;
572 }
573 UpdateRect->Top = Start->Y;
574 UpdateRect->Bottom = Start->Y + (Start->X + Length - 1) / Buff->ScreenBufferSize.X;
575 if (Buff->ScreenBufferSize.Y <= UpdateRect->Bottom)
576 {
577 UpdateRect->Bottom = Buff->ScreenBufferSize.Y - 1;
578 }
579 }
580
581 DWORD FASTCALL
582 ConioEffectiveCursorSize(PCONSOLE Console, DWORD Scale)
583 {
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);
588 return Size;
589 }
590
591 static NTSTATUS
592 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
593 IN PCSR_THREAD ClientThread,
594 IN BOOL CreateWaitBlock OPTIONAL);
595
596 // Wait function CSR_WAIT_FUNCTION
597 static BOOLEAN
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,
604 IN ULONG WaitFlags)
605 {
606 NTSTATUS Status;
607
608 DPRINT("WriteConsoleThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
609
610 /*
611 * If we are notified of the process termination via a call
612 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
613 * CsrDestroyThread, just return.
614 */
615 if (WaitFlags & CsrProcessTerminating)
616 {
617 Status = STATUS_THREAD_IS_TERMINATING;
618 goto Quit;
619 }
620
621 Status = DoWriteConsole(WaitApiMessage,
622 WaitThread,
623 FALSE);
624
625 Quit:
626 if (Status != STATUS_PENDING)
627 {
628 WaitApiMessage->Status = Status;
629 }
630
631 return (Status == STATUS_PENDING ? FALSE : TRUE);
632 }
633
634 static NTSTATUS
635 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
636 IN PCSR_THREAD ClientThread,
637 IN BOOL CreateWaitBlock OPTIONAL)
638 {
639 NTSTATUS Status = STATUS_SUCCESS;
640 PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
641 PCONSOLE Console;
642 PCONSOLE_SCREEN_BUFFER Buff;
643 PCHAR Buffer;
644 DWORD Written = 0;
645 ULONG Length;
646
647 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(ClientThread->Process), WriteConsoleRequest->OutputHandle, &Buff, GENERIC_WRITE, FALSE);
648 if (!NT_SUCCESS(Status)) return Status;
649
650 Console = Buff->Header.Console;
651
652 // if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION))
653 if (Console->PauseFlags && Console->UnpauseEvent != NULL)
654 {
655 if (CreateWaitBlock)
656 {
657 if (!CsrCreateWait(&Console->WriteWaitQueue,
658 WriteConsoleThread,
659 ClientThread,
660 ApiMessage,
661 NULL,
662 NULL))
663 {
664 /* Fail */
665 ConSrvReleaseScreenBuffer(Buff, FALSE);
666 return STATUS_NO_MEMORY;
667 }
668 }
669
670 /* Wait until we un-pause the console */
671 Status = STATUS_PENDING;
672 }
673 else
674 {
675 if (WriteConsoleRequest->Unicode)
676 {
677 Length = WideCharToMultiByte(Console->OutputCodePage, 0,
678 (PWCHAR)WriteConsoleRequest->Buffer,
679 WriteConsoleRequest->NrCharactersToWrite,
680 NULL, 0, NULL, NULL);
681 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
682 if (Buffer)
683 {
684 WideCharToMultiByte(Console->OutputCodePage, 0,
685 (PWCHAR)WriteConsoleRequest->Buffer,
686 WriteConsoleRequest->NrCharactersToWrite,
687 Buffer, Length, NULL, NULL);
688 }
689 else
690 {
691 Status = STATUS_NO_MEMORY;
692 }
693 }
694 else
695 {
696 Buffer = (PCHAR)WriteConsoleRequest->Buffer;
697 }
698
699 if (Buffer)
700 {
701 if (NT_SUCCESS(Status))
702 {
703 Status = ConioWriteConsole(Console, Buff, Buffer,
704 WriteConsoleRequest->NrCharactersToWrite, TRUE);
705 if (NT_SUCCESS(Status))
706 {
707 Written = WriteConsoleRequest->NrCharactersToWrite;
708 }
709 }
710 if (WriteConsoleRequest->Unicode)
711 {
712 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
713 }
714 }
715
716 WriteConsoleRequest->NrCharactersWritten = Written;
717 }
718
719 ConSrvReleaseScreenBuffer(Buff, FALSE);
720 return Status;
721 }
722
723
724 /* PUBLIC SERVER APIS *********************************************************/
725
726 CSR_API(SrvReadConsoleOutput)
727 {
728 PCONSOLE_READOUTPUT ReadOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputRequest;
729 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
730 PCHAR_INFO CharInfo;
731 PCHAR_INFO CurCharInfo;
732 PCONSOLE_SCREEN_BUFFER Buff;
733 SHORT SizeX, SizeY;
734 NTSTATUS Status;
735 COORD BufferSize;
736 COORD BufferCoord;
737 SMALL_RECT ReadRegion;
738 SMALL_RECT ScreenRect;
739 DWORD i;
740 PBYTE Ptr;
741 LONG X, Y;
742 UINT CodePage;
743
744 DPRINT("SrvReadConsoleOutput\n");
745
746 CharInfo = ReadOutputRequest->CharInfo;
747 ReadRegion = ReadOutputRequest->ReadRegion;
748 BufferSize = ReadOutputRequest->BufferSize;
749 BufferCoord = ReadOutputRequest->BufferCoord;
750
751 if (!CsrValidateMessageBuffer(ApiMessage,
752 (PVOID*)&ReadOutputRequest->CharInfo,
753 BufferSize.X * BufferSize.Y,
754 sizeof(CHAR_INFO)))
755 {
756 return STATUS_INVALID_PARAMETER;
757 }
758
759 Status = ConSrvGetScreenBuffer(ProcessData, ReadOutputRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
760 if (!NT_SUCCESS(Status)) return Status;
761
762 /* FIXME: Is this correct? */
763 CodePage = ProcessData->Console->OutputCodePage;
764
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;
769
770 ConioInitRect(&ScreenRect, 0, 0, Buff->ScreenBufferSize.Y, Buff->ScreenBufferSize.X);
771 if (!ConioGetIntersection(&ReadRegion, &ScreenRect, &ReadRegion))
772 {
773 ConSrvReleaseScreenBuffer(Buff, TRUE);
774 return STATUS_SUCCESS;
775 }
776
777 for (i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y)
778 {
779 CurCharInfo = CharInfo + (i * BufferSize.X);
780
781 Ptr = ConioCoordToPointer(Buff, ReadRegion.Left, Y);
782 for (X = ReadRegion.Left; X < ReadRegion.Right; ++X)
783 {
784 if (ReadOutputRequest->Unicode)
785 {
786 // ConsoleAnsiCharToUnicodeChar(ProcessData->Console, (PCHAR)Ptr++, &CurCharInfo->Char.UnicodeChar);
787 MultiByteToWideChar(CodePage, 0,
788 (PCHAR)Ptr++, 1,
789 &CurCharInfo->Char.UnicodeChar, 1);
790 }
791 else
792 {
793 CurCharInfo->Char.AsciiChar = *Ptr++;
794 }
795 CurCharInfo->Attributes = *Ptr++;
796 ++CurCharInfo;
797 }
798 }
799
800 ConSrvReleaseScreenBuffer(Buff, TRUE);
801
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;
806
807 return STATUS_SUCCESS;
808 }
809
810 CSR_API(SrvWriteConsole)
811 {
812 NTSTATUS Status;
813 PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
814
815 DPRINT("SrvWriteConsole\n");
816
817 if (!CsrValidateMessageBuffer(ApiMessage,
818 (PVOID)&WriteConsoleRequest->Buffer,
819 WriteConsoleRequest->BufferSize,
820 sizeof(BYTE)))
821 {
822 return STATUS_INVALID_PARAMETER;
823 }
824
825 Status = DoWriteConsole(ApiMessage,
826 CsrGetClientThread(),
827 TRUE);
828
829 if (Status == STATUS_PENDING)
830 *ReplyCode = CsrReplyPending;
831
832 return Status;
833 }
834
835 CSR_API(SrvWriteConsoleOutput)
836 {
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;
840 PCONSOLE Console;
841 PCONSOLE_SCREEN_BUFFER Buff;
842 SMALL_RECT ScreenBuffer;
843 CHAR_INFO* CurCharInfo;
844 SMALL_RECT WriteRegion;
845 CHAR_INFO* CharInfo;
846 COORD BufferCoord;
847 COORD BufferSize;
848 NTSTATUS Status;
849 PBYTE Ptr;
850
851 DPRINT("SrvWriteConsoleOutput\n");
852
853 BufferSize = WriteOutputRequest->BufferSize;
854 BufferCoord = WriteOutputRequest->BufferCoord;
855 CharInfo = WriteOutputRequest->CharInfo;
856
857 if (!CsrValidateMessageBuffer(ApiMessage,
858 (PVOID*)&WriteOutputRequest->CharInfo,
859 BufferSize.X * BufferSize.Y,
860 sizeof(CHAR_INFO)))
861 {
862 return STATUS_INVALID_PARAMETER;
863 }
864
865 Status = ConSrvGetScreenBuffer(ProcessData,
866 WriteOutputRequest->OutputHandle,
867 &Buff,
868 GENERIC_WRITE,
869 TRUE);
870 if (!NT_SUCCESS(Status)) return Status;
871
872 Console = Buff->Header.Console;
873
874 WriteRegion = WriteOutputRequest->WriteRegion;
875
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;
880
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))
884 {
885 ConSrvReleaseScreenBuffer(Buff, TRUE);
886
887 /* It is okay to have a WriteRegion completely outside the screen buffer.
888 No data is written then. */
889 return STATUS_SUCCESS;
890 }
891
892 for (i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++)
893 {
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++)
897 {
898 CHAR AsciiChar;
899 if (WriteOutputRequest->Unicode)
900 {
901 ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar);
902 }
903 else
904 {
905 AsciiChar = CurCharInfo->Char.AsciiChar;
906 }
907 *Ptr++ = AsciiChar;
908 *Ptr++ = (BYTE)CurCharInfo->Attributes;
909 CurCharInfo++;
910 }
911 }
912
913 ConioDrawRegion(Console, &WriteRegion);
914
915 ConSrvReleaseScreenBuffer(Buff, TRUE);
916
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;
921
922 return STATUS_SUCCESS;
923 }
924
925 CSR_API(SrvReadConsoleOutputString)
926 {
927 NTSTATUS Status;
928 PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputCodeRequest;
929 PCONSOLE Console;
930 PCONSOLE_SCREEN_BUFFER Buff;
931 USHORT CodeType;
932 SHORT Xpos, Ypos;
933 PVOID ReadBuffer;
934 DWORD i;
935 ULONG CodeSize;
936 BYTE Code;
937
938 DPRINT("SrvReadConsoleOutputString\n");
939
940 CodeType = ReadOutputCodeRequest->CodeType;
941 switch (CodeType)
942 {
943 case CODE_ASCII:
944 CodeSize = sizeof(CHAR);
945 break;
946
947 case CODE_UNICODE:
948 CodeSize = sizeof(WCHAR);
949 break;
950
951 case CODE_ATTRIBUTE:
952 CodeSize = sizeof(WORD);
953 break;
954
955 default:
956 return STATUS_INVALID_PARAMETER;
957 }
958
959 if (!CsrValidateMessageBuffer(ApiMessage,
960 (PVOID*)&ReadOutputCodeRequest->pCode.pCode,
961 ReadOutputCodeRequest->NumCodesToRead,
962 CodeSize))
963 {
964 return STATUS_INVALID_PARAMETER;
965 }
966
967 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ReadOutputCodeRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
968 if (!NT_SUCCESS(Status)) return Status;
969
970 Console = Buff->Header.Console;
971
972 ReadBuffer = ReadOutputCodeRequest->pCode.pCode;
973 Xpos = ReadOutputCodeRequest->ReadCoord.X;
974 Ypos = (ReadOutputCodeRequest->ReadCoord.Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y;
975
976 /*
977 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
978 *
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.
985 *
986 * TODO: Do NOT loop up to NumCodesToRead, but stop before
987 * if we are going to overflow...
988 */
989 for (i = 0; i < ReadOutputCodeRequest->NumCodesToRead; ++i)
990 {
991 Code = Buff->Buffer[2 * (Xpos + Ypos * Buff->ScreenBufferSize.X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)];
992
993 switch (CodeType)
994 {
995 case CODE_UNICODE:
996 ConsoleAnsiCharToUnicodeChar(Console, (PWCHAR)ReadBuffer, (PCHAR)&Code);
997 break;
998
999 case CODE_ASCII:
1000 *(PCHAR)ReadBuffer = (CHAR)Code;
1001 break;
1002
1003 case CODE_ATTRIBUTE:
1004 *(PWORD)ReadBuffer = (WORD)Code;
1005 break;
1006 }
1007 ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
1008
1009 Xpos++;
1010
1011 if (Xpos == Buff->ScreenBufferSize.X)
1012 {
1013 Xpos = 0;
1014 Ypos++;
1015
1016 if (Ypos == Buff->ScreenBufferSize.Y)
1017 {
1018 Ypos = 0;
1019 }
1020 }
1021 }
1022
1023 // switch (CodeType)
1024 // {
1025 // case CODE_UNICODE:
1026 // *(PWCHAR)ReadBuffer = 0;
1027 // break;
1028
1029 // case CODE_ASCII:
1030 // *(PCHAR)ReadBuffer = 0;
1031 // break;
1032
1033 // case CODE_ATTRIBUTE:
1034 // *(PWORD)ReadBuffer = 0;
1035 // break;
1036 // }
1037
1038 ReadOutputCodeRequest->EndCoord.X = Xpos;
1039 ReadOutputCodeRequest->EndCoord.Y = (Ypos - Buff->VirtualY + Buff->ScreenBufferSize.Y) % Buff->ScreenBufferSize.Y;
1040
1041 ConSrvReleaseScreenBuffer(Buff, TRUE);
1042
1043 ReadOutputCodeRequest->CodesRead = (DWORD)((ULONG_PTR)ReadBuffer - (ULONG_PTR)ReadOutputCodeRequest->pCode.pCode) / CodeSize;
1044 // <= ReadOutputCodeRequest->NumCodesToRead
1045
1046 return STATUS_SUCCESS;
1047 }
1048
1049 CSR_API(SrvWriteConsoleOutputString)
1050 {
1051 NTSTATUS Status;
1052 PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputCodeRequest;
1053 PCONSOLE Console;
1054 PCONSOLE_SCREEN_BUFFER Buff;
1055 USHORT CodeType;
1056 PBYTE Buffer; // PUCHAR
1057 PCHAR String, tmpString = NULL;
1058 DWORD X, Y, Length; // , Written = 0;
1059 ULONG CodeSize;
1060 SMALL_RECT UpdateRect;
1061
1062 DPRINT("SrvWriteConsoleOutputString\n");
1063
1064 CodeType = WriteOutputCodeRequest->CodeType;
1065 switch (CodeType)
1066 {
1067 case CODE_ASCII:
1068 CodeSize = sizeof(CHAR);
1069 break;
1070
1071 case CODE_UNICODE:
1072 CodeSize = sizeof(WCHAR);
1073 break;
1074
1075 case CODE_ATTRIBUTE:
1076 CodeSize = sizeof(WORD);
1077 break;
1078
1079 default:
1080 return STATUS_INVALID_PARAMETER;
1081 }
1082
1083 if (!CsrValidateMessageBuffer(ApiMessage,
1084 (PVOID*)&WriteOutputCodeRequest->pCode.pCode,
1085 WriteOutputCodeRequest->Length,
1086 CodeSize))
1087 {
1088 return STATUS_INVALID_PARAMETER;
1089 }
1090
1091 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1092 WriteOutputCodeRequest->OutputHandle,
1093 &Buff,
1094 GENERIC_WRITE,
1095 TRUE);
1096 if (!NT_SUCCESS(Status)) return Status;
1097
1098 Console = Buff->Header.Console;
1099
1100 switch (CodeType)
1101 {
1102 case CODE_UNICODE:
1103 {
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);
1109 if (String)
1110 {
1111 WideCharToMultiByte(Console->OutputCodePage, 0,
1112 (PWCHAR)WriteOutputCodeRequest->pCode.UnicodeChar,
1113 WriteOutputCodeRequest->Length,
1114 String, Length, NULL, NULL);
1115 }
1116 else
1117 {
1118 Status = STATUS_NO_MEMORY;
1119 }
1120
1121 break;
1122 }
1123
1124 case CODE_ASCII:
1125 String = (PCHAR)WriteOutputCodeRequest->pCode.AsciiChar;
1126 break;
1127
1128 case CODE_ATTRIBUTE:
1129 default:
1130 // *(ReadBuffer++) = Code;
1131 String = (PCHAR)WriteOutputCodeRequest->pCode.Attribute;
1132 break;
1133 }
1134
1135 if (String && NT_SUCCESS(Status))
1136 {
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)];
1141
1142 while (Length--)
1143 {
1144 *Buffer = *String++;
1145 // ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
1146 String = (PCHAR)((ULONG_PTR)String + CodeSize);
1147 // Written++;
1148 Buffer += 2;
1149 if (++X == Buff->ScreenBufferSize.X)
1150 {
1151 if (++Y == Buff->ScreenBufferSize.Y)
1152 {
1153 Y = 0;
1154 Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0);
1155 }
1156 X = 0;
1157 }
1158 }
1159
1160 if (Buff == Console->ActiveBuffer)
1161 {
1162 ConioComputeUpdateRect(Buff, &UpdateRect, &WriteOutputCodeRequest->Coord,
1163 WriteOutputCodeRequest->Length);
1164 ConioDrawRegion(Console, &UpdateRect);
1165 }
1166
1167 // WriteOutputCodeRequest->EndCoord.X = X;
1168 // WriteOutputCodeRequest->EndCoord.Y = (Y + Buff->ScreenBufferSize.Y - Buff->VirtualY) % Buff->ScreenBufferSize.Y;
1169 }
1170
1171 if (tmpString)
1172 {
1173 RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString);
1174 }
1175
1176 ConSrvReleaseScreenBuffer(Buff, TRUE);
1177
1178 // WriteOutputCodeRequest->NrCharactersWritten = Written;
1179 return Status;
1180 }
1181
1182 CSR_API(SrvFillConsoleOutput)
1183 {
1184 NTSTATUS Status;
1185 PCONSOLE_FILLOUTPUTCODE FillOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputRequest;
1186 PCONSOLE Console;
1187 PCONSOLE_SCREEN_BUFFER Buff;
1188 DWORD X, Y, Length; // , Written = 0;
1189 USHORT CodeType;
1190 BYTE Code;
1191 PBYTE Buffer;
1192 SMALL_RECT UpdateRect;
1193
1194 DPRINT("SrvFillConsoleOutput\n");
1195
1196 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), FillOutputRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1197 if (!NT_SUCCESS(Status)) return Status;
1198
1199 Console = Buff->Header.Console;
1200
1201 CodeType = FillOutputRequest->CodeType;
1202
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)];
1207
1208 switch (CodeType)
1209 {
1210 case CODE_ASCII:
1211 Code = (BYTE)FillOutputRequest->Code.AsciiChar;
1212 break;
1213
1214 case CODE_UNICODE:
1215 ConsoleUnicodeCharToAnsiChar(Console, (PCHAR)&Code, &FillOutputRequest->Code.UnicodeChar);
1216 break;
1217
1218 case CODE_ATTRIBUTE:
1219 Code = (BYTE)FillOutputRequest->Code.Attribute;
1220 break;
1221
1222 default:
1223 ConSrvReleaseScreenBuffer(Buff, TRUE);
1224 return STATUS_INVALID_PARAMETER;
1225 }
1226
1227 while (Length--)
1228 {
1229 *Buffer = Code;
1230 Buffer += 2;
1231 // Written++;
1232 if (++X == Buff->ScreenBufferSize.X)
1233 {
1234 if (++Y == Buff->ScreenBufferSize.Y)
1235 {
1236 Y = 0;
1237 Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0);
1238 }
1239 X = 0;
1240 }
1241 }
1242
1243 if (Buff == Console->ActiveBuffer)
1244 {
1245 ConioComputeUpdateRect(Buff, &UpdateRect, &FillOutputRequest->Coord,
1246 FillOutputRequest->Length);
1247 ConioDrawRegion(Console, &UpdateRect);
1248 }
1249
1250 ConSrvReleaseScreenBuffer(Buff, TRUE);
1251 /*
1252 Length = FillOutputRequest->Length;
1253 FillOutputRequest->NrCharactersWritten = Length;
1254 */
1255 return STATUS_SUCCESS;
1256 }
1257
1258 CSR_API(SrvGetConsoleCursorInfo)
1259 {
1260 NTSTATUS Status;
1261 PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
1262 PCONSOLE_SCREEN_BUFFER Buff;
1263
1264 DPRINT("SrvGetConsoleCursorInfo\n");
1265
1266 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
1267 if (!NT_SUCCESS(Status)) return Status;
1268
1269 CursorInfoRequest->Info.bVisible = Buff->CursorInfo.bVisible;
1270 CursorInfoRequest->Info.dwSize = Buff->CursorInfo.dwSize;
1271
1272 ConSrvReleaseScreenBuffer(Buff, TRUE);
1273 return STATUS_SUCCESS;
1274 }
1275
1276 CSR_API(SrvSetConsoleCursorInfo)
1277 {
1278 NTSTATUS Status;
1279 PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
1280 PCONSOLE Console;
1281 PCONSOLE_SCREEN_BUFFER Buff;
1282 DWORD Size;
1283 BOOL Visible;
1284
1285 DPRINT("SrvSetConsoleCursorInfo\n");
1286
1287 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1288 if (!NT_SUCCESS(Status)) return Status;
1289
1290 Console = Buff->Header.Console;
1291
1292 Size = CursorInfoRequest->Info.dwSize;
1293 Visible = CursorInfoRequest->Info.bVisible;
1294 if (Size < 1)
1295 {
1296 Size = 1;
1297 }
1298 if (100 < Size)
1299 {
1300 Size = 100;
1301 }
1302
1303 if ( (Size != Buff->CursorInfo.dwSize) ||
1304 (Visible && ! Buff->CursorInfo.bVisible) ||
1305 (! Visible && Buff->CursorInfo.bVisible) )
1306 {
1307 Buff->CursorInfo.dwSize = Size;
1308 Buff->CursorInfo.bVisible = Visible;
1309
1310 if (!ConioSetCursorInfo(Console, Buff))
1311 {
1312 ConSrvReleaseScreenBuffer(Buff, TRUE);
1313 return STATUS_UNSUCCESSFUL;
1314 }
1315 }
1316
1317 ConSrvReleaseScreenBuffer(Buff, TRUE);
1318 return STATUS_SUCCESS;
1319 }
1320
1321 CSR_API(SrvSetConsoleCursorPosition)
1322 {
1323 NTSTATUS Status;
1324 PCONSOLE_SETCURSORPOSITION SetCursorPositionRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorPositionRequest;
1325 PCONSOLE Console;
1326 PCONSOLE_SCREEN_BUFFER Buff;
1327 SHORT OldCursorX, OldCursorY;
1328 SHORT NewCursorX, NewCursorY;
1329
1330 DPRINT("SrvSetConsoleCursorPosition\n");
1331
1332 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetCursorPositionRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1333 if (!NT_SUCCESS(Status)) return Status;
1334
1335 Console = Buff->Header.Console;
1336
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 )
1341 {
1342 ConSrvReleaseScreenBuffer(Buff, TRUE);
1343 return STATUS_INVALID_PARAMETER;
1344 }
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)
1350 {
1351 if (!ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
1352 {
1353 ConSrvReleaseScreenBuffer(Buff, TRUE);
1354 return STATUS_UNSUCCESSFUL;
1355 }
1356 }
1357
1358 ConSrvReleaseScreenBuffer(Buff, TRUE);
1359 return STATUS_SUCCESS;
1360 }
1361
1362 CSR_API(SrvSetConsoleTextAttribute)
1363 {
1364 NTSTATUS Status;
1365 PCONSOLE_SETTEXTATTRIB SetTextAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetTextAttribRequest;
1366 PCONSOLE Console;
1367 PCONSOLE_SCREEN_BUFFER Buff;
1368
1369 DPRINT("SrvSetConsoleTextAttribute\n");
1370
1371 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetTextAttribRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1372 if (!NT_SUCCESS(Status)) return Status;
1373
1374 Console = Buff->Header.Console;
1375
1376 Buff->ScreenDefaultAttrib = SetTextAttribRequest->Attrib;
1377 if (Buff == Console->ActiveBuffer)
1378 {
1379 if (!ConioUpdateScreenInfo(Console, Buff))
1380 {
1381 ConSrvReleaseScreenBuffer(Buff, TRUE);
1382 return STATUS_UNSUCCESSFUL;
1383 }
1384 }
1385
1386 ConSrvReleaseScreenBuffer(Buff, TRUE);
1387 return STATUS_SUCCESS;
1388 }
1389
1390 CSR_API(SrvCreateConsoleScreenBuffer)
1391 {
1392 NTSTATUS Status;
1393 PCONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CreateScreenBufferRequest;
1394 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
1395 PCONSOLE Console;
1396 PCONSOLE_SCREEN_BUFFER Buff;
1397
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;
1404
1405 DPRINT("SrvCreateConsoleScreenBuffer\n");
1406
1407 Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
1408 if (!NT_SUCCESS(Status)) return Status;
1409
1410 /*
1411 if (Console->ActiveBuffer)
1412 {
1413 ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize;
1414 if (ScreenBufferSize.X == 0) ScreenBufferSize.X = 80;
1415 if (ScreenBufferSize.Y == 0) ScreenBufferSize.Y = 25;
1416
1417 ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib;
1418 PopupAttrib = Console->ActiveBuffer->PopupDefaultAttrib;
1419
1420 IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible;
1421 CursorSize = Console->ActiveBuffer->CursorInfo.dwSize;
1422 }
1423 */
1424
1425 // This is Windows' behaviour
1426 {
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;
1430
1431 if (Console->ActiveBuffer)
1432 {
1433 ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib;
1434 PopupAttrib = Console->ActiveBuffer->PopupDefaultAttrib;
1435 DisplayMode = Console->ActiveBuffer->DisplayMode;
1436
1437 IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible;
1438 CursorSize = Console->ActiveBuffer->CursorInfo.dwSize;
1439 }
1440 }
1441
1442 Status = ConSrvCreateScreenBuffer(Console,
1443 &Buff,
1444 ScreenBufferSize,
1445 ScreenAttrib,
1446 PopupAttrib,
1447 DisplayMode,
1448 IsCursorVisible,
1449 CursorSize);
1450 if (NT_SUCCESS(Status))
1451 {
1452 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
1453
1454 /* Insert the new handle inside the process handles table */
1455 Status = ConSrvInsertObject(ProcessData,
1456 &CreateScreenBufferRequest->OutputHandle,
1457 &Buff->Header,
1458 CreateScreenBufferRequest->Access,
1459 CreateScreenBufferRequest->Inheritable,
1460 CreateScreenBufferRequest->ShareMode);
1461
1462 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
1463 }
1464
1465 ConSrvReleaseConsole(Console, TRUE);
1466 return Status;
1467 }
1468
1469 CSR_API(SrvGetConsoleScreenBufferInfo)
1470 {
1471 NTSTATUS Status;
1472 PCONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScreenBufferInfoRequest;
1473 PCONSOLE Console;
1474 PCONSOLE_SCREEN_BUFFER Buff;
1475 PCONSOLE_SCREEN_BUFFER_INFO pInfo = &ScreenBufferInfoRequest->Info;
1476
1477 DPRINT("SrvGetConsoleScreenBufferInfo\n");
1478
1479 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ScreenBufferInfoRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
1480 if (!NT_SUCCESS(Status)) return Status;
1481
1482 Console = Buff->Header.Console;
1483
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;
1492
1493 ConSrvReleaseScreenBuffer(Buff, TRUE);
1494 return STATUS_SUCCESS;
1495 }
1496
1497 CSR_API(SrvSetConsoleActiveScreenBuffer)
1498 {
1499 NTSTATUS Status;
1500 PCONSOLE_SETACTIVESCREENBUFFER SetScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferRequest;
1501 PCONSOLE Console;
1502 PCONSOLE_SCREEN_BUFFER Buff;
1503
1504 DPRINT("SrvSetConsoleActiveScreenBuffer\n");
1505
1506 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetScreenBufferRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1507 if (!NT_SUCCESS(Status)) return Status;
1508
1509 Console = Buff->Header.Console;
1510
1511 if (Buff == Console->ActiveBuffer)
1512 {
1513 ConSrvReleaseScreenBuffer(Buff, TRUE);
1514 return STATUS_SUCCESS;
1515 }
1516
1517 /* If old buffer has no handles, it's now unreferenced */
1518 if (Console->ActiveBuffer->Header.HandleCount == 0)
1519 {
1520 ConioDeleteScreenBuffer(Console->ActiveBuffer);
1521 }
1522
1523 /* Tie console to new buffer */
1524 Console->ActiveBuffer = Buff;
1525
1526 /* Redraw the console */
1527 ConioDrawConsole(Console);
1528
1529 ConSrvReleaseScreenBuffer(Buff, TRUE);
1530 return STATUS_SUCCESS;
1531 }
1532
1533 CSR_API(SrvScrollConsoleScreenBuffer)
1534 {
1535 PCONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScrollScreenBufferRequest;
1536 PCONSOLE Console;
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;
1544 NTSTATUS Status;
1545 HANDLE OutputHandle;
1546 BOOLEAN UseClipRectangle;
1547 COORD DestinationOrigin;
1548 CHAR_INFO Fill;
1549 CHAR FillChar;
1550
1551 DPRINT("SrvScrollConsoleScreenBuffer\n");
1552
1553 OutputHandle = ScrollScreenBufferRequest->OutputHandle;
1554 UseClipRectangle = ScrollScreenBufferRequest->UseClipRectangle;
1555 DestinationOrigin = ScrollScreenBufferRequest->DestinationOrigin;
1556 Fill = ScrollScreenBufferRequest->Fill;
1557
1558 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1559 if (!NT_SUCCESS(Status)) return Status;
1560
1561 Console = Buff->Header.Console;
1562
1563 ScrollRectangle = ScrollScreenBufferRequest->ScrollRectangle;
1564
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))
1568 {
1569 ConSrvReleaseScreenBuffer(Buff, TRUE);
1570 return STATUS_SUCCESS;
1571 }
1572
1573 /* If the source was clipped on the left or top, adjust the destination accordingly */
1574 if (ScrollRectangle.Left < 0)
1575 {
1576 DestinationOrigin.X -= ScrollRectangle.Left;
1577 }
1578 if (ScrollRectangle.Top < 0)
1579 {
1580 DestinationOrigin.Y -= ScrollRectangle.Top;
1581 }
1582
1583 if (UseClipRectangle)
1584 {
1585 ClipRectangle = ScrollScreenBufferRequest->ClipRectangle;
1586 if (!ConioGetIntersection(&ClipRectangle, &ClipRectangle, &ScreenBuffer))
1587 {
1588 ConSrvReleaseScreenBuffer(Buff, TRUE);
1589 return STATUS_SUCCESS;
1590 }
1591 }
1592 else
1593 {
1594 ClipRectangle = ScreenBuffer;
1595 }
1596
1597 ConioInitRect(&DstRegion,
1598 DestinationOrigin.Y,
1599 DestinationOrigin.X,
1600 DestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
1601 DestinationOrigin.X + ConioRectWidth(&SrcRegion) - 1);
1602
1603 if (ScrollScreenBufferRequest->Unicode)
1604 ConsoleUnicodeCharToAnsiChar(Console, &FillChar, &Fill.Char.UnicodeChar);
1605 else
1606 FillChar = Fill.Char.AsciiChar;
1607
1608 ConioMoveRegion(Buff, &SrcRegion, &DstRegion, &ClipRectangle, Fill.Attributes << 8 | (BYTE)FillChar);
1609
1610 if (Buff == Console->ActiveBuffer)
1611 {
1612 ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
1613 if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &ClipRectangle))
1614 {
1615 /* Draw update region */
1616 ConioDrawRegion(Console, &UpdateRegion);
1617 }
1618 }
1619
1620 ConSrvReleaseScreenBuffer(Buff, TRUE);
1621 return STATUS_SUCCESS;
1622 }
1623
1624 CSR_API(SrvSetConsoleScreenBufferSize)
1625 {
1626 NTSTATUS Status;
1627 PCONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferSizeRequest;
1628 PCONSOLE_SCREEN_BUFFER Buff;
1629
1630 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetScreenBufferSizeRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1631 if (!NT_SUCCESS(Status)) return Status;
1632
1633 Status = ConioResizeBuffer(Buff->Header.Console, Buff, SetScreenBufferSizeRequest->Size);
1634
1635 ConSrvReleaseScreenBuffer(Buff, TRUE);
1636 return Status;
1637 }
1638
1639 /* EOF */