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