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