[KERNEL32]
[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 I/O functions
6 * PROGRAMMERS:
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "consrv.h"
12 #include "conio.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17
18 /* GLOBALS ********************************************************************/
19
20 #define ConioInitRect(Rect, top, left, bottom, right) \
21 do { \
22 ((Rect)->Top) = top; \
23 ((Rect)->Left) = left; \
24 ((Rect)->Bottom) = bottom; \
25 ((Rect)->Right) = right; \
26 } while(0)
27
28 #define ConioIsRectEmpty(Rect) \
29 (((Rect)->Left > (Rect)->Right) || ((Rect)->Top > (Rect)->Bottom))
30
31 #define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \
32 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
33
34 #define ConsoleAnsiCharToUnicodeChar(Console, dWChar, sChar) \
35 MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1)
36
37
38 /* PRIVATE FUNCTIONS **********************************************************/
39
40 PBYTE FASTCALL
41 ConioCoordToPointer(PCSRSS_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
42 {
43 return &Buff->Buffer[2 * (((Y + Buff->VirtualY) % Buff->MaxY) * Buff->MaxX + X)];
44 }
45
46 static VOID FASTCALL
47 ClearLineBuffer(PCSRSS_SCREEN_BUFFER Buff)
48 {
49 PBYTE Ptr = ConioCoordToPointer(Buff, 0, Buff->CurrentY);
50 UINT Pos;
51
52 for (Pos = 0; Pos < Buff->MaxX; Pos++)
53 {
54 /* Fill the cell */
55 *Ptr++ = ' ';
56 *Ptr++ = Buff->DefaultAttrib;
57 }
58 }
59
60 NTSTATUS FASTCALL
61 CsrInitConsoleScreenBuffer(PCSRSS_CONSOLE Console,
62 PCSRSS_SCREEN_BUFFER Buffer)
63 {
64 DPRINT("CsrInitConsoleScreenBuffer Size X %d Size Y %d\n", Buffer->MaxX, Buffer->MaxY);
65
66 Buffer->Header.Type = CONIO_SCREEN_BUFFER_MAGIC;
67 Buffer->Header.Console = Console;
68 Buffer->Header.HandleCount = 0;
69 Buffer->ShowX = 0;
70 Buffer->ShowY = 0;
71 Buffer->VirtualY = 0;
72 Buffer->Buffer = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, Buffer->MaxX * Buffer->MaxY * 2);
73 if (NULL == Buffer->Buffer)
74 {
75 return STATUS_INSUFFICIENT_RESOURCES;
76 }
77 ConioInitScreenBuffer(Console, Buffer);
78 /* initialize buffer to be empty with default attributes */
79 for (Buffer->CurrentY = 0 ; Buffer->CurrentY < Buffer->MaxY; Buffer->CurrentY++)
80 {
81 ClearLineBuffer(Buffer);
82 }
83 Buffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
84 Buffer->CurrentX = 0;
85 Buffer->CurrentY = 0;
86
87 InsertHeadList(&Console->BufferList, &Buffer->ListEntry);
88 return STATUS_SUCCESS;
89 }
90
91 static VOID FASTCALL
92 ConioNextLine(PCSRSS_SCREEN_BUFFER Buff, SMALL_RECT *UpdateRect, UINT *ScrolledLines)
93 {
94 /* If we hit bottom, slide the viewable screen */
95 if (++Buff->CurrentY == Buff->MaxY)
96 {
97 Buff->CurrentY--;
98 if (++Buff->VirtualY == Buff->MaxY)
99 {
100 Buff->VirtualY = 0;
101 }
102 (*ScrolledLines)++;
103 ClearLineBuffer(Buff);
104 if (UpdateRect->Top != 0)
105 {
106 UpdateRect->Top--;
107 }
108 }
109 UpdateRect->Left = 0;
110 UpdateRect->Right = Buff->MaxX - 1;
111 UpdateRect->Bottom = Buff->CurrentY;
112 }
113
114 NTSTATUS FASTCALL
115 ConioWriteConsole(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff,
116 CHAR *Buffer, DWORD Length, BOOL Attrib)
117 {
118 UINT i;
119 PBYTE Ptr;
120 SMALL_RECT UpdateRect;
121 LONG CursorStartX, CursorStartY;
122 UINT ScrolledLines;
123
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;
130 ScrolledLines = 0;
131
132 for (i = 0; i < Length; i++)
133 {
134 if (Buff->Mode & ENABLE_PROCESSED_OUTPUT)
135 {
136 /* --- LF --- */
137 if (Buffer[i] == '\n')
138 {
139 Buff->CurrentX = 0;
140 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
141 continue;
142 }
143 /* --- BS --- */
144 else if (Buffer[i] == '\b')
145 {
146 /* Only handle BS if we're not on the first pos of the first line */
147 if (0 != Buff->CurrentX || 0 != Buff->CurrentY)
148 {
149 if (0 == Buff->CurrentX)
150 {
151 /* slide virtual position up */
152 Buff->CurrentX = Buff->MaxX - 1;
153 Buff->CurrentY--;
154 UpdateRect.Top = min(UpdateRect.Top, (LONG)Buff->CurrentY);
155 }
156 else
157 {
158 Buff->CurrentX--;
159 }
160 Ptr = ConioCoordToPointer(Buff, Buff->CurrentX, Buff->CurrentY);
161 Ptr[0] = ' ';
162 Ptr[1] = Buff->DefaultAttrib;
163 UpdateRect.Left = min(UpdateRect.Left, (LONG) Buff->CurrentX);
164 UpdateRect.Right = max(UpdateRect.Right, (LONG) Buff->CurrentX);
165 }
166 continue;
167 }
168 /* --- CR --- */
169 else if (Buffer[i] == '\r')
170 {
171 Buff->CurrentX = 0;
172 UpdateRect.Left = min(UpdateRect.Left, (LONG) Buff->CurrentX);
173 UpdateRect.Right = max(UpdateRect.Right, (LONG) Buff->CurrentX);
174 continue;
175 }
176 /* --- TAB --- */
177 else if (Buffer[i] == '\t')
178 {
179 UINT EndX;
180
181 UpdateRect.Left = min(UpdateRect.Left, (LONG)Buff->CurrentX);
182 EndX = (Buff->CurrentX + 8) & ~7;
183 if (EndX > Buff->MaxX)
184 {
185 EndX = Buff->MaxX;
186 }
187 Ptr = ConioCoordToPointer(Buff, Buff->CurrentX, Buff->CurrentY);
188 while (Buff->CurrentX < EndX)
189 {
190 *Ptr++ = ' ';
191 *Ptr++ = Buff->DefaultAttrib;
192 Buff->CurrentX++;
193 }
194 UpdateRect.Right = max(UpdateRect.Right, (LONG) Buff->CurrentX - 1);
195 if (Buff->CurrentX == Buff->MaxX)
196 {
197 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
198 {
199 Buff->CurrentX = 0;
200 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
201 }
202 else
203 {
204 Buff->CurrentX--;
205 }
206 }
207 continue;
208 }
209 }
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);
213 Ptr[0] = Buffer[i];
214 if (Attrib)
215 {
216 Ptr[1] = Buff->DefaultAttrib;
217 }
218 Buff->CurrentX++;
219 if (Buff->CurrentX == Buff->MaxX)
220 {
221 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
222 {
223 Buff->CurrentX = 0;
224 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
225 }
226 else
227 {
228 Buff->CurrentX = CursorStartX;
229 }
230 }
231 }
232
233 if (!ConioIsRectEmpty(&UpdateRect) && Buff == Console->ActiveBuffer)
234 {
235 ConioWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY, ScrolledLines,
236 Buffer, Length);
237 }
238
239 return STATUS_SUCCESS;
240 }
241
242 __inline BOOLEAN ConioGetIntersection(
243 SMALL_RECT *Intersection,
244 SMALL_RECT *Rect1,
245 SMALL_RECT *Rect2)
246 {
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))
253 {
254 /* The rectangles do not intersect */
255 ConioInitRect(Intersection, 0, -1, 0, -1);
256 return FALSE;
257 }
258
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));
264
265 return TRUE;
266 }
267
268 __inline BOOLEAN ConioGetUnion(
269 SMALL_RECT *Union,
270 SMALL_RECT *Rect1,
271 SMALL_RECT *Rect2)
272 {
273 if (ConioIsRectEmpty(Rect1))
274 {
275 if (ConioIsRectEmpty(Rect2))
276 {
277 ConioInitRect(Union, 0, -1, 0, -1);
278 return FALSE;
279 }
280 else
281 {
282 *Union = *Rect2;
283 }
284 }
285 else if (ConioIsRectEmpty(Rect2))
286 {
287 *Union = *Rect1;
288 }
289 else
290 {
291 ConioInitRect(Union,
292 min(Rect1->Top, Rect2->Top),
293 min(Rect1->Left, Rect2->Left),
294 max(Rect1->Bottom, Rect2->Bottom),
295 max(Rect1->Right, Rect2->Right));
296 }
297
298 return TRUE;
299 }
300
301 /*
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.
304 */
305 static VOID FASTCALL
306 ConioMoveRegion(PCSRSS_SCREEN_BUFFER ScreenBuffer,
307 SMALL_RECT *SrcRegion,
308 SMALL_RECT *DstRegion,
309 SMALL_RECT *ClipRegion,
310 WORD Fill)
311 {
312 int Width = ConioRectWidth(SrcRegion);
313 int Height = ConioRectHeight(SrcRegion);
314 int SX, SY;
315 int DX, DY;
316 int XDelta, YDelta;
317 int i, j;
318
319 SY = SrcRegion->Top;
320 DY = DstRegion->Top;
321 YDelta = 1;
322 if (SY < DY)
323 {
324 /* Moving down: work from bottom up */
325 SY = SrcRegion->Bottom;
326 DY = DstRegion->Bottom;
327 YDelta = -1;
328 }
329 for (i = 0; i < Height; i++)
330 {
331 PWORD SRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, SY);
332 PWORD DRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, DY);
333
334 SX = SrcRegion->Left;
335 DX = DstRegion->Left;
336 XDelta = 1;
337 if (SX < DX)
338 {
339 /* Moving right: work from right to left */
340 SX = SrcRegion->Right;
341 DX = DstRegion->Right;
342 XDelta = -1;
343 }
344 for (j = 0; j < Width; j++)
345 {
346 WORD Cell = SRow[SX];
347 if (SX >= ClipRegion->Left && SX <= ClipRegion->Right
348 && SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
349 {
350 SRow[SX] = Fill;
351 }
352 if (DX >= ClipRegion->Left && DX <= ClipRegion->Right
353 && DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
354 {
355 DRow[DX] = Cell;
356 }
357 SX += XDelta;
358 DX += XDelta;
359 }
360 SY += YDelta;
361 DY += YDelta;
362 }
363 }
364
365 VOID WINAPI
366 ConioDeleteScreenBuffer(PCSRSS_SCREEN_BUFFER Buffer)
367 {
368 PCSRSS_CONSOLE Console = Buffer->Header.Console;
369
370 RemoveEntryList(&Buffer->ListEntry);
371 if (Buffer == Console->ActiveBuffer)
372 {
373 /* Deleted active buffer; switch to most recently created */
374 Console->ActiveBuffer = NULL;
375 if (!IsListEmpty(&Console->BufferList))
376 {
377 Console->ActiveBuffer = CONTAINING_RECORD(Console->BufferList.Flink, CSRSS_SCREEN_BUFFER, ListEntry);
378 ConioDrawConsole(Console);
379 }
380 }
381
382 HeapFree(ConSrvHeap, 0, Buffer->Buffer);
383 HeapFree(ConSrvHeap, 0, Buffer);
384 }
385
386 VOID FASTCALL
387 ConioDrawConsole(PCSRSS_CONSOLE Console)
388 {
389 SMALL_RECT Region;
390
391 ConioInitRect(&Region, 0, 0, Console->Size.Y - 1, Console->Size.X - 1);
392
393 ConioDrawRegion(Console, &Region);
394 }
395
396 static VOID FASTCALL
397 ConioComputeUpdateRect(PCSRSS_SCREEN_BUFFER Buff, SMALL_RECT *UpdateRect, COORD *Start, UINT Length)
398 {
399 if (Buff->MaxX <= Start->X + Length)
400 {
401 UpdateRect->Left = 0;
402 }
403 else
404 {
405 UpdateRect->Left = Start->X;
406 }
407 if (Buff->MaxX <= Start->X + Length)
408 {
409 UpdateRect->Right = Buff->MaxX - 1;
410 }
411 else
412 {
413 UpdateRect->Right = Start->X + Length - 1;
414 }
415 UpdateRect->Top = Start->Y;
416 UpdateRect->Bottom = Start->Y+ (Start->X + Length - 1) / Buff->MaxX;
417 if (Buff->MaxY <= UpdateRect->Bottom)
418 {
419 UpdateRect->Bottom = Buff->MaxY - 1;
420 }
421 }
422
423 DWORD FASTCALL
424 ConioEffectiveCursorSize(PCSRSS_CONSOLE Console, DWORD Scale)
425 {
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);
430 return Size;
431 }
432
433 static NTSTATUS
434 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
435 IN PCSR_THREAD ClientThread,
436 IN BOOL CreateWaitBlock OPTIONAL);
437
438 // Wait function CSR_WAIT_FUNCTION
439 static BOOLEAN
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,
446 IN ULONG WaitFlags)
447 {
448 NTSTATUS Status;
449
450 DPRINT("WriteConsoleThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
451
452 /*
453 * If we are called via CsrNotifyWaitBlock by a call to
454 * CsrDestroyProcess or CsrDestroyThread, just return.
455 */
456 if (WaitFlags & CsrProcessTerminating)
457 {
458 Status = STATUS_THREAD_IS_TERMINATING;
459 goto Quit;
460 }
461
462 Status = DoWriteConsole(WaitApiMessage,
463 WaitThread,
464 FALSE);
465
466 Quit:
467 if (Status != STATUS_PENDING)
468 {
469 WaitApiMessage->Status = Status;
470 }
471
472 return (Status == STATUS_PENDING ? FALSE : TRUE);
473 }
474
475 static NTSTATUS
476 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
477 IN PCSR_THREAD ClientThread,
478 IN BOOL CreateWaitBlock OPTIONAL)
479 {
480 NTSTATUS Status = STATUS_SUCCESS;
481 PCSRSS_WRITE_CONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
482 PCSRSS_CONSOLE Console;
483 PCSRSS_SCREEN_BUFFER Buff;
484 PCHAR Buffer;
485 DWORD Written = 0;
486 ULONG Length;
487
488 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(ClientThread->Process), WriteConsoleRequest->ConsoleHandle, &Buff, GENERIC_WRITE);
489 if (!NT_SUCCESS(Status)) return Status;
490
491 Console = Buff->Header.Console;
492
493 // if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION))
494 if (Console->PauseFlags && Console->UnpauseEvent != NULL)
495 {
496 if (CreateWaitBlock)
497 {
498 if (!CsrCreateWait(&Console->WriteWaitQueue,
499 WriteConsoleThread,
500 ClientThread,
501 ApiMessage,
502 NULL,
503 NULL))
504 {
505 /* Fail */
506 ConioUnlockScreenBuffer(Buff);
507 return STATUS_NO_MEMORY;
508 }
509 }
510
511 /* Wait until we un-pause the console */
512 Status = STATUS_PENDING;
513 }
514 else
515 {
516 if(WriteConsoleRequest->Unicode)
517 {
518 Length = WideCharToMultiByte(Console->OutputCodePage, 0,
519 (PWCHAR)WriteConsoleRequest->Buffer,
520 WriteConsoleRequest->NrCharactersToWrite,
521 NULL, 0, NULL, NULL);
522 Buffer = RtlAllocateHeap(GetProcessHeap(), 0, Length);
523 if (Buffer)
524 {
525 WideCharToMultiByte(Console->OutputCodePage, 0,
526 (PWCHAR)WriteConsoleRequest->Buffer,
527 WriteConsoleRequest->NrCharactersToWrite,
528 Buffer, Length, NULL, NULL);
529 }
530 else
531 {
532 Status = STATUS_NO_MEMORY;
533 }
534 }
535 else
536 {
537 Buffer = (PCHAR)WriteConsoleRequest->Buffer;
538 }
539
540 if (Buffer)
541 {
542 if (NT_SUCCESS(Status))
543 {
544 Status = ConioWriteConsole(Console, Buff, Buffer,
545 WriteConsoleRequest->NrCharactersToWrite, TRUE);
546 if (NT_SUCCESS(Status))
547 {
548 Written = WriteConsoleRequest->NrCharactersToWrite;
549 }
550 }
551 if (WriteConsoleRequest->Unicode)
552 {
553 RtlFreeHeap(GetProcessHeap(), 0, Buffer);
554 }
555 }
556
557 WriteConsoleRequest->NrCharactersWritten = Written;
558 }
559
560 ConioUnlockScreenBuffer(Buff);
561 return Status;
562 }
563
564
565 /* PUBLIC APIS ****************************************************************/
566
567 CSR_API(SrvReadConsoleOutput)
568 {
569 PCSRSS_READ_CONSOLE_OUTPUT ReadConsoleOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleOutputRequest;
570 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
571 PCHAR_INFO CharInfo;
572 PCHAR_INFO CurCharInfo;
573 PCSRSS_SCREEN_BUFFER Buff;
574 DWORD SizeX, SizeY;
575 NTSTATUS Status;
576 COORD BufferSize;
577 COORD BufferCoord;
578 SMALL_RECT ReadRegion;
579 SMALL_RECT ScreenRect;
580 DWORD i;
581 PBYTE Ptr;
582 LONG X, Y;
583 UINT CodePage;
584
585 DPRINT("SrvReadConsoleOutput\n");
586
587 CharInfo = ReadConsoleOutputRequest->CharInfo;
588 ReadRegion = ReadConsoleOutputRequest->ReadRegion;
589 BufferSize = ReadConsoleOutputRequest->BufferSize;
590 BufferCoord = ReadConsoleOutputRequest->BufferCoord;
591
592 if (!CsrValidateMessageBuffer(ApiMessage,
593 (PVOID*)&ReadConsoleOutputRequest->CharInfo,
594 BufferSize.X * BufferSize.Y,
595 sizeof(CHAR_INFO)))
596 {
597 return STATUS_INVALID_PARAMETER;
598 }
599
600 Status = ConioLockScreenBuffer(ProcessData, ReadConsoleOutputRequest->ConsoleHandle, &Buff, GENERIC_READ);
601 if (!NT_SUCCESS(Status)) return Status;
602
603 /* FIXME: Is this correct? */
604 CodePage = ProcessData->Console->OutputCodePage;
605
606 SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&ReadRegion));
607 SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&ReadRegion));
608 ReadRegion.Bottom = ReadRegion.Top + SizeY;
609 ReadRegion.Right = ReadRegion.Left + SizeX;
610
611 ConioInitRect(&ScreenRect, 0, 0, Buff->MaxY, Buff->MaxX);
612 if (!ConioGetIntersection(&ReadRegion, &ScreenRect, &ReadRegion))
613 {
614 ConioUnlockScreenBuffer(Buff);
615 return STATUS_SUCCESS;
616 }
617
618 for (i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y)
619 {
620 CurCharInfo = CharInfo + (i * BufferSize.X);
621
622 Ptr = ConioCoordToPointer(Buff, ReadRegion.Left, Y);
623 for (X = ReadRegion.Left; X < ReadRegion.Right; ++X)
624 {
625 if (ReadConsoleOutputRequest->Unicode)
626 {
627 // ConsoleAnsiCharToUnicodeChar(ProcessData->Console, (PCHAR)Ptr++, &CurCharInfo->Char.UnicodeChar);
628 MultiByteToWideChar(CodePage, 0,
629 (PCHAR)Ptr++, 1,
630 &CurCharInfo->Char.UnicodeChar, 1);
631 }
632 else
633 {
634 CurCharInfo->Char.AsciiChar = *Ptr++;
635 }
636 CurCharInfo->Attributes = *Ptr++;
637 ++CurCharInfo;
638 }
639 }
640
641 ConioUnlockScreenBuffer(Buff);
642
643 ReadConsoleOutputRequest->ReadRegion.Right = ReadRegion.Left + SizeX - 1;
644 ReadConsoleOutputRequest->ReadRegion.Bottom = ReadRegion.Top + SizeY - 1;
645 ReadConsoleOutputRequest->ReadRegion.Left = ReadRegion.Left;
646 ReadConsoleOutputRequest->ReadRegion.Top = ReadRegion.Top;
647
648 return STATUS_SUCCESS;
649 }
650
651 CSR_API(SrvWriteConsole)
652 {
653 NTSTATUS Status;
654 PCSRSS_WRITE_CONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
655
656 DPRINT("SrvWriteConsole\n");
657
658 if (!CsrValidateMessageBuffer(ApiMessage,
659 (PVOID)&WriteConsoleRequest->Buffer,
660 WriteConsoleRequest->BufferSize,
661 sizeof(BYTE)))
662 {
663 return STATUS_INVALID_PARAMETER;
664 }
665
666 Status = DoWriteConsole(ApiMessage,
667 CsrGetClientThread(),
668 TRUE);
669
670 if (Status == STATUS_PENDING)
671 *ReplyCode = CsrReplyPending;
672
673 return Status;
674 }
675
676 CSR_API(SrvWriteConsoleOutput)
677 {
678 PCSRSS_WRITE_CONSOLE_OUTPUT WriteConsoleOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleOutputRequest;
679 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
680 SHORT i, X, Y, SizeX, SizeY;
681 PCSRSS_CONSOLE Console;
682 PCSRSS_SCREEN_BUFFER Buff;
683 SMALL_RECT ScreenBuffer;
684 CHAR_INFO* CurCharInfo;
685 SMALL_RECT WriteRegion;
686 CHAR_INFO* CharInfo;
687 COORD BufferCoord;
688 COORD BufferSize;
689 NTSTATUS Status;
690 PBYTE Ptr;
691
692 DPRINT("SrvWriteConsoleOutput\n");
693
694 BufferSize = WriteConsoleOutputRequest->BufferSize;
695 BufferCoord = WriteConsoleOutputRequest->BufferCoord;
696 CharInfo = WriteConsoleOutputRequest->CharInfo;
697
698 if (!CsrValidateMessageBuffer(ApiMessage,
699 (PVOID*)&WriteConsoleOutputRequest->CharInfo,
700 BufferSize.X * BufferSize.Y,
701 sizeof(CHAR_INFO)))
702 {
703 return STATUS_INVALID_PARAMETER;
704 }
705
706 Status = ConioLockScreenBuffer(ProcessData,
707 WriteConsoleOutputRequest->ConsoleHandle,
708 &Buff,
709 GENERIC_WRITE);
710 if (!NT_SUCCESS(Status)) return Status;
711
712 Console = Buff->Header.Console;
713
714 WriteRegion = WriteConsoleOutputRequest->WriteRegion;
715
716 SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&WriteRegion));
717 SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&WriteRegion));
718 WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
719 WriteRegion.Right = WriteRegion.Left + SizeX - 1;
720
721 /* Make sure WriteRegion is inside the screen buffer */
722 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
723 if (!ConioGetIntersection(&WriteRegion, &ScreenBuffer, &WriteRegion))
724 {
725 ConioUnlockScreenBuffer(Buff);
726
727 /* It is okay to have a WriteRegion completely outside the screen buffer.
728 No data is written then. */
729 return STATUS_SUCCESS;
730 }
731
732 for (i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++)
733 {
734 CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
735 Ptr = ConioCoordToPointer(Buff, WriteRegion.Left, Y);
736 for (X = WriteRegion.Left; X <= WriteRegion.Right; X++)
737 {
738 CHAR AsciiChar;
739 if (WriteConsoleOutputRequest->Unicode)
740 {
741 ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar);
742 }
743 else
744 {
745 AsciiChar = CurCharInfo->Char.AsciiChar;
746 }
747 *Ptr++ = AsciiChar;
748 *Ptr++ = CurCharInfo->Attributes;
749 CurCharInfo++;
750 }
751 }
752
753 ConioDrawRegion(Console, &WriteRegion);
754
755 ConioUnlockScreenBuffer(Buff);
756
757 WriteConsoleOutputRequest->WriteRegion.Right = WriteRegion.Left + SizeX - 1;
758 WriteConsoleOutputRequest->WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
759 WriteConsoleOutputRequest->WriteRegion.Left = WriteRegion.Left;
760 WriteConsoleOutputRequest->WriteRegion.Top = WriteRegion.Top;
761
762 return STATUS_SUCCESS;
763 }
764
765 CSR_API(SrvReadConsoleOutputString)
766 {
767 NTSTATUS Status;
768 PCSRSS_READ_CONSOLE_OUTPUT_CODE ReadConsoleOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleOutputCodeRequest;
769 PCSRSS_CONSOLE Console;
770 PCSRSS_SCREEN_BUFFER Buff;
771 USHORT CodeType;
772 DWORD Xpos, Ypos;
773 PVOID ReadBuffer;
774 DWORD i;
775 ULONG CodeSize;
776 BYTE Code;
777
778 DPRINT("SrvReadConsoleOutputString\n");
779
780 CodeType = ReadConsoleOutputCodeRequest->CodeType;
781 switch (CodeType)
782 {
783 case CODE_ASCII:
784 CodeSize = sizeof(CHAR);
785 break;
786
787 case CODE_UNICODE:
788 CodeSize = sizeof(WCHAR);
789 break;
790
791 case CODE_ATTRIBUTE:
792 CodeSize = sizeof(WORD);
793 break;
794
795 default:
796 return STATUS_INVALID_PARAMETER;
797 }
798
799 if (!CsrValidateMessageBuffer(ApiMessage,
800 (PVOID*)&ReadConsoleOutputCodeRequest->pCode.pCode,
801 ReadConsoleOutputCodeRequest->NumCodesToRead,
802 CodeSize))
803 {
804 return STATUS_INVALID_PARAMETER;
805 }
806
807 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ReadConsoleOutputCodeRequest->ConsoleHandle, &Buff, GENERIC_READ);
808 if (!NT_SUCCESS(Status)) return Status;
809
810 Console = Buff->Header.Console;
811
812 ReadBuffer = ReadConsoleOutputCodeRequest->pCode.pCode;
813 Xpos = ReadConsoleOutputCodeRequest->ReadCoord.X;
814 Ypos = (ReadConsoleOutputCodeRequest->ReadCoord.Y + Buff->VirtualY) % Buff->MaxY;
815
816 /*
817 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
818 *
819 * If the number of attributes (resp. characters) to be read from extends
820 * beyond the end of the specified screen buffer row, attributes (resp.
821 * characters) are read from the next row. If the number of attributes
822 * (resp. characters) to be read from extends beyond the end of the console
823 * screen buffer, attributes (resp. characters) up to the end of the console
824 * screen buffer are read.
825 *
826 * TODO: Do NOT loop up to NumCodesToRead, but stop before
827 * if we are going to overflow...
828 */
829 for (i = 0; i < ReadConsoleOutputCodeRequest->NumCodesToRead; ++i)
830 {
831 Code = Buff->Buffer[2 * (Xpos + Ypos * Buff->MaxX) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)];
832
833 switch (CodeType)
834 {
835 case CODE_UNICODE:
836 ConsoleAnsiCharToUnicodeChar(Console, (PWCHAR)ReadBuffer, (PCHAR)&Code);
837 break;
838
839 case CODE_ASCII:
840 *(PCHAR)ReadBuffer = (CHAR)Code;
841 break;
842
843 case CODE_ATTRIBUTE:
844 *(PWORD)ReadBuffer = (WORD)Code;
845 break;
846 }
847 ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
848
849 Xpos++;
850
851 if (Xpos == Buff->MaxX)
852 {
853 Xpos = 0;
854 Ypos++;
855
856 if (Ypos == Buff->MaxY)
857 {
858 Ypos = 0;
859 }
860 }
861 }
862
863 switch (CodeType)
864 {
865 case CODE_UNICODE:
866 *(PWCHAR)ReadBuffer = 0;
867 break;
868
869 case CODE_ASCII:
870 *(PCHAR)ReadBuffer = 0;
871 break;
872
873 case CODE_ATTRIBUTE:
874 *(PWORD)ReadBuffer = 0;
875 break;
876 }
877
878 ReadConsoleOutputCodeRequest->EndCoord.X = Xpos;
879 ReadConsoleOutputCodeRequest->EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
880
881 ConioUnlockScreenBuffer(Buff);
882
883 ReadConsoleOutputCodeRequest->CodesRead = (DWORD)((ULONG_PTR)ReadBuffer - (ULONG_PTR)ReadConsoleOutputCodeRequest->pCode.pCode) / CodeSize;
884 // <= ReadConsoleOutputCodeRequest->NumCodesToRead
885
886 return STATUS_SUCCESS;
887 }
888
889 CSR_API(SrvWriteConsoleOutputString)
890 {
891 NTSTATUS Status;
892 PCSRSS_WRITE_CONSOLE_OUTPUT_CODE WriteConsoleOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleOutputCodeRequest;
893 PCSRSS_CONSOLE Console;
894 PCSRSS_SCREEN_BUFFER Buff;
895 USHORT CodeType;
896 PBYTE Buffer; // PUCHAR
897 PCHAR String, tmpString = NULL;
898 DWORD X, Y, Length; // , Written = 0;
899 ULONG CodeSize;
900 SMALL_RECT UpdateRect;
901
902 DPRINT("SrvWriteConsoleOutputString\n");
903
904 CodeType = WriteConsoleOutputCodeRequest->CodeType;
905 switch (CodeType)
906 {
907 case CODE_ASCII:
908 CodeSize = sizeof(CHAR);
909 break;
910
911 case CODE_UNICODE:
912 CodeSize = sizeof(WCHAR);
913 break;
914
915 case CODE_ATTRIBUTE:
916 CodeSize = sizeof(WORD);
917 break;
918
919 default:
920 return STATUS_INVALID_PARAMETER;
921 }
922
923 if (!CsrValidateMessageBuffer(ApiMessage,
924 (PVOID*)&WriteConsoleOutputCodeRequest->pCode.pCode,
925 WriteConsoleOutputCodeRequest->Length,
926 CodeSize))
927 {
928 return STATUS_INVALID_PARAMETER;
929 }
930
931 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
932 WriteConsoleOutputCodeRequest->ConsoleHandle,
933 &Buff,
934 GENERIC_WRITE);
935 if (!NT_SUCCESS(Status)) return Status;
936
937 Console = Buff->Header.Console;
938
939 switch (CodeType)
940 {
941 case CODE_UNICODE:
942 {
943 Length = WideCharToMultiByte(Console->OutputCodePage, 0,
944 (PWCHAR)WriteConsoleOutputCodeRequest->pCode.UnicodeChar,
945 WriteConsoleOutputCodeRequest->Length,
946 NULL, 0, NULL, NULL);
947 tmpString = String = RtlAllocateHeap(GetProcessHeap(), 0, Length);
948 if (String)
949 {
950 WideCharToMultiByte(Console->OutputCodePage, 0,
951 (PWCHAR)WriteConsoleOutputCodeRequest->pCode.UnicodeChar,
952 WriteConsoleOutputCodeRequest->Length,
953 String, Length, NULL, NULL);
954 }
955 else
956 {
957 Status = STATUS_NO_MEMORY;
958 }
959
960 break;
961 }
962
963 case CODE_ASCII:
964 String = (PCHAR)WriteConsoleOutputCodeRequest->pCode.AsciiChar;
965 break;
966
967 case CODE_ATTRIBUTE:
968 default:
969 // *(ReadBuffer++) = Code;
970 String = (PCHAR)WriteConsoleOutputCodeRequest->pCode.Attribute;
971 break;
972 }
973
974 if (String && NT_SUCCESS(Status))
975 {
976 X = WriteConsoleOutputCodeRequest->Coord.X;
977 Y = (WriteConsoleOutputCodeRequest->Coord.Y + Buff->VirtualY) % Buff->MaxY;
978 Length = WriteConsoleOutputCodeRequest->Length;
979 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)];
980
981 while (Length--)
982 {
983 *Buffer = *String++;
984 // ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
985 String = (PCHAR)((ULONG_PTR)String + CodeSize);
986 // Written++;
987 Buffer += 2;
988 if (++X == Buff->MaxX)
989 {
990 if (++Y == Buff->MaxY)
991 {
992 Y = 0;
993 Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0);
994 }
995 X = 0;
996 }
997 }
998
999 if (Buff == Console->ActiveBuffer)
1000 {
1001 ConioComputeUpdateRect(Buff, &UpdateRect, &WriteConsoleOutputCodeRequest->Coord,
1002 WriteConsoleOutputCodeRequest->Length);
1003 ConioDrawRegion(Console, &UpdateRect);
1004 }
1005
1006 WriteConsoleOutputCodeRequest->EndCoord.X = X;
1007 WriteConsoleOutputCodeRequest->EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
1008 }
1009
1010 if (tmpString)
1011 {
1012 RtlFreeHeap(GetProcessHeap(), 0, tmpString);
1013 }
1014
1015 ConioUnlockScreenBuffer(Buff);
1016
1017 // WriteConsoleOutputCodeRequest->NrCharactersWritten = Written;
1018 return Status;
1019 }
1020
1021 CSR_API(SrvFillConsoleOutput)
1022 {
1023 NTSTATUS Status;
1024 PCSRSS_FILL_OUTPUT FillOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputRequest;
1025 PCSRSS_CONSOLE Console;
1026 PCSRSS_SCREEN_BUFFER Buff;
1027 DWORD X, Y, Length; // , Written = 0;
1028 USHORT CodeType;
1029 BYTE Code;
1030 PBYTE Buffer;
1031 SMALL_RECT UpdateRect;
1032
1033 DPRINT("SrvFillConsoleOutput\n");
1034
1035 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), FillOutputRequest->ConsoleHandle, &Buff, GENERIC_WRITE);
1036 if (!NT_SUCCESS(Status)) return Status;
1037
1038 Console = Buff->Header.Console;
1039
1040 CodeType = FillOutputRequest->CodeType;
1041
1042 X = FillOutputRequest->Coord.X;
1043 Y = (FillOutputRequest->Coord.Y + Buff->VirtualY) % Buff->MaxY;
1044 Length = FillOutputRequest->Length;
1045 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)];
1046
1047 switch (CodeType)
1048 {
1049 case CODE_ASCII:
1050 Code = (BYTE)FillOutputRequest->Code.AsciiChar;
1051 break;
1052
1053 case CODE_UNICODE:
1054 ConsoleUnicodeCharToAnsiChar(Console, (PCHAR)&Code, &FillOutputRequest->Code.UnicodeChar);
1055 break;
1056
1057 case CODE_ATTRIBUTE:
1058 Code = (BYTE)FillOutputRequest->Code.Attribute;
1059 break;
1060
1061 default:
1062 ConioUnlockScreenBuffer(Buff);
1063 return STATUS_INVALID_PARAMETER;
1064 }
1065
1066 while (Length--)
1067 {
1068 *Buffer = Code;
1069 Buffer += 2;
1070 // Written++;
1071 if (++X == Buff->MaxX)
1072 {
1073 if (++Y == Buff->MaxY)
1074 {
1075 Y = 0;
1076 Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0);
1077 }
1078 X = 0;
1079 }
1080 }
1081
1082 if (Buff == Console->ActiveBuffer)
1083 {
1084 ConioComputeUpdateRect(Buff, &UpdateRect, &FillOutputRequest->Coord,
1085 FillOutputRequest->Length);
1086 ConioDrawRegion(Console, &UpdateRect);
1087 }
1088
1089 ConioUnlockScreenBuffer(Buff);
1090 /*
1091 Length = FillOutputRequest->Length;
1092 FillOutputRequest->NrCharactersWritten = Length;
1093 */
1094 return STATUS_SUCCESS;
1095 }
1096
1097 CSR_API(SrvGetConsoleCursorInfo)
1098 {
1099 NTSTATUS Status;
1100 PCSRSS_CURSOR_INFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
1101 PCSRSS_SCREEN_BUFFER Buff;
1102
1103 DPRINT("SrvGetConsoleCursorInfo\n");
1104
1105 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->ConsoleHandle, &Buff, GENERIC_READ);
1106 if (!NT_SUCCESS(Status)) return Status;
1107
1108 CursorInfoRequest->Info.bVisible = Buff->CursorInfo.bVisible;
1109 CursorInfoRequest->Info.dwSize = Buff->CursorInfo.dwSize;
1110 ConioUnlockScreenBuffer(Buff);
1111
1112 return STATUS_SUCCESS;
1113 }
1114
1115 CSR_API(SrvSetConsoleCursorInfo)
1116 {
1117 NTSTATUS Status;
1118 PCSRSS_CURSOR_INFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
1119 PCSRSS_CONSOLE Console;
1120 PCSRSS_SCREEN_BUFFER Buff;
1121 DWORD Size;
1122 BOOL Visible;
1123
1124 DPRINT("SrvSetConsoleCursorInfo\n");
1125
1126 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->ConsoleHandle, &Buff, GENERIC_WRITE);
1127 if (!NT_SUCCESS(Status)) return Status;
1128
1129 Console = Buff->Header.Console;
1130
1131 Size = CursorInfoRequest->Info.dwSize;
1132 Visible = CursorInfoRequest->Info.bVisible;
1133 if (Size < 1)
1134 {
1135 Size = 1;
1136 }
1137 if (100 < Size)
1138 {
1139 Size = 100;
1140 }
1141
1142 if ( (Size != Buff->CursorInfo.dwSize) ||
1143 (Visible && ! Buff->CursorInfo.bVisible) ||
1144 (! Visible && Buff->CursorInfo.bVisible) )
1145 {
1146 Buff->CursorInfo.dwSize = Size;
1147 Buff->CursorInfo.bVisible = Visible;
1148
1149 if (!ConioSetCursorInfo(Console, Buff))
1150 {
1151 ConioUnlockScreenBuffer(Buff);
1152 return STATUS_UNSUCCESSFUL;
1153 }
1154 }
1155
1156 ConioUnlockScreenBuffer(Buff);
1157
1158 return STATUS_SUCCESS;
1159 }
1160
1161 CSR_API(SrvSetConsoleCursorPosition)
1162 {
1163 NTSTATUS Status;
1164 PCSRSS_SET_CURSOR_POSITION SetCursorPositionRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorPositionRequest;
1165 PCSRSS_CONSOLE Console;
1166 PCSRSS_SCREEN_BUFFER Buff;
1167 LONG OldCursorX, OldCursorY;
1168 LONG NewCursorX, NewCursorY;
1169
1170 DPRINT("SrvSetConsoleCursorPosition\n");
1171
1172 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetCursorPositionRequest->ConsoleHandle, &Buff, GENERIC_WRITE);
1173 if (!NT_SUCCESS(Status)) return Status;
1174
1175 Console = Buff->Header.Console;
1176
1177 NewCursorX = SetCursorPositionRequest->Position.X;
1178 NewCursorY = SetCursorPositionRequest->Position.Y;
1179 if ( NewCursorX < 0 || NewCursorX >= Buff->MaxX ||
1180 NewCursorY < 0 || NewCursorY >= Buff->MaxY )
1181 {
1182 ConioUnlockScreenBuffer(Buff);
1183 return STATUS_INVALID_PARAMETER;
1184 }
1185 OldCursorX = Buff->CurrentX;
1186 OldCursorY = Buff->CurrentY;
1187 Buff->CurrentX = NewCursorX;
1188 Buff->CurrentY = NewCursorY;
1189 if (Buff == Console->ActiveBuffer)
1190 {
1191 if (! ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
1192 {
1193 ConioUnlockScreenBuffer(Buff);
1194 return STATUS_UNSUCCESSFUL;
1195 }
1196 }
1197
1198 ConioUnlockScreenBuffer(Buff);
1199
1200 return STATUS_SUCCESS;
1201 }
1202
1203 CSR_API(SrvSetConsoleTextAttribute)
1204 {
1205 NTSTATUS Status;
1206 PCSRSS_SET_ATTRIB SetAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetAttribRequest;
1207 PCSRSS_CONSOLE Console;
1208 PCSRSS_SCREEN_BUFFER Buff;
1209
1210 DPRINT("SrvSetConsoleTextAttribute\n");
1211
1212 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetAttribRequest->ConsoleHandle, &Buff, GENERIC_WRITE);
1213 if (!NT_SUCCESS(Status)) return Status;
1214
1215 Console = Buff->Header.Console;
1216
1217 Buff->DefaultAttrib = SetAttribRequest->Attrib;
1218 if (Buff == Console->ActiveBuffer)
1219 {
1220 if (!ConioUpdateScreenInfo(Console, Buff))
1221 {
1222 ConioUnlockScreenBuffer(Buff);
1223 return STATUS_UNSUCCESSFUL;
1224 }
1225 }
1226
1227 ConioUnlockScreenBuffer(Buff);
1228
1229 return STATUS_SUCCESS;
1230 }
1231
1232 CSR_API(SrvCreateConsoleScreenBuffer)
1233 {
1234 NTSTATUS Status;
1235 PCSRSS_CREATE_SCREEN_BUFFER CreateScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CreateScreenBufferRequest;
1236 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
1237 PCSRSS_CONSOLE Console;
1238 PCSRSS_SCREEN_BUFFER Buff;
1239
1240 DPRINT("SrvCreateConsoleScreenBuffer\n");
1241
1242 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
1243
1244 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1245 if (!NT_SUCCESS(Status))
1246 {
1247 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
1248 return Status;
1249 }
1250
1251 Buff = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
1252 if (Buff != NULL)
1253 {
1254 if (Console->ActiveBuffer)
1255 {
1256 Buff->MaxX = Console->ActiveBuffer->MaxX;
1257 Buff->MaxY = Console->ActiveBuffer->MaxY;
1258 Buff->CursorInfo.bVisible = Console->ActiveBuffer->CursorInfo.bVisible;
1259 Buff->CursorInfo.dwSize = Console->ActiveBuffer->CursorInfo.dwSize;
1260 }
1261 else
1262 {
1263 Buff->CursorInfo.bVisible = TRUE;
1264 Buff->CursorInfo.dwSize = CSR_DEFAULT_CURSOR_SIZE;
1265 }
1266
1267 if (Buff->MaxX == 0)
1268 {
1269 Buff->MaxX = 80;
1270 }
1271
1272 if (Buff->MaxY == 0)
1273 {
1274 Buff->MaxY = 25;
1275 }
1276
1277 Status = CsrInitConsoleScreenBuffer(Console, Buff);
1278 if (NT_SUCCESS(Status))
1279 {
1280 Status = Win32CsrInsertObject(ProcessData,
1281 &CreateScreenBufferRequest->OutputHandle,
1282 &Buff->Header,
1283 CreateScreenBufferRequest->Access,
1284 CreateScreenBufferRequest->Inheritable,
1285 CreateScreenBufferRequest->ShareMode);
1286 }
1287 }
1288 else
1289 {
1290 Status = STATUS_INSUFFICIENT_RESOURCES;
1291 }
1292
1293 ConioUnlockConsole(Console);
1294
1295 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
1296
1297 return Status;
1298 }
1299
1300 CSR_API(SrvGetConsoleScreenBufferInfo)
1301 {
1302 NTSTATUS Status;
1303 PCSRSS_SCREEN_BUFFER_INFO ScreenBufferInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScreenBufferInfoRequest;
1304 PCSRSS_CONSOLE Console;
1305 PCSRSS_SCREEN_BUFFER Buff;
1306 PCONSOLE_SCREEN_BUFFER_INFO pInfo = &ScreenBufferInfoRequest->Info;
1307
1308 DPRINT("SrvGetConsoleScreenBufferInfo\n");
1309
1310 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ScreenBufferInfoRequest->ConsoleHandle, &Buff, GENERIC_READ);
1311 if (!NT_SUCCESS(Status)) return Status;
1312
1313 Console = Buff->Header.Console;
1314
1315 pInfo->dwSize.X = Buff->MaxX;
1316 pInfo->dwSize.Y = Buff->MaxY;
1317 pInfo->dwCursorPosition.X = Buff->CurrentX;
1318 pInfo->dwCursorPosition.Y = Buff->CurrentY;
1319 pInfo->wAttributes = Buff->DefaultAttrib;
1320 pInfo->srWindow.Left = Buff->ShowX;
1321 pInfo->srWindow.Right = Buff->ShowX + Console->Size.X - 1;
1322 pInfo->srWindow.Top = Buff->ShowY;
1323 pInfo->srWindow.Bottom = Buff->ShowY + Console->Size.Y - 1;
1324 pInfo->dwMaximumWindowSize.X = Buff->MaxX;
1325 pInfo->dwMaximumWindowSize.Y = Buff->MaxY;
1326
1327 ConioUnlockScreenBuffer(Buff);
1328
1329 return STATUS_SUCCESS;
1330 }
1331
1332 CSR_API(SrvSetConsoleActiveScreenBuffer)
1333 {
1334 NTSTATUS Status;
1335 PCSRSS_SET_SCREEN_BUFFER SetScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferRequest;
1336 PCSRSS_CONSOLE Console;
1337 PCSRSS_SCREEN_BUFFER Buff;
1338
1339 DPRINT("SrvSetConsoleActiveScreenBuffer\n");
1340
1341 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetScreenBufferRequest->OutputHandle, &Buff, GENERIC_WRITE);
1342 if (!NT_SUCCESS(Status)) return Status;
1343
1344 Console = Buff->Header.Console;
1345
1346 if (Buff == Console->ActiveBuffer)
1347 {
1348 ConioUnlockScreenBuffer(Buff);
1349 return STATUS_SUCCESS;
1350 }
1351
1352 /* If old buffer has no handles, it's now unreferenced */
1353 if (Console->ActiveBuffer->Header.HandleCount == 0)
1354 {
1355 ConioDeleteScreenBuffer(Console->ActiveBuffer);
1356 }
1357
1358 /* Tie console to new buffer */
1359 Console->ActiveBuffer = Buff;
1360
1361 /* Redraw the console */
1362 ConioDrawConsole(Console);
1363
1364 ConioUnlockScreenBuffer(Buff);
1365
1366 return STATUS_SUCCESS;
1367 }
1368
1369 CSR_API(SrvScrollConsoleScreenBuffer)
1370 {
1371 PCSRSS_SCROLL_CONSOLE_SCREEN_BUFFER ScrollConsoleScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScrollConsoleScreenBufferRequest;
1372 PCSRSS_CONSOLE Console;
1373 PCSRSS_SCREEN_BUFFER Buff;
1374 SMALL_RECT ScreenBuffer;
1375 SMALL_RECT SrcRegion;
1376 SMALL_RECT DstRegion;
1377 SMALL_RECT UpdateRegion;
1378 SMALL_RECT ScrollRectangle;
1379 SMALL_RECT ClipRectangle;
1380 NTSTATUS Status;
1381 HANDLE ConsoleHandle;
1382 BOOLEAN UseClipRectangle;
1383 COORD DestinationOrigin;
1384 CHAR_INFO Fill;
1385 CHAR FillChar;
1386
1387 DPRINT("SrvScrollConsoleScreenBuffer\n");
1388
1389 ConsoleHandle = ScrollConsoleScreenBufferRequest->ConsoleHandle;
1390 UseClipRectangle = ScrollConsoleScreenBufferRequest->UseClipRectangle;
1391 DestinationOrigin = ScrollConsoleScreenBufferRequest->DestinationOrigin;
1392 Fill = ScrollConsoleScreenBufferRequest->Fill;
1393
1394 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ConsoleHandle, &Buff, GENERIC_WRITE);
1395 if (!NT_SUCCESS(Status)) return Status;
1396
1397 Console = Buff->Header.Console;
1398
1399 ScrollRectangle = ScrollConsoleScreenBufferRequest->ScrollRectangle;
1400
1401 /* Make sure source rectangle is inside the screen buffer */
1402 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1403 if (! ConioGetIntersection(&SrcRegion, &ScreenBuffer, &ScrollRectangle))
1404 {
1405 ConioUnlockScreenBuffer(Buff);
1406 return STATUS_SUCCESS;
1407 }
1408
1409 /* If the source was clipped on the left or top, adjust the destination accordingly */
1410 if (ScrollRectangle.Left < 0)
1411 {
1412 DestinationOrigin.X -= ScrollRectangle.Left;
1413 }
1414 if (ScrollRectangle.Top < 0)
1415 {
1416 DestinationOrigin.Y -= ScrollRectangle.Top;
1417 }
1418
1419 if (UseClipRectangle)
1420 {
1421 ClipRectangle = ScrollConsoleScreenBufferRequest->ClipRectangle;
1422 if (!ConioGetIntersection(&ClipRectangle, &ClipRectangle, &ScreenBuffer))
1423 {
1424 ConioUnlockScreenBuffer(Buff);
1425 return STATUS_SUCCESS;
1426 }
1427 }
1428 else
1429 {
1430 ClipRectangle = ScreenBuffer;
1431 }
1432
1433 ConioInitRect(&DstRegion,
1434 DestinationOrigin.Y,
1435 DestinationOrigin.X,
1436 DestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
1437 DestinationOrigin.X + ConioRectWidth(&SrcRegion) - 1);
1438
1439 if (ScrollConsoleScreenBufferRequest->Unicode)
1440 ConsoleUnicodeCharToAnsiChar(Console, &FillChar, &Fill.Char.UnicodeChar);
1441 else
1442 FillChar = Fill.Char.AsciiChar;
1443
1444 ConioMoveRegion(Buff, &SrcRegion, &DstRegion, &ClipRectangle, Fill.Attributes << 8 | (BYTE)FillChar);
1445
1446 if (Buff == Console->ActiveBuffer)
1447 {
1448 ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
1449 if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &ClipRectangle))
1450 {
1451 /* Draw update region */
1452 ConioDrawRegion(Console, &UpdateRegion);
1453 }
1454 }
1455
1456 ConioUnlockScreenBuffer(Buff);
1457
1458 return STATUS_SUCCESS;
1459 }
1460
1461 CSR_API(SrvSetConsoleScreenBufferSize)
1462 {
1463 NTSTATUS Status;
1464 PCSRSS_SET_SCREEN_BUFFER_SIZE SetScreenBufferSize = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferSize;
1465 PCSRSS_SCREEN_BUFFER Buff;
1466
1467 Status = ConioLockScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetScreenBufferSize->OutputHandle, &Buff, GENERIC_WRITE);
1468 if (!NT_SUCCESS(Status)) return Status;
1469
1470 Status = ConioResizeBuffer(Buff->Header.Console, Buff, SetScreenBufferSize->Size);
1471 ConioUnlockScreenBuffer(Buff);
1472
1473 return Status;
1474 }
1475
1476 /* EOF */