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