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