[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 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(PCONSOLE_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(PCONSOLE_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(PCONSOLE Console,
62 PCONSOLE_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 = RtlAllocateHeap(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(PCONSOLE_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(PCONSOLE Console, PCONSOLE_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(PCONSOLE_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(PCONSOLE_SCREEN_BUFFER Buffer)
367 {
368 PCONSOLE 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, CONSOLE_SCREEN_BUFFER, ListEntry);
378 ConioDrawConsole(Console);
379 }
380 }
381
382 RtlFreeHeap(ConSrvHeap, 0, Buffer->Buffer);
383 RtlFreeHeap(ConSrvHeap, 0, Buffer);
384 }
385
386 VOID FASTCALL
387 ConioDrawConsole(PCONSOLE 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(PCONSOLE_SCREEN_BUFFER Buff, SMALL_RECT* UpdateRect, PCOORD 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(PCONSOLE 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 DPRINT1("WriteConsoleThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
451
452 /*
453 * If we are notified of the process termination via a call
454 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
455 * CsrDestroyThread, just return.
456 */
457 if (WaitFlags & CsrProcessTerminating)
458 {
459 Status = STATUS_THREAD_IS_TERMINATING;
460 goto Quit;
461 }
462
463 Status = DoWriteConsole(WaitApiMessage,
464 WaitThread,
465 FALSE);
466
467 Quit:
468 if (Status != STATUS_PENDING)
469 {
470 WaitApiMessage->Status = Status;
471 }
472
473 return (Status == STATUS_PENDING ? FALSE : TRUE);
474 }
475
476 static NTSTATUS
477 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
478 IN PCSR_THREAD ClientThread,
479 IN BOOL CreateWaitBlock OPTIONAL)
480 {
481 NTSTATUS Status = STATUS_SUCCESS;
482 PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
483 PCONSOLE Console;
484 PCONSOLE_SCREEN_BUFFER Buff;
485 PCHAR Buffer;
486 DWORD Written = 0;
487 ULONG Length;
488
489 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(ClientThread->Process), WriteConsoleRequest->OutputHandle, &Buff, GENERIC_WRITE, FALSE);
490 if (!NT_SUCCESS(Status)) return Status;
491
492 Console = Buff->Header.Console;
493
494 // if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION))
495 if (Console->PauseFlags && Console->UnpauseEvent != NULL)
496 {
497 if (CreateWaitBlock)
498 {
499 if (!CsrCreateWait(&Console->WriteWaitQueue,
500 WriteConsoleThread,
501 ClientThread,
502 ApiMessage,
503 NULL,
504 NULL))
505 {
506 /* Fail */
507 ConioReleaseScreenBuffer(Buff, FALSE);
508 return STATUS_NO_MEMORY;
509 }
510 }
511
512 /* Wait until we un-pause the console */
513 Status = STATUS_PENDING;
514 }
515 else
516 {
517 if (WriteConsoleRequest->Unicode)
518 {
519 Length = WideCharToMultiByte(Console->OutputCodePage, 0,
520 (PWCHAR)WriteConsoleRequest->Buffer,
521 WriteConsoleRequest->NrCharactersToWrite,
522 NULL, 0, NULL, NULL);
523 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
524 if (Buffer)
525 {
526 WideCharToMultiByte(Console->OutputCodePage, 0,
527 (PWCHAR)WriteConsoleRequest->Buffer,
528 WriteConsoleRequest->NrCharactersToWrite,
529 Buffer, Length, NULL, NULL);
530 }
531 else
532 {
533 Status = STATUS_NO_MEMORY;
534 }
535 }
536 else
537 {
538 Buffer = (PCHAR)WriteConsoleRequest->Buffer;
539 }
540
541 if (Buffer)
542 {
543 if (NT_SUCCESS(Status))
544 {
545 Status = ConioWriteConsole(Console, Buff, Buffer,
546 WriteConsoleRequest->NrCharactersToWrite, TRUE);
547 if (NT_SUCCESS(Status))
548 {
549 Written = WriteConsoleRequest->NrCharactersToWrite;
550 }
551 }
552 if (WriteConsoleRequest->Unicode)
553 {
554 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
555 }
556 }
557
558 WriteConsoleRequest->NrCharactersWritten = Written;
559 }
560
561 ConioReleaseScreenBuffer(Buff, FALSE);
562 return Status;
563 }
564
565
566 /* PUBLIC APIS ****************************************************************/
567
568 CSR_API(SrvReadConsoleOutput)
569 {
570 PCONSOLE_READOUTPUT ReadOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputRequest;
571 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
572 PCHAR_INFO CharInfo;
573 PCHAR_INFO CurCharInfo;
574 PCONSOLE_SCREEN_BUFFER Buff;
575 DWORD SizeX, SizeY;
576 NTSTATUS Status;
577 COORD BufferSize;
578 COORD BufferCoord;
579 SMALL_RECT ReadRegion;
580 SMALL_RECT ScreenRect;
581 DWORD i;
582 PBYTE Ptr;
583 LONG X, Y;
584 UINT CodePage;
585
586 DPRINT("SrvReadConsoleOutput\n");
587
588 CharInfo = ReadOutputRequest->CharInfo;
589 ReadRegion = ReadOutputRequest->ReadRegion;
590 BufferSize = ReadOutputRequest->BufferSize;
591 BufferCoord = ReadOutputRequest->BufferCoord;
592
593 if (!CsrValidateMessageBuffer(ApiMessage,
594 (PVOID*)&ReadOutputRequest->CharInfo,
595 BufferSize.X * BufferSize.Y,
596 sizeof(CHAR_INFO)))
597 {
598 return STATUS_INVALID_PARAMETER;
599 }
600
601 Status = ConioGetScreenBuffer(ProcessData, ReadOutputRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
602 if (!NT_SUCCESS(Status)) return Status;
603
604 /* FIXME: Is this correct? */
605 CodePage = ProcessData->Console->OutputCodePage;
606
607 SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&ReadRegion));
608 SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&ReadRegion));
609 ReadRegion.Bottom = ReadRegion.Top + SizeY;
610 ReadRegion.Right = ReadRegion.Left + SizeX;
611
612 ConioInitRect(&ScreenRect, 0, 0, Buff->MaxY, Buff->MaxX);
613 if (!ConioGetIntersection(&ReadRegion, &ScreenRect, &ReadRegion))
614 {
615 ConioReleaseScreenBuffer(Buff, TRUE);
616 return STATUS_SUCCESS;
617 }
618
619 for (i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y)
620 {
621 CurCharInfo = CharInfo + (i * BufferSize.X);
622
623 Ptr = ConioCoordToPointer(Buff, ReadRegion.Left, Y);
624 for (X = ReadRegion.Left; X < ReadRegion.Right; ++X)
625 {
626 if (ReadOutputRequest->Unicode)
627 {
628 // ConsoleAnsiCharToUnicodeChar(ProcessData->Console, (PCHAR)Ptr++, &CurCharInfo->Char.UnicodeChar);
629 MultiByteToWideChar(CodePage, 0,
630 (PCHAR)Ptr++, 1,
631 &CurCharInfo->Char.UnicodeChar, 1);
632 }
633 else
634 {
635 CurCharInfo->Char.AsciiChar = *Ptr++;
636 }
637 CurCharInfo->Attributes = *Ptr++;
638 ++CurCharInfo;
639 }
640 }
641
642 ConioReleaseScreenBuffer(Buff, TRUE);
643
644 ReadOutputRequest->ReadRegion.Right = ReadRegion.Left + SizeX - 1;
645 ReadOutputRequest->ReadRegion.Bottom = ReadRegion.Top + SizeY - 1;
646 ReadOutputRequest->ReadRegion.Left = ReadRegion.Left;
647 ReadOutputRequest->ReadRegion.Top = ReadRegion.Top;
648
649 return STATUS_SUCCESS;
650 }
651
652 CSR_API(SrvWriteConsole)
653 {
654 NTSTATUS Status;
655 PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
656
657 DPRINT("SrvWriteConsole\n");
658
659 if (!CsrValidateMessageBuffer(ApiMessage,
660 (PVOID)&WriteConsoleRequest->Buffer,
661 WriteConsoleRequest->BufferSize,
662 sizeof(BYTE)))
663 {
664 return STATUS_INVALID_PARAMETER;
665 }
666
667 Status = DoWriteConsole(ApiMessage,
668 CsrGetClientThread(),
669 TRUE);
670
671 if (Status == STATUS_PENDING)
672 *ReplyCode = CsrReplyPending;
673
674 return Status;
675 }
676
677 CSR_API(SrvWriteConsoleOutput)
678 {
679 PCONSOLE_WRITEOUTPUT WriteOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputRequest;
680 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
681 SHORT i, X, Y, SizeX, SizeY;
682 PCONSOLE Console;
683 PCONSOLE_SCREEN_BUFFER Buff;
684 SMALL_RECT ScreenBuffer;
685 CHAR_INFO* CurCharInfo;
686 SMALL_RECT WriteRegion;
687 CHAR_INFO* CharInfo;
688 COORD BufferCoord;
689 COORD BufferSize;
690 NTSTATUS Status;
691 PBYTE Ptr;
692
693 DPRINT("SrvWriteConsoleOutput\n");
694
695 BufferSize = WriteOutputRequest->BufferSize;
696 BufferCoord = WriteOutputRequest->BufferCoord;
697 CharInfo = WriteOutputRequest->CharInfo;
698
699 if (!CsrValidateMessageBuffer(ApiMessage,
700 (PVOID*)&WriteOutputRequest->CharInfo,
701 BufferSize.X * BufferSize.Y,
702 sizeof(CHAR_INFO)))
703 {
704 return STATUS_INVALID_PARAMETER;
705 }
706
707 Status = ConioGetScreenBuffer(ProcessData,
708 WriteOutputRequest->OutputHandle,
709 &Buff,
710 GENERIC_WRITE,
711 TRUE);
712 if (!NT_SUCCESS(Status)) return Status;
713
714 Console = Buff->Header.Console;
715
716 WriteRegion = WriteOutputRequest->WriteRegion;
717
718 SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&WriteRegion));
719 SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&WriteRegion));
720 WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
721 WriteRegion.Right = WriteRegion.Left + SizeX - 1;
722
723 /* Make sure WriteRegion is inside the screen buffer */
724 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
725 if (!ConioGetIntersection(&WriteRegion, &ScreenBuffer, &WriteRegion))
726 {
727 ConioReleaseScreenBuffer(Buff, TRUE);
728
729 /* It is okay to have a WriteRegion completely outside the screen buffer.
730 No data is written then. */
731 return STATUS_SUCCESS;
732 }
733
734 for (i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++)
735 {
736 CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
737 Ptr = ConioCoordToPointer(Buff, WriteRegion.Left, Y);
738 for (X = WriteRegion.Left; X <= WriteRegion.Right; X++)
739 {
740 CHAR AsciiChar;
741 if (WriteOutputRequest->Unicode)
742 {
743 ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar);
744 }
745 else
746 {
747 AsciiChar = CurCharInfo->Char.AsciiChar;
748 }
749 *Ptr++ = AsciiChar;
750 *Ptr++ = CurCharInfo->Attributes;
751 CurCharInfo++;
752 }
753 }
754
755 ConioDrawRegion(Console, &WriteRegion);
756
757 ConioReleaseScreenBuffer(Buff, TRUE);
758
759 WriteOutputRequest->WriteRegion.Right = WriteRegion.Left + SizeX - 1;
760 WriteOutputRequest->WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
761 WriteOutputRequest->WriteRegion.Left = WriteRegion.Left;
762 WriteOutputRequest->WriteRegion.Top = WriteRegion.Top;
763
764 return STATUS_SUCCESS;
765 }
766
767 CSR_API(SrvReadConsoleOutputString)
768 {
769 NTSTATUS Status;
770 PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputCodeRequest;
771 PCONSOLE Console;
772 PCONSOLE_SCREEN_BUFFER Buff;
773 USHORT CodeType;
774 DWORD Xpos, Ypos;
775 PVOID ReadBuffer;
776 DWORD i;
777 ULONG CodeSize;
778 BYTE Code;
779
780 DPRINT("SrvReadConsoleOutputString\n");
781
782 CodeType = ReadOutputCodeRequest->CodeType;
783 switch (CodeType)
784 {
785 case CODE_ASCII:
786 CodeSize = sizeof(CHAR);
787 break;
788
789 case CODE_UNICODE:
790 CodeSize = sizeof(WCHAR);
791 break;
792
793 case CODE_ATTRIBUTE:
794 CodeSize = sizeof(WORD);
795 break;
796
797 default:
798 return STATUS_INVALID_PARAMETER;
799 }
800
801 if (!CsrValidateMessageBuffer(ApiMessage,
802 (PVOID*)&ReadOutputCodeRequest->pCode.pCode,
803 ReadOutputCodeRequest->NumCodesToRead,
804 CodeSize))
805 {
806 return STATUS_INVALID_PARAMETER;
807 }
808
809 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ReadOutputCodeRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
810 if (!NT_SUCCESS(Status)) return Status;
811
812 Console = Buff->Header.Console;
813
814 ReadBuffer = ReadOutputCodeRequest->pCode.pCode;
815 Xpos = ReadOutputCodeRequest->ReadCoord.X;
816 Ypos = (ReadOutputCodeRequest->ReadCoord.Y + Buff->VirtualY) % Buff->MaxY;
817
818 /*
819 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
820 *
821 * If the number of attributes (resp. characters) to be read from extends
822 * beyond the end of the specified screen buffer row, attributes (resp.
823 * characters) are read from the next row. If the number of attributes
824 * (resp. characters) to be read from extends beyond the end of the console
825 * screen buffer, attributes (resp. characters) up to the end of the console
826 * screen buffer are read.
827 *
828 * TODO: Do NOT loop up to NumCodesToRead, but stop before
829 * if we are going to overflow...
830 */
831 for (i = 0; i < ReadOutputCodeRequest->NumCodesToRead; ++i)
832 {
833 Code = Buff->Buffer[2 * (Xpos + Ypos * Buff->MaxX) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)];
834
835 switch (CodeType)
836 {
837 case CODE_UNICODE:
838 ConsoleAnsiCharToUnicodeChar(Console, (PWCHAR)ReadBuffer, (PCHAR)&Code);
839 break;
840
841 case CODE_ASCII:
842 *(PCHAR)ReadBuffer = (CHAR)Code;
843 break;
844
845 case CODE_ATTRIBUTE:
846 *(PWORD)ReadBuffer = (WORD)Code;
847 break;
848 }
849 ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
850
851 Xpos++;
852
853 if (Xpos == Buff->MaxX)
854 {
855 Xpos = 0;
856 Ypos++;
857
858 if (Ypos == Buff->MaxY)
859 {
860 Ypos = 0;
861 }
862 }
863 }
864
865 switch (CodeType)
866 {
867 case CODE_UNICODE:
868 *(PWCHAR)ReadBuffer = 0;
869 break;
870
871 case CODE_ASCII:
872 *(PCHAR)ReadBuffer = 0;
873 break;
874
875 case CODE_ATTRIBUTE:
876 *(PWORD)ReadBuffer = 0;
877 break;
878 }
879
880 ReadOutputCodeRequest->EndCoord.X = Xpos;
881 ReadOutputCodeRequest->EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
882
883 ConioReleaseScreenBuffer(Buff, TRUE);
884
885 ReadOutputCodeRequest->CodesRead = (DWORD)((ULONG_PTR)ReadBuffer - (ULONG_PTR)ReadOutputCodeRequest->pCode.pCode) / CodeSize;
886 // <= ReadOutputCodeRequest->NumCodesToRead
887
888 return STATUS_SUCCESS;
889 }
890
891 CSR_API(SrvWriteConsoleOutputString)
892 {
893 NTSTATUS Status;
894 PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputCodeRequest;
895 PCONSOLE Console;
896 PCONSOLE_SCREEN_BUFFER Buff;
897 USHORT CodeType;
898 PBYTE Buffer; // PUCHAR
899 PCHAR String, tmpString = NULL;
900 DWORD X, Y, Length; // , Written = 0;
901 ULONG CodeSize;
902 SMALL_RECT UpdateRect;
903
904 DPRINT("SrvWriteConsoleOutputString\n");
905
906 CodeType = WriteOutputCodeRequest->CodeType;
907 switch (CodeType)
908 {
909 case CODE_ASCII:
910 CodeSize = sizeof(CHAR);
911 break;
912
913 case CODE_UNICODE:
914 CodeSize = sizeof(WCHAR);
915 break;
916
917 case CODE_ATTRIBUTE:
918 CodeSize = sizeof(WORD);
919 break;
920
921 default:
922 return STATUS_INVALID_PARAMETER;
923 }
924
925 if (!CsrValidateMessageBuffer(ApiMessage,
926 (PVOID*)&WriteOutputCodeRequest->pCode.pCode,
927 WriteOutputCodeRequest->Length,
928 CodeSize))
929 {
930 return STATUS_INVALID_PARAMETER;
931 }
932
933 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
934 WriteOutputCodeRequest->OutputHandle,
935 &Buff,
936 GENERIC_WRITE,
937 TRUE);
938 if (!NT_SUCCESS(Status)) return Status;
939
940 Console = Buff->Header.Console;
941
942 switch (CodeType)
943 {
944 case CODE_UNICODE:
945 {
946 Length = WideCharToMultiByte(Console->OutputCodePage, 0,
947 (PWCHAR)WriteOutputCodeRequest->pCode.UnicodeChar,
948 WriteOutputCodeRequest->Length,
949 NULL, 0, NULL, NULL);
950 tmpString = String = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
951 if (String)
952 {
953 WideCharToMultiByte(Console->OutputCodePage, 0,
954 (PWCHAR)WriteOutputCodeRequest->pCode.UnicodeChar,
955 WriteOutputCodeRequest->Length,
956 String, Length, NULL, NULL);
957 }
958 else
959 {
960 Status = STATUS_NO_MEMORY;
961 }
962
963 break;
964 }
965
966 case CODE_ASCII:
967 String = (PCHAR)WriteOutputCodeRequest->pCode.AsciiChar;
968 break;
969
970 case CODE_ATTRIBUTE:
971 default:
972 // *(ReadBuffer++) = Code;
973 String = (PCHAR)WriteOutputCodeRequest->pCode.Attribute;
974 break;
975 }
976
977 if (String && NT_SUCCESS(Status))
978 {
979 X = WriteOutputCodeRequest->Coord.X;
980 Y = (WriteOutputCodeRequest->Coord.Y + Buff->VirtualY) % Buff->MaxY;
981 Length = WriteOutputCodeRequest->Length;
982 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)];
983
984 while (Length--)
985 {
986 *Buffer = *String++;
987 // ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
988 String = (PCHAR)((ULONG_PTR)String + CodeSize);
989 // Written++;
990 Buffer += 2;
991 if (++X == Buff->MaxX)
992 {
993 if (++Y == Buff->MaxY)
994 {
995 Y = 0;
996 Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0);
997 }
998 X = 0;
999 }
1000 }
1001
1002 if (Buff == Console->ActiveBuffer)
1003 {
1004 ConioComputeUpdateRect(Buff, &UpdateRect, &WriteOutputCodeRequest->Coord,
1005 WriteOutputCodeRequest->Length);
1006 ConioDrawRegion(Console, &UpdateRect);
1007 }
1008
1009 WriteOutputCodeRequest->EndCoord.X = X;
1010 WriteOutputCodeRequest->EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
1011 }
1012
1013 if (tmpString)
1014 {
1015 RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString);
1016 }
1017
1018 ConioReleaseScreenBuffer(Buff, TRUE);
1019
1020 // WriteOutputCodeRequest->NrCharactersWritten = Written;
1021 return Status;
1022 }
1023
1024 CSR_API(SrvFillConsoleOutput)
1025 {
1026 NTSTATUS Status;
1027 PCONSOLE_FILLOUTPUTCODE FillOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputRequest;
1028 PCONSOLE Console;
1029 PCONSOLE_SCREEN_BUFFER Buff;
1030 DWORD X, Y, Length; // , Written = 0;
1031 USHORT CodeType;
1032 BYTE Code;
1033 PBYTE Buffer;
1034 SMALL_RECT UpdateRect;
1035
1036 DPRINT("SrvFillConsoleOutput\n");
1037
1038 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), FillOutputRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1039 if (!NT_SUCCESS(Status)) return Status;
1040
1041 Console = Buff->Header.Console;
1042
1043 CodeType = FillOutputRequest->CodeType;
1044
1045 X = FillOutputRequest->Coord.X;
1046 Y = (FillOutputRequest->Coord.Y + Buff->VirtualY) % Buff->MaxY;
1047 Length = FillOutputRequest->Length;
1048 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + (CodeType == CODE_ATTRIBUTE ? 1 : 0)];
1049
1050 switch (CodeType)
1051 {
1052 case CODE_ASCII:
1053 Code = (BYTE)FillOutputRequest->Code.AsciiChar;
1054 break;
1055
1056 case CODE_UNICODE:
1057 ConsoleUnicodeCharToAnsiChar(Console, (PCHAR)&Code, &FillOutputRequest->Code.UnicodeChar);
1058 break;
1059
1060 case CODE_ATTRIBUTE:
1061 Code = (BYTE)FillOutputRequest->Code.Attribute;
1062 break;
1063
1064 default:
1065 ConioReleaseScreenBuffer(Buff, TRUE);
1066 return STATUS_INVALID_PARAMETER;
1067 }
1068
1069 while (Length--)
1070 {
1071 *Buffer = Code;
1072 Buffer += 2;
1073 // Written++;
1074 if (++X == Buff->MaxX)
1075 {
1076 if (++Y == Buff->MaxY)
1077 {
1078 Y = 0;
1079 Buffer = Buff->Buffer + (CodeType == CODE_ATTRIBUTE ? 1 : 0);
1080 }
1081 X = 0;
1082 }
1083 }
1084
1085 if (Buff == Console->ActiveBuffer)
1086 {
1087 ConioComputeUpdateRect(Buff, &UpdateRect, &FillOutputRequest->Coord,
1088 FillOutputRequest->Length);
1089 ConioDrawRegion(Console, &UpdateRect);
1090 }
1091
1092 ConioReleaseScreenBuffer(Buff, TRUE);
1093 /*
1094 Length = FillOutputRequest->Length;
1095 FillOutputRequest->NrCharactersWritten = Length;
1096 */
1097 return STATUS_SUCCESS;
1098 }
1099
1100 CSR_API(SrvGetConsoleCursorInfo)
1101 {
1102 NTSTATUS Status;
1103 PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
1104 PCONSOLE_SCREEN_BUFFER Buff;
1105
1106 DPRINT("SrvGetConsoleCursorInfo\n");
1107
1108 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
1109 if (!NT_SUCCESS(Status)) return Status;
1110
1111 CursorInfoRequest->Info.bVisible = Buff->CursorInfo.bVisible;
1112 CursorInfoRequest->Info.dwSize = Buff->CursorInfo.dwSize;
1113 ConioReleaseScreenBuffer(Buff, TRUE);
1114
1115 return STATUS_SUCCESS;
1116 }
1117
1118 CSR_API(SrvSetConsoleCursorInfo)
1119 {
1120 NTSTATUS Status;
1121 PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
1122 PCONSOLE Console;
1123 PCONSOLE_SCREEN_BUFFER Buff;
1124 DWORD Size;
1125 BOOL Visible;
1126
1127 DPRINT("SrvSetConsoleCursorInfo\n");
1128
1129 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), CursorInfoRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1130 if (!NT_SUCCESS(Status)) return Status;
1131
1132 Console = Buff->Header.Console;
1133
1134 Size = CursorInfoRequest->Info.dwSize;
1135 Visible = CursorInfoRequest->Info.bVisible;
1136 if (Size < 1)
1137 {
1138 Size = 1;
1139 }
1140 if (100 < Size)
1141 {
1142 Size = 100;
1143 }
1144
1145 if ( (Size != Buff->CursorInfo.dwSize) ||
1146 (Visible && ! Buff->CursorInfo.bVisible) ||
1147 (! Visible && Buff->CursorInfo.bVisible) )
1148 {
1149 Buff->CursorInfo.dwSize = Size;
1150 Buff->CursorInfo.bVisible = Visible;
1151
1152 if (!ConioSetCursorInfo(Console, Buff))
1153 {
1154 ConioReleaseScreenBuffer(Buff, TRUE);
1155 return STATUS_UNSUCCESSFUL;
1156 }
1157 }
1158
1159 ConioReleaseScreenBuffer(Buff, TRUE);
1160
1161 return STATUS_SUCCESS;
1162 }
1163
1164 CSR_API(SrvSetConsoleCursorPosition)
1165 {
1166 NTSTATUS Status;
1167 PCONSOLE_SETCURSORPOSITION SetCursorPositionRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorPositionRequest;
1168 PCONSOLE Console;
1169 PCONSOLE_SCREEN_BUFFER Buff;
1170 LONG OldCursorX, OldCursorY;
1171 LONG NewCursorX, NewCursorY;
1172
1173 DPRINT("SrvSetConsoleCursorPosition\n");
1174
1175 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetCursorPositionRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1176 if (!NT_SUCCESS(Status)) return Status;
1177
1178 Console = Buff->Header.Console;
1179
1180 NewCursorX = SetCursorPositionRequest->Position.X;
1181 NewCursorY = SetCursorPositionRequest->Position.Y;
1182 if ( NewCursorX < 0 || NewCursorX >= Buff->MaxX ||
1183 NewCursorY < 0 || NewCursorY >= Buff->MaxY )
1184 {
1185 ConioReleaseScreenBuffer(Buff, TRUE);
1186 return STATUS_INVALID_PARAMETER;
1187 }
1188 OldCursorX = Buff->CurrentX;
1189 OldCursorY = Buff->CurrentY;
1190 Buff->CurrentX = NewCursorX;
1191 Buff->CurrentY = NewCursorY;
1192 if (Buff == Console->ActiveBuffer)
1193 {
1194 if (!ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
1195 {
1196 ConioReleaseScreenBuffer(Buff, TRUE);
1197 return STATUS_UNSUCCESSFUL;
1198 }
1199 }
1200
1201 ConioReleaseScreenBuffer(Buff, TRUE);
1202
1203 return STATUS_SUCCESS;
1204 }
1205
1206 CSR_API(SrvSetConsoleTextAttribute)
1207 {
1208 NTSTATUS Status;
1209 PCONSOLE_SETTEXTATTRIB SetTextAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetTextAttribRequest;
1210 PCONSOLE Console;
1211 PCONSOLE_SCREEN_BUFFER Buff;
1212
1213 DPRINT("SrvSetConsoleTextAttribute\n");
1214
1215 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetTextAttribRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1216 if (!NT_SUCCESS(Status)) return Status;
1217
1218 Console = Buff->Header.Console;
1219
1220 Buff->DefaultAttrib = SetTextAttribRequest->Attrib;
1221 if (Buff == Console->ActiveBuffer)
1222 {
1223 if (!ConioUpdateScreenInfo(Console, Buff))
1224 {
1225 ConioReleaseScreenBuffer(Buff, TRUE);
1226 return STATUS_UNSUCCESSFUL;
1227 }
1228 }
1229
1230 ConioReleaseScreenBuffer(Buff, TRUE);
1231
1232 return STATUS_SUCCESS;
1233 }
1234
1235 CSR_API(SrvCreateConsoleScreenBuffer)
1236 {
1237 NTSTATUS Status;
1238 PCONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CreateScreenBufferRequest;
1239 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
1240 PCONSOLE Console;
1241 PCONSOLE_SCREEN_BUFFER Buff;
1242
1243 DPRINT("SrvCreateConsoleScreenBuffer\n");
1244
1245 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
1246
1247 Status = ConioGetConsole(ProcessData, &Console, TRUE);
1248 if (!NT_SUCCESS(Status))
1249 {
1250 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
1251 return Status;
1252 }
1253
1254 Buff = RtlAllocateHeap(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CONSOLE_SCREEN_BUFFER));
1255 if (Buff != NULL)
1256 {
1257 if (Console->ActiveBuffer)
1258 {
1259 Buff->MaxX = Console->ActiveBuffer->MaxX;
1260 Buff->MaxY = Console->ActiveBuffer->MaxY;
1261 Buff->CursorInfo.bVisible = Console->ActiveBuffer->CursorInfo.bVisible;
1262 Buff->CursorInfo.dwSize = Console->ActiveBuffer->CursorInfo.dwSize;
1263 }
1264 else
1265 {
1266 Buff->CursorInfo.bVisible = TRUE;
1267 Buff->CursorInfo.dwSize = CSR_DEFAULT_CURSOR_SIZE;
1268 }
1269
1270 if (Buff->MaxX == 0)
1271 {
1272 Buff->MaxX = 80;
1273 }
1274
1275 if (Buff->MaxY == 0)
1276 {
1277 Buff->MaxY = 25;
1278 }
1279
1280 Status = CsrInitConsoleScreenBuffer(Console, Buff);
1281 if (NT_SUCCESS(Status))
1282 {
1283 Status = Win32CsrInsertObject(ProcessData,
1284 &CreateScreenBufferRequest->OutputHandle,
1285 &Buff->Header,
1286 CreateScreenBufferRequest->Access,
1287 CreateScreenBufferRequest->Inheritable,
1288 CreateScreenBufferRequest->ShareMode);
1289 }
1290 }
1291 else
1292 {
1293 Status = STATUS_INSUFFICIENT_RESOURCES;
1294 }
1295
1296 ConioReleaseConsole(Console, TRUE);
1297
1298 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
1299
1300 return Status;
1301 }
1302
1303 CSR_API(SrvGetConsoleScreenBufferInfo)
1304 {
1305 NTSTATUS Status;
1306 PCONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScreenBufferInfoRequest;
1307 PCONSOLE Console;
1308 PCONSOLE_SCREEN_BUFFER Buff;
1309 PCONSOLE_SCREEN_BUFFER_INFO pInfo = &ScreenBufferInfoRequest->Info;
1310
1311 DPRINT("SrvGetConsoleScreenBufferInfo\n");
1312
1313 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ScreenBufferInfoRequest->OutputHandle, &Buff, GENERIC_READ, TRUE);
1314 if (!NT_SUCCESS(Status)) return Status;
1315
1316 Console = Buff->Header.Console;
1317
1318 pInfo->dwSize.X = Buff->MaxX;
1319 pInfo->dwSize.Y = Buff->MaxY;
1320 pInfo->dwCursorPosition.X = Buff->CurrentX;
1321 pInfo->dwCursorPosition.Y = Buff->CurrentY;
1322 pInfo->wAttributes = Buff->DefaultAttrib;
1323 pInfo->srWindow.Left = Buff->ShowX;
1324 pInfo->srWindow.Right = Buff->ShowX + Console->Size.X - 1;
1325 pInfo->srWindow.Top = Buff->ShowY;
1326 pInfo->srWindow.Bottom = Buff->ShowY + Console->Size.Y - 1;
1327 pInfo->dwMaximumWindowSize.X = Buff->MaxX;
1328 pInfo->dwMaximumWindowSize.Y = Buff->MaxY;
1329
1330 ConioReleaseScreenBuffer(Buff, TRUE);
1331
1332 return STATUS_SUCCESS;
1333 }
1334
1335 CSR_API(SrvSetConsoleActiveScreenBuffer)
1336 {
1337 NTSTATUS Status;
1338 PCONSOLE_SETACTIVESCREENBUFFER SetScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferRequest;
1339 PCONSOLE Console;
1340 PCONSOLE_SCREEN_BUFFER Buff;
1341
1342 DPRINT("SrvSetConsoleActiveScreenBuffer\n");
1343
1344 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetScreenBufferRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1345 if (!NT_SUCCESS(Status)) return Status;
1346
1347 Console = Buff->Header.Console;
1348
1349 if (Buff == Console->ActiveBuffer)
1350 {
1351 ConioReleaseScreenBuffer(Buff, TRUE);
1352 return STATUS_SUCCESS;
1353 }
1354
1355 /* If old buffer has no handles, it's now unreferenced */
1356 if (Console->ActiveBuffer->Header.HandleCount == 0)
1357 {
1358 ConioDeleteScreenBuffer(Console->ActiveBuffer);
1359 }
1360
1361 /* Tie console to new buffer */
1362 Console->ActiveBuffer = Buff;
1363
1364 /* Redraw the console */
1365 ConioDrawConsole(Console);
1366
1367 ConioReleaseScreenBuffer(Buff, TRUE);
1368
1369 return STATUS_SUCCESS;
1370 }
1371
1372 CSR_API(SrvScrollConsoleScreenBuffer)
1373 {
1374 PCONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScrollScreenBufferRequest;
1375 PCONSOLE Console;
1376 PCONSOLE_SCREEN_BUFFER Buff;
1377 SMALL_RECT ScreenBuffer;
1378 SMALL_RECT SrcRegion;
1379 SMALL_RECT DstRegion;
1380 SMALL_RECT UpdateRegion;
1381 SMALL_RECT ScrollRectangle;
1382 SMALL_RECT ClipRectangle;
1383 NTSTATUS Status;
1384 HANDLE OutputHandle;
1385 BOOLEAN UseClipRectangle;
1386 COORD DestinationOrigin;
1387 CHAR_INFO Fill;
1388 CHAR FillChar;
1389
1390 DPRINT("SrvScrollConsoleScreenBuffer\n");
1391
1392 OutputHandle = ScrollScreenBufferRequest->OutputHandle;
1393 UseClipRectangle = ScrollScreenBufferRequest->UseClipRectangle;
1394 DestinationOrigin = ScrollScreenBufferRequest->DestinationOrigin;
1395 Fill = ScrollScreenBufferRequest->Fill;
1396
1397 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1398 if (!NT_SUCCESS(Status)) return Status;
1399
1400 Console = Buff->Header.Console;
1401
1402 ScrollRectangle = ScrollScreenBufferRequest->ScrollRectangle;
1403
1404 /* Make sure source rectangle is inside the screen buffer */
1405 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1406 if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, &ScrollRectangle))
1407 {
1408 ConioReleaseScreenBuffer(Buff, TRUE);
1409 return STATUS_SUCCESS;
1410 }
1411
1412 /* If the source was clipped on the left or top, adjust the destination accordingly */
1413 if (ScrollRectangle.Left < 0)
1414 {
1415 DestinationOrigin.X -= ScrollRectangle.Left;
1416 }
1417 if (ScrollRectangle.Top < 0)
1418 {
1419 DestinationOrigin.Y -= ScrollRectangle.Top;
1420 }
1421
1422 if (UseClipRectangle)
1423 {
1424 ClipRectangle = ScrollScreenBufferRequest->ClipRectangle;
1425 if (!ConioGetIntersection(&ClipRectangle, &ClipRectangle, &ScreenBuffer))
1426 {
1427 ConioReleaseScreenBuffer(Buff, TRUE);
1428 return STATUS_SUCCESS;
1429 }
1430 }
1431 else
1432 {
1433 ClipRectangle = ScreenBuffer;
1434 }
1435
1436 ConioInitRect(&DstRegion,
1437 DestinationOrigin.Y,
1438 DestinationOrigin.X,
1439 DestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
1440 DestinationOrigin.X + ConioRectWidth(&SrcRegion) - 1);
1441
1442 if (ScrollScreenBufferRequest->Unicode)
1443 ConsoleUnicodeCharToAnsiChar(Console, &FillChar, &Fill.Char.UnicodeChar);
1444 else
1445 FillChar = Fill.Char.AsciiChar;
1446
1447 ConioMoveRegion(Buff, &SrcRegion, &DstRegion, &ClipRectangle, Fill.Attributes << 8 | (BYTE)FillChar);
1448
1449 if (Buff == Console->ActiveBuffer)
1450 {
1451 ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
1452 if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &ClipRectangle))
1453 {
1454 /* Draw update region */
1455 ConioDrawRegion(Console, &UpdateRegion);
1456 }
1457 }
1458
1459 ConioReleaseScreenBuffer(Buff, TRUE);
1460
1461 return STATUS_SUCCESS;
1462 }
1463
1464 CSR_API(SrvSetConsoleScreenBufferSize)
1465 {
1466 NTSTATUS Status;
1467 PCONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferSizeRequest;
1468 PCONSOLE_SCREEN_BUFFER Buff;
1469
1470 Status = ConioGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), SetScreenBufferSizeRequest->OutputHandle, &Buff, GENERIC_WRITE, TRUE);
1471 if (!NT_SUCCESS(Status)) return Status;
1472
1473 Status = ConioResizeBuffer(Buff->Header.Console, Buff, SetScreenBufferSizeRequest->Size);
1474 ConioReleaseScreenBuffer(Buff, TRUE);
1475
1476 return Status;
1477 }
1478
1479 /* EOF */