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