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