179ff1aa25e6dd8156aabf47c0756dcbba5ad544
[reactos.git] / win32ss / user / winsrv / consrv / condrv / text.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Driver DLL
4 * FILE: win32ss/user/winsrv/consrv/condrv/text.c
5 * PURPOSE: Console Output Functions for text-mode screen-buffers
6 * PROGRAMMERS: Jeffrey Morlan
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <consrv.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 /* PRIVATE FUNCTIONS **********************************************************/
20
21 CONSOLE_IO_OBJECT_TYPE
22 TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This)
23 {
24 // return This->Header.Type;
25 return TEXTMODE_BUFFER;
26 }
27
28 static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl =
29 {
30 TEXTMODE_BUFFER_GetType,
31 };
32
33
34 /*static*/ VOID
35 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff);
36
37
38 NTSTATUS
39 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
40 IN OUT PCONSOLE Console,
41 IN PCONSOLE_SCREEN_BUFFER_VTBL Vtbl,
42 IN SIZE_T Size);
43 VOID
44 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
45
46
47 NTSTATUS
48 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
49 IN OUT PCONSOLE Console,
50 IN PTEXTMODE_BUFFER_INFO TextModeInfo)
51 {
52 NTSTATUS Status = STATUS_SUCCESS;
53 PTEXTMODE_SCREEN_BUFFER NewBuffer = NULL;
54
55 if (Console == NULL || Buffer == NULL || TextModeInfo == NULL)
56 return STATUS_INVALID_PARAMETER;
57
58 *Buffer = NULL;
59
60 Status = CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER*)&NewBuffer,
61 Console,
62 &TextVtbl,
63 sizeof(TEXTMODE_SCREEN_BUFFER));
64 if (!NT_SUCCESS(Status)) return Status;
65 NewBuffer->Header.Type = TEXTMODE_BUFFER;
66
67 NewBuffer->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
68 TextModeInfo->ScreenBufferSize.X *
69 TextModeInfo->ScreenBufferSize.Y *
70 sizeof(CHAR_INFO));
71 if (NewBuffer->Buffer == NULL)
72 {
73 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
74 return STATUS_INSUFFICIENT_RESOURCES;
75 }
76
77 NewBuffer->ScreenBufferSize = NewBuffer->OldScreenBufferSize
78 = TextModeInfo->ScreenBufferSize;
79 NewBuffer->ViewSize = NewBuffer->OldViewSize
80 = Console->ConsoleSize;
81
82 NewBuffer->ViewOrigin.X = NewBuffer->ViewOrigin.Y = 0;
83 NewBuffer->VirtualY = 0;
84
85 NewBuffer->CursorBlinkOn = NewBuffer->ForceCursorOff = FALSE;
86 NewBuffer->CursorInfo.bVisible = (TextModeInfo->IsCursorVisible && (TextModeInfo->CursorSize != 0));
87 NewBuffer->CursorInfo.dwSize = min(max(TextModeInfo->CursorSize, 0), 100);
88
89 NewBuffer->ScreenDefaultAttrib = TextModeInfo->ScreenAttrib;
90 NewBuffer->PopupDefaultAttrib = TextModeInfo->PopupAttrib;
91
92 /* Initialize buffer to be empty with default attributes */
93 for (NewBuffer->CursorPosition.Y = 0 ; NewBuffer->CursorPosition.Y < NewBuffer->ScreenBufferSize.Y; NewBuffer->CursorPosition.Y++)
94 {
95 ClearLineBuffer(NewBuffer);
96 }
97 NewBuffer->CursorPosition.X = NewBuffer->CursorPosition.Y = 0;
98
99 NewBuffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
100
101 *Buffer = (PCONSOLE_SCREEN_BUFFER)NewBuffer;
102 return STATUS_SUCCESS;
103 }
104
105 VOID
106 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
107 {
108 PTEXTMODE_SCREEN_BUFFER Buff = (PTEXTMODE_SCREEN_BUFFER)Buffer;
109
110 /*
111 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
112 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
113 */
114 Buffer->Header.Type = SCREEN_BUFFER;
115
116 ConsoleFreeHeap(Buff->Buffer);
117
118 CONSOLE_SCREEN_BUFFER_Destroy(Buffer);
119 }
120
121
122 PCHAR_INFO
123 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
124 {
125 return &Buff->Buffer[((Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y) * Buff->ScreenBufferSize.X + X];
126 }
127
128 /*static*/ VOID
129 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff)
130 {
131 PCHAR_INFO Ptr = ConioCoordToPointer(Buff, 0, Buff->CursorPosition.Y);
132 SHORT Pos;
133
134 for (Pos = 0; Pos < Buff->ScreenBufferSize.X; Pos++, Ptr++)
135 {
136 /* Fill the cell */
137 Ptr->Char.UnicodeChar = L' ';
138 Ptr->Attributes = Buff->ScreenDefaultAttrib;
139 }
140 }
141
142 static VOID
143 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff,
144 IN OUT PSMALL_RECT UpdateRect,
145 IN PCOORD Start,
146 IN UINT Length)
147 {
148 if (Buff->ScreenBufferSize.X <= Start->X + Length)
149 {
150 UpdateRect->Left = 0;
151 }
152 else
153 {
154 UpdateRect->Left = Start->X;
155 }
156 if (Buff->ScreenBufferSize.X <= Start->X + Length)
157 {
158 UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
159 }
160 else
161 {
162 UpdateRect->Right = Start->X + Length - 1;
163 }
164 UpdateRect->Top = Start->Y;
165 UpdateRect->Bottom = Start->Y + (Start->X + Length - 1) / Buff->ScreenBufferSize.X;
166 if (Buff->ScreenBufferSize.Y <= UpdateRect->Bottom)
167 {
168 UpdateRect->Bottom = Buff->ScreenBufferSize.Y - 1;
169 }
170 }
171
172 /*
173 * Move from one rectangle to another. We must be careful about the order that
174 * this is done, to avoid overwriting parts of the source before they are moved.
175 */
176 static VOID
177 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
178 PSMALL_RECT SrcRegion,
179 PSMALL_RECT DstRegion,
180 PSMALL_RECT ClipRegion,
181 CHAR_INFO FillChar)
182 {
183 int Width = ConioRectWidth(SrcRegion);
184 int Height = ConioRectHeight(SrcRegion);
185 int SX, SY;
186 int DX, DY;
187 int XDelta, YDelta;
188 int i, j;
189
190 SY = SrcRegion->Top;
191 DY = DstRegion->Top;
192 YDelta = 1;
193 if (SY < DY)
194 {
195 /* Moving down: work from bottom up */
196 SY = SrcRegion->Bottom;
197 DY = DstRegion->Bottom;
198 YDelta = -1;
199 }
200 for (i = 0; i < Height; i++)
201 {
202 PCHAR_INFO SRow = ConioCoordToPointer(ScreenBuffer, 0, SY);
203 PCHAR_INFO DRow = ConioCoordToPointer(ScreenBuffer, 0, DY);
204
205 SX = SrcRegion->Left;
206 DX = DstRegion->Left;
207 XDelta = 1;
208 if (SX < DX)
209 {
210 /* Moving right: work from right to left */
211 SX = SrcRegion->Right;
212 DX = DstRegion->Right;
213 XDelta = -1;
214 }
215 for (j = 0; j < Width; j++)
216 {
217 CHAR_INFO Cell = SRow[SX];
218 if (SX >= ClipRegion->Left && SX <= ClipRegion->Right &&
219 SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
220 {
221 SRow[SX] = FillChar;
222 }
223 if (DX >= ClipRegion->Left && DX <= ClipRegion->Right &&
224 DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
225 {
226 DRow[DX] = Cell;
227 }
228 SX += XDelta;
229 DX += XDelta;
230 }
231 SY += YDelta;
232 DY += YDelta;
233 }
234 }
235
236 // FIXME!
237 NTSTATUS NTAPI
238 ConDrvWriteConsoleInput(IN PCONSOLE Console,
239 IN PCONSOLE_INPUT_BUFFER InputBuffer,
240 IN BOOLEAN AppendToEnd,
241 IN PINPUT_RECORD InputRecord,
242 IN ULONG NumEventsToWrite,
243 OUT PULONG NumEventsWritten OPTIONAL);
244
245 NTSTATUS
246 ConioResizeBuffer(PCONSOLE Console,
247 PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
248 COORD Size)
249 {
250 PCHAR_INFO Buffer;
251 DWORD Offset = 0;
252 PCHAR_INFO ptr;
253 WORD CurrentAttribute;
254 USHORT CurrentY;
255 PCHAR_INFO OldBuffer;
256 DWORD i;
257 DWORD diff;
258
259 /* Buffer size is not allowed to be smaller than the view size */
260 if (Size.X < ScreenBuffer->ViewSize.X || Size.Y < ScreenBuffer->ViewSize.Y)
261 return STATUS_INVALID_PARAMETER;
262
263 if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y)
264 {
265 // FIXME: Trigger a buffer resize event ??
266 return STATUS_SUCCESS;
267 }
268
269 if (Console->FixedSize)
270 {
271 /*
272 * The console is in fixed-size mode, so we cannot resize anything
273 * at the moment. However, keep those settings somewhere so that
274 * we can try to set them up when we will be allowed to do so.
275 */
276 ScreenBuffer->OldScreenBufferSize = Size;
277 return STATUS_NOT_SUPPORTED; // STATUS_SUCCESS
278 }
279
280 Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size.X * Size.Y * sizeof(CHAR_INFO));
281 if (!Buffer) return STATUS_NO_MEMORY;
282
283 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y);
284 OldBuffer = ScreenBuffer->Buffer;
285
286 for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++)
287 {
288 ptr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
289 if (Size.X <= ScreenBuffer->ScreenBufferSize.X)
290 {
291 /* Reduce size */
292 RtlCopyMemory(Buffer + Offset, ptr, Size.X * sizeof(CHAR_INFO));
293 Offset += Size.X;
294 }
295 else
296 {
297 /* Enlarge size */
298 RtlCopyMemory(Buffer + Offset, ptr, ScreenBuffer->ScreenBufferSize.X * sizeof(CHAR_INFO));
299 Offset += ScreenBuffer->ScreenBufferSize.X;
300
301 /* The attribute to be used is the one of the last cell of the current line */
302 CurrentAttribute = ConioCoordToPointer(ScreenBuffer,
303 ScreenBuffer->ScreenBufferSize.X - 1,
304 CurrentY)->Attributes;
305
306 diff = Size.X - ScreenBuffer->ScreenBufferSize.X;
307
308 /* Zero-out the new part of the buffer */
309 for (i = 0; i < diff; i++)
310 {
311 ptr = Buffer + Offset;
312 ptr->Char.UnicodeChar = L' ';
313 ptr->Attributes = CurrentAttribute;
314 ++Offset;
315 }
316 }
317 }
318
319 if (Size.Y > ScreenBuffer->ScreenBufferSize.Y)
320 {
321 diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y);
322
323 /* Zero-out the new part of the buffer */
324 for (i = 0; i < diff; i++)
325 {
326 ptr = Buffer + Offset;
327 ptr->Char.UnicodeChar = L' ';
328 ptr->Attributes = ScreenBuffer->ScreenDefaultAttrib;
329 ++Offset;
330 }
331 }
332
333 (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer);
334 ConsoleFreeHeap(OldBuffer);
335 ScreenBuffer->ScreenBufferSize = ScreenBuffer->OldScreenBufferSize = Size;
336 ScreenBuffer->VirtualY = 0;
337
338 /* Ensure cursor and window are within buffer */
339 if (ScreenBuffer->CursorPosition.X >= Size.X)
340 ScreenBuffer->CursorPosition.X = Size.X - 1;
341 if (ScreenBuffer->CursorPosition.Y >= Size.Y)
342 ScreenBuffer->CursorPosition.Y = Size.Y - 1;
343 if (ScreenBuffer->ViewOrigin.X > Size.X - ScreenBuffer->ViewSize.X)
344 ScreenBuffer->ViewOrigin.X = Size.X - ScreenBuffer->ViewSize.X;
345 if (ScreenBuffer->ViewOrigin.Y > Size.Y - ScreenBuffer->ViewSize.Y)
346 ScreenBuffer->ViewOrigin.Y = Size.Y - ScreenBuffer->ViewSize.Y;
347
348 /*
349 * Trigger a buffer resize event
350 */
351 if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT)
352 {
353 ULONG NumEventsWritten;
354 INPUT_RECORD er;
355
356 er.EventType = WINDOW_BUFFER_SIZE_EVENT;
357 er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize;
358
359 // ConioProcessInputEvent(Console, &er);
360 ConDrvWriteConsoleInput(Console,
361 &Console->InputBuffer,
362 TRUE,
363 &er,
364 1,
365 &NumEventsWritten);
366 }
367
368 return STATUS_SUCCESS;
369 }
370
371 NTSTATUS NTAPI
372 ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console,
373 IN PTEXTMODE_SCREEN_BUFFER Buffer,
374 IN USHORT NewScreenAttrib,
375 IN USHORT NewPopupAttrib)
376 {
377 DWORD X, Y, Length;
378 PCHAR_INFO Ptr;
379
380 COORD TopLeft = {0};
381 ULONG NumCodesToWrite;
382 USHORT OldScreenAttrib, OldPopupAttrib;
383
384 if (Console == NULL || Buffer == NULL)
385 {
386 return STATUS_INVALID_PARAMETER;
387 }
388
389 /* Validity check */
390 ASSERT(Console == Buffer->Header.Console);
391
392 NumCodesToWrite = Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y;
393 OldScreenAttrib = Buffer->ScreenDefaultAttrib;
394 OldPopupAttrib = Buffer->PopupDefaultAttrib;
395
396 X = TopLeft.X;
397 Y = (TopLeft.Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
398 Length = NumCodesToWrite;
399
400 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
401 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
402
403 while (Length--)
404 {
405 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
406 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
407
408 /*
409 * Change the current colors only if they are the old ones.
410 */
411
412 /* Foreground color */
413 if ((Ptr->Attributes & 0x0F) == (OldScreenAttrib & 0x0F))
414 Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewScreenAttrib & 0x0F);
415 if ((Ptr->Attributes & 0x0F) == (OldPopupAttrib & 0x0F))
416 Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewPopupAttrib & 0x0F);
417
418 /* Background color */
419 if ((Ptr->Attributes & 0xF0) == (OldScreenAttrib & 0xF0))
420 Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewScreenAttrib & 0xF0);
421 if ((Ptr->Attributes & 0xF0) == (OldPopupAttrib & 0xF0))
422 Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewPopupAttrib & 0xF0);
423
424 // ++Ptr;
425
426 if (++X == Buffer->ScreenBufferSize.X)
427 {
428 X = 0;
429
430 if (++Y == Buffer->ScreenBufferSize.Y)
431 {
432 Y = 0;
433 }
434 }
435 }
436
437 /* Save foreground and background colors for both screen and popup */
438 Buffer->ScreenDefaultAttrib = (NewScreenAttrib & 0x00FF);
439 Buffer->PopupDefaultAttrib = (NewPopupAttrib & 0x00FF);
440
441 /* Refresh the display if needed */
442 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
443 {
444 SMALL_RECT UpdateRect;
445 ConioComputeUpdateRect(Buffer, &UpdateRect, &TopLeft, NumCodesToWrite);
446 TermDrawRegion(Console, &UpdateRect);
447 }
448
449 return STATUS_SUCCESS;
450 }
451
452
453 /* PUBLIC DRIVER APIS *********************************************************/
454
455 NTSTATUS NTAPI
456 ConDrvReadConsoleOutput(IN PCONSOLE Console,
457 IN PTEXTMODE_SCREEN_BUFFER Buffer,
458 IN BOOLEAN Unicode,
459 OUT PCHAR_INFO CharInfo/*Buffer*/,
460 IN OUT PSMALL_RECT ReadRegion)
461 {
462 SHORT X, Y;
463 SMALL_RECT ScreenBuffer;
464 PCHAR_INFO CurCharInfo;
465 SMALL_RECT CapturedReadRegion;
466 PCHAR_INFO Ptr;
467
468 if (Console == NULL || Buffer == NULL || CharInfo == NULL || ReadRegion == NULL)
469 {
470 return STATUS_INVALID_PARAMETER;
471 }
472
473 /* Validity check */
474 ASSERT(Console == Buffer->Header.Console);
475
476 CapturedReadRegion = *ReadRegion;
477
478 /* Make sure ReadRegion is inside the screen buffer */
479 ConioInitRect(&ScreenBuffer, 0, 0,
480 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
481 if (!ConioGetIntersection(&CapturedReadRegion, &ScreenBuffer, &CapturedReadRegion))
482 {
483 /*
484 * It is okay to have a ReadRegion completely outside
485 * the screen buffer. No data is read then.
486 */
487 return STATUS_SUCCESS;
488 }
489
490 CurCharInfo = CharInfo;
491
492 for (Y = CapturedReadRegion.Top; Y <= CapturedReadRegion.Bottom; ++Y)
493 {
494 Ptr = ConioCoordToPointer(Buffer, CapturedReadRegion.Left, Y);
495 for (X = CapturedReadRegion.Left; X <= CapturedReadRegion.Right; ++X)
496 {
497 if (Unicode)
498 {
499 CurCharInfo->Char.UnicodeChar = Ptr->Char.UnicodeChar;
500 }
501 else
502 {
503 // ConsoleUnicodeCharToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
504 WideCharToMultiByte(Console->OutputCodePage, 0, &Ptr->Char.UnicodeChar, 1,
505 &CurCharInfo->Char.AsciiChar, 1, NULL, NULL);
506 }
507 CurCharInfo->Attributes = Ptr->Attributes;
508 ++Ptr;
509 ++CurCharInfo;
510 }
511 }
512
513 *ReadRegion = CapturedReadRegion;
514
515 return STATUS_SUCCESS;
516 }
517
518 NTSTATUS NTAPI
519 ConDrvWriteConsoleOutput(IN PCONSOLE Console,
520 IN PTEXTMODE_SCREEN_BUFFER Buffer,
521 IN BOOLEAN Unicode,
522 IN PCHAR_INFO CharInfo/*Buffer*/,
523 IN OUT PSMALL_RECT WriteRegion)
524 {
525 SHORT X, Y;
526 SMALL_RECT ScreenBuffer;
527 PCHAR_INFO CurCharInfo;
528 SMALL_RECT CapturedWriteRegion;
529 PCHAR_INFO Ptr;
530
531 if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL)
532 {
533 return STATUS_INVALID_PARAMETER;
534 }
535
536 /* Validity check */
537 ASSERT(Console == Buffer->Header.Console);
538
539 CapturedWriteRegion = *WriteRegion;
540
541 /* Make sure WriteRegion is inside the screen buffer */
542 ConioInitRect(&ScreenBuffer, 0, 0,
543 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
544 if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
545 {
546 /*
547 * It is okay to have a WriteRegion completely outside
548 * the screen buffer. No data is written then.
549 */
550 return STATUS_SUCCESS;
551 }
552
553 CurCharInfo = CharInfo;
554
555 for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y)
556 {
557 Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
558 for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X)
559 {
560 if (Unicode)
561 {
562 Ptr->Char.UnicodeChar = CurCharInfo->Char.UnicodeChar;
563 }
564 else
565 {
566 ConsoleAnsiCharToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char.AsciiChar);
567 }
568 Ptr->Attributes = CurCharInfo->Attributes;
569 ++Ptr;
570 ++CurCharInfo;
571 }
572 }
573
574 TermDrawRegion(Console, &CapturedWriteRegion);
575
576 *WriteRegion = CapturedWriteRegion;
577
578 return STATUS_SUCCESS;
579 }
580
581 /*
582 * NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput...
583 */
584 NTSTATUS NTAPI
585 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console,
586 IN PTEXTMODE_SCREEN_BUFFER Buffer,
587 IN PCHAR_CELL CharInfo/*Buffer*/,
588 IN COORD CharInfoSize,
589 IN OUT PSMALL_RECT WriteRegion,
590 IN BOOLEAN DrawRegion)
591 {
592 SHORT X, Y;
593 SMALL_RECT ScreenBuffer;
594 PCHAR_CELL CurCharInfo;
595 SMALL_RECT CapturedWriteRegion;
596 PCHAR_INFO Ptr;
597
598 if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL)
599 {
600 return STATUS_INVALID_PARAMETER;
601 }
602
603 /* Validity check */
604 ASSERT(Console == Buffer->Header.Console);
605
606 CapturedWriteRegion = *WriteRegion;
607
608 /* Make sure WriteRegion is inside the screen buffer */
609 ConioInitRect(&ScreenBuffer, 0, 0,
610 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
611 if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
612 {
613 /*
614 * It is okay to have a WriteRegion completely outside
615 * the screen buffer. No data is written then.
616 */
617 return STATUS_SUCCESS;
618 }
619
620 // CurCharInfo = CharInfo;
621
622 for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y)
623 {
624 /**/CurCharInfo = CharInfo + Y * CharInfoSize.X + CapturedWriteRegion.Left;/**/
625
626 Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
627 for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X)
628 {
629 ConsoleAnsiCharToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char);
630 Ptr->Attributes = CurCharInfo->Attributes;
631 ++Ptr;
632 ++CurCharInfo;
633 }
634 }
635
636 if (DrawRegion) TermDrawRegion(Console, &CapturedWriteRegion);
637
638 *WriteRegion = CapturedWriteRegion;
639
640 return STATUS_SUCCESS;
641 }
642
643 NTSTATUS NTAPI
644 ConDrvWriteConsole(IN PCONSOLE Console,
645 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
646 IN BOOLEAN Unicode,
647 IN PVOID StringBuffer,
648 IN ULONG NumCharsToWrite,
649 OUT PULONG NumCharsWritten OPTIONAL)
650 {
651 NTSTATUS Status = STATUS_SUCCESS;
652 PWCHAR Buffer = NULL;
653 ULONG Written = 0;
654 ULONG Length;
655
656 if (Console == NULL || ScreenBuffer == NULL /* || StringBuffer == NULL */)
657 return STATUS_INVALID_PARAMETER;
658
659 /* Validity checks */
660 ASSERT(Console == ScreenBuffer->Header.Console);
661 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCharsToWrite == 0));
662
663 /* Stop here if the console is paused */
664 if (Console->UnpauseEvent != NULL) return STATUS_PENDING;
665
666 /* Convert the string to UNICODE */
667 if (Unicode)
668 {
669 Buffer = StringBuffer;
670 }
671 else
672 {
673 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
674 (PCHAR)StringBuffer,
675 NumCharsToWrite,
676 NULL, 0);
677 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
678 if (Buffer)
679 {
680 MultiByteToWideChar(Console->OutputCodePage, 0,
681 (PCHAR)StringBuffer,
682 NumCharsToWrite,
683 (PWCHAR)Buffer, Length);
684 }
685 else
686 {
687 Status = STATUS_NO_MEMORY;
688 }
689 }
690
691 /* Send it */
692 if (Buffer)
693 {
694 if (NT_SUCCESS(Status))
695 {
696 Status = TermWriteStream(Console,
697 ScreenBuffer,
698 Buffer,
699 NumCharsToWrite,
700 TRUE);
701 if (NT_SUCCESS(Status))
702 {
703 Written = NumCharsToWrite;
704 }
705 }
706
707 if (!Unicode) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
708 }
709
710 if (NumCharsWritten) *NumCharsWritten = Written;
711
712 return Status;
713 }
714
715 NTSTATUS NTAPI
716 ConDrvReadConsoleOutputString(IN PCONSOLE Console,
717 IN PTEXTMODE_SCREEN_BUFFER Buffer,
718 IN CODE_TYPE CodeType,
719 OUT PVOID StringBuffer,
720 IN ULONG NumCodesToRead,
721 IN PCOORD ReadCoord,
722 // OUT PCOORD EndCoord,
723 OUT PULONG NumCodesRead OPTIONAL)
724 {
725 SHORT Xpos, Ypos;
726 PVOID ReadBuffer;
727 ULONG i;
728 ULONG CodeSize;
729 PCHAR_INFO Ptr;
730
731 if (Console == NULL || Buffer == NULL || ReadCoord == NULL /* || EndCoord == NULL */)
732 {
733 return STATUS_INVALID_PARAMETER;
734 }
735
736 /* Validity checks */
737 ASSERT(Console == Buffer->Header.Console);
738 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToRead == 0));
739
740 //
741 // FIXME: Make overflow checks on ReadCoord !!!!!!
742 //
743
744 if (NumCodesRead) *NumCodesRead = 0;
745
746 switch (CodeType)
747 {
748 case CODE_ASCII:
749 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
750 break;
751
752 case CODE_UNICODE:
753 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
754 break;
755
756 case CODE_ATTRIBUTE:
757 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
758 break;
759
760 default:
761 return STATUS_INVALID_PARAMETER;
762 }
763
764 ReadBuffer = StringBuffer;
765 Xpos = ReadCoord->X;
766 Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
767
768 /*
769 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
770 *
771 * If the number of attributes (resp. characters) to be read from extends
772 * beyond the end of the specified screen buffer row, attributes (resp.
773 * characters) are read from the next row. If the number of attributes
774 * (resp. characters) to be read from extends beyond the end of the console
775 * screen buffer, attributes (resp. characters) up to the end of the console
776 * screen buffer are read.
777 *
778 * TODO: Do NOT loop up to NumCodesToRead, but stop before
779 * if we are going to overflow...
780 */
781 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work
782 for (i = 0; i < min(NumCodesToRead, Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y); ++i)
783 {
784 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either
785 Ptr = &Buffer->Buffer[Xpos + Ypos * Buffer->ScreenBufferSize.X];
786
787 switch (CodeType)
788 {
789 case CODE_ASCII:
790 ConsoleUnicodeCharToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
791 break;
792
793 case CODE_UNICODE:
794 *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
795 break;
796
797 case CODE_ATTRIBUTE:
798 *(PWORD)ReadBuffer = Ptr->Attributes;
799 break;
800 }
801 ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
802 // ++Ptr;
803
804 Xpos++;
805
806 if (Xpos == Buffer->ScreenBufferSize.X)
807 {
808 Xpos = 0;
809 Ypos++;
810
811 if (Ypos == Buffer->ScreenBufferSize.Y)
812 {
813 Ypos = 0;
814 }
815 }
816 }
817
818 // EndCoord->X = Xpos;
819 // EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y;
820
821 if (NumCodesRead)
822 *NumCodesRead = (ULONG)((ULONG_PTR)ReadBuffer - (ULONG_PTR)StringBuffer) / CodeSize;
823 // <= NumCodesToRead
824
825 return STATUS_SUCCESS;
826 }
827
828 NTSTATUS NTAPI
829 ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
830 IN PTEXTMODE_SCREEN_BUFFER Buffer,
831 IN CODE_TYPE CodeType,
832 IN PVOID StringBuffer,
833 IN ULONG NumCodesToWrite,
834 IN PCOORD WriteCoord,
835 // OUT PCOORD EndCoord,
836 OUT PULONG NumCodesWritten OPTIONAL)
837 {
838 NTSTATUS Status = STATUS_SUCCESS;
839 PVOID WriteBuffer = NULL;
840 PWCHAR tmpString = NULL;
841 DWORD X, Y, Length; // , Written = 0;
842 ULONG CodeSize;
843 PCHAR_INFO Ptr;
844
845 if (Console == NULL || Buffer == NULL || WriteCoord == NULL /* || EndCoord == NULL */)
846 {
847 return STATUS_INVALID_PARAMETER;
848 }
849
850 /* Validity checks */
851 ASSERT(Console == Buffer->Header.Console);
852 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToWrite == 0));
853
854 //
855 // FIXME: Make overflow checks on WriteCoord !!!!!!
856 //
857
858 if (NumCodesWritten) *NumCodesWritten = 0;
859
860 switch (CodeType)
861 {
862 case CODE_ASCII:
863 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
864 break;
865
866 case CODE_UNICODE:
867 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
868 break;
869
870 case CODE_ATTRIBUTE:
871 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
872 break;
873
874 default:
875 return STATUS_INVALID_PARAMETER;
876 }
877
878 if (CodeType == CODE_ASCII)
879 {
880 /* Convert the ASCII string into Unicode before writing it to the console */
881 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
882 (PCHAR)StringBuffer,
883 NumCodesToWrite,
884 NULL, 0);
885 tmpString = WriteBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
886 if (WriteBuffer)
887 {
888 MultiByteToWideChar(Console->OutputCodePage, 0,
889 (PCHAR)StringBuffer,
890 NumCodesToWrite,
891 (PWCHAR)WriteBuffer, Length);
892 }
893 else
894 {
895 Status = STATUS_NO_MEMORY;
896 }
897
898 // FIXME: Quick fix: fix the CodeType and CodeSize since the
899 // ASCII string was converted into UNICODE.
900 // A proper fix needs to be written.
901 CodeType = CODE_UNICODE;
902 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
903 }
904 else
905 {
906 /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
907 WriteBuffer = StringBuffer;
908 }
909
910 if (WriteBuffer == NULL || !NT_SUCCESS(Status)) goto Cleanup;
911
912 X = WriteCoord->X;
913 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
914 Length = NumCodesToWrite;
915 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
916 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
917
918 while (Length--)
919 {
920 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
921 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
922
923 switch (CodeType)
924 {
925 case CODE_ASCII:
926 case CODE_UNICODE:
927 Ptr->Char.UnicodeChar = *(PWCHAR)WriteBuffer;
928 break;
929
930 case CODE_ATTRIBUTE:
931 Ptr->Attributes = *(PWORD)WriteBuffer;
932 break;
933 }
934 WriteBuffer = (PVOID)((ULONG_PTR)WriteBuffer + CodeSize);
935 // ++Ptr;
936
937 // Written++;
938 if (++X == Buffer->ScreenBufferSize.X)
939 {
940 X = 0;
941
942 if (++Y == Buffer->ScreenBufferSize.Y)
943 {
944 Y = 0;
945 }
946 }
947 }
948
949 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
950 {
951 SMALL_RECT UpdateRect;
952 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
953 TermDrawRegion(Console, &UpdateRect);
954 }
955
956 // EndCoord->X = X;
957 // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
958
959 Cleanup:
960 if (tmpString) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString);
961
962 if (NumCodesWritten) *NumCodesWritten = NumCodesToWrite; // Written;
963 return Status;
964 }
965
966 NTSTATUS NTAPI
967 ConDrvFillConsoleOutput(IN PCONSOLE Console,
968 IN PTEXTMODE_SCREEN_BUFFER Buffer,
969 IN CODE_TYPE CodeType,
970 IN CODE_ELEMENT Code,
971 IN ULONG NumCodesToWrite,
972 IN PCOORD WriteCoord,
973 OUT PULONG NumCodesWritten OPTIONAL)
974 {
975 DWORD X, Y, Length; // , Written = 0;
976 PCHAR_INFO Ptr;
977
978 if (Console == NULL || Buffer == NULL || WriteCoord == NULL)
979 {
980 return STATUS_INVALID_PARAMETER;
981 }
982
983 /* Validity check */
984 ASSERT(Console == Buffer->Header.Console);
985
986 //
987 // FIXME: Make overflow checks on WriteCoord !!!!!!
988 //
989
990 if (NumCodesWritten) *NumCodesWritten = 0;
991
992 if (CodeType == CODE_ASCII)
993 {
994 /* Conversion from the ASCII char to the UNICODE char */
995 CODE_ELEMENT tmp;
996 ConsoleAnsiCharToUnicodeChar(Console, &tmp.UnicodeChar, &Code.AsciiChar);
997 Code = tmp;
998 }
999
1000 X = WriteCoord->X;
1001 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1002 Length = NumCodesToWrite;
1003 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1004 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1005
1006 while (Length--)
1007 {
1008 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1009 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
1010
1011 switch (CodeType)
1012 {
1013 case CODE_ASCII:
1014 case CODE_UNICODE:
1015 Ptr->Char.UnicodeChar = Code.UnicodeChar;
1016 break;
1017
1018 case CODE_ATTRIBUTE:
1019 Ptr->Attributes = Code.Attribute;
1020 break;
1021 }
1022 // ++Ptr;
1023
1024 // Written++;
1025 if (++X == Buffer->ScreenBufferSize.X)
1026 {
1027 X = 0;
1028
1029 if (++Y == Buffer->ScreenBufferSize.Y)
1030 {
1031 Y = 0;
1032 }
1033 }
1034 }
1035
1036 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1037 {
1038 SMALL_RECT UpdateRect;
1039 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
1040 TermDrawRegion(Console, &UpdateRect);
1041 }
1042
1043 if (NumCodesWritten) *NumCodesWritten = NumCodesToWrite; // Written;
1044 return STATUS_SUCCESS;
1045 }
1046
1047 NTSTATUS NTAPI
1048 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console,
1049 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1050 OUT PCOORD ScreenBufferSize,
1051 OUT PCOORD CursorPosition,
1052 OUT PCOORD ViewOrigin,
1053 OUT PCOORD ViewSize,
1054 OUT PCOORD MaximumViewSize,
1055 OUT PWORD Attributes)
1056 {
1057 if (Console == NULL || Buffer == NULL || ScreenBufferSize == NULL ||
1058 CursorPosition == NULL || ViewOrigin == NULL || ViewSize == NULL ||
1059 MaximumViewSize == NULL || Attributes == NULL)
1060 {
1061 return STATUS_INVALID_PARAMETER;
1062 }
1063
1064 /* Validity check */
1065 ASSERT(Console == Buffer->Header.Console);
1066
1067 *ScreenBufferSize = Buffer->ScreenBufferSize;
1068 *CursorPosition = Buffer->CursorPosition;
1069 *ViewOrigin = Buffer->ViewOrigin;
1070 *ViewSize = Buffer->ViewSize;
1071 *Attributes = Buffer->ScreenDefaultAttrib;
1072
1073 // FIXME: Refine the computation
1074 *MaximumViewSize = Buffer->ScreenBufferSize;
1075
1076 return STATUS_SUCCESS;
1077 }
1078
1079 NTSTATUS NTAPI
1080 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
1081 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1082 IN WORD Attributes)
1083 {
1084 if (Console == NULL || Buffer == NULL)
1085 return STATUS_INVALID_PARAMETER;
1086
1087 /* Validity check */
1088 ASSERT(Console == Buffer->Header.Console);
1089
1090 Buffer->ScreenDefaultAttrib = Attributes;
1091 return STATUS_SUCCESS;
1092 }
1093
1094 NTSTATUS NTAPI
1095 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
1096 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1097 IN PCOORD Size)
1098 {
1099 NTSTATUS Status;
1100
1101 if (Console == NULL || Buffer == NULL || Size == NULL)
1102 return STATUS_INVALID_PARAMETER;
1103
1104 /* Validity check */
1105 ASSERT(Console == Buffer->Header.Console);
1106
1107 Status = ConioResizeBuffer(Console, Buffer, *Size);
1108 if (NT_SUCCESS(Status)) TermResizeTerminal(Console);
1109
1110 return Status;
1111 }
1112
1113 NTSTATUS NTAPI
1114 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
1115 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1116 IN BOOLEAN Unicode,
1117 IN PSMALL_RECT ScrollRectangle,
1118 IN BOOLEAN UseClipRectangle,
1119 IN PSMALL_RECT ClipRectangle OPTIONAL,
1120 IN PCOORD DestinationOrigin,
1121 IN CHAR_INFO FillChar)
1122 {
1123 COORD CapturedDestinationOrigin;
1124 SMALL_RECT ScreenBuffer;
1125 SMALL_RECT SrcRegion;
1126 SMALL_RECT DstRegion;
1127 SMALL_RECT UpdateRegion;
1128 SMALL_RECT CapturedClipRectangle;
1129
1130 if (Console == NULL || Buffer == NULL || ScrollRectangle == NULL ||
1131 (UseClipRectangle ? ClipRectangle == NULL : FALSE) || DestinationOrigin == NULL)
1132 {
1133 return STATUS_INVALID_PARAMETER;
1134 }
1135
1136 /* Validity check */
1137 ASSERT(Console == Buffer->Header.Console);
1138
1139 CapturedDestinationOrigin = *DestinationOrigin;
1140
1141 /* Make sure the source rectangle is inside the screen buffer */
1142 ConioInitRect(&ScreenBuffer, 0, 0,
1143 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
1144 if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, ScrollRectangle))
1145 {
1146 return STATUS_SUCCESS;
1147 }
1148
1149 /* If the source was clipped on the left or top, adjust the destination accordingly */
1150 if (ScrollRectangle->Left < 0)
1151 {
1152 CapturedDestinationOrigin.X -= ScrollRectangle->Left;
1153 }
1154 if (ScrollRectangle->Top < 0)
1155 {
1156 CapturedDestinationOrigin.Y -= ScrollRectangle->Top;
1157 }
1158
1159 if (UseClipRectangle)
1160 {
1161 CapturedClipRectangle = *ClipRectangle;
1162 if (!ConioGetIntersection(&CapturedClipRectangle, &CapturedClipRectangle, &ScreenBuffer))
1163 {
1164 return STATUS_SUCCESS;
1165 }
1166 }
1167 else
1168 {
1169 CapturedClipRectangle = ScreenBuffer;
1170 }
1171
1172 ConioInitRect(&DstRegion,
1173 CapturedDestinationOrigin.Y,
1174 CapturedDestinationOrigin.X,
1175 CapturedDestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
1176 CapturedDestinationOrigin.X + ConioRectWidth(&SrcRegion ) - 1);
1177
1178 if (!Unicode)
1179 {
1180 WCHAR tmp;
1181 ConsoleAnsiCharToUnicodeChar(Console, &tmp, &FillChar.Char.AsciiChar);
1182 FillChar.Char.UnicodeChar = tmp;
1183 }
1184
1185 ConioMoveRegion(Buffer, &SrcRegion, &DstRegion, &CapturedClipRectangle, FillChar);
1186
1187 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1188 {
1189 ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
1190 if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &CapturedClipRectangle))
1191 {
1192 /* Draw update region */
1193 TermDrawRegion(Console, &UpdateRegion);
1194 }
1195 }
1196
1197 return STATUS_SUCCESS;
1198 }
1199
1200 NTSTATUS NTAPI
1201 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console,
1202 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1203 IN BOOLEAN Absolute,
1204 IN PSMALL_RECT WindowRect)
1205 {
1206 SMALL_RECT CapturedWindowRect;
1207
1208 if (Console == NULL || Buffer == NULL || WindowRect == NULL)
1209 return STATUS_INVALID_PARAMETER;
1210
1211 /* Validity check */
1212 ASSERT(Console == Buffer->Header.Console);
1213
1214 CapturedWindowRect = *WindowRect;
1215
1216 if (Absolute == FALSE)
1217 {
1218 /* Relative positions given. Transform them to absolute ones */
1219 CapturedWindowRect.Left += Buffer->ViewOrigin.X;
1220 CapturedWindowRect.Top += Buffer->ViewOrigin.Y;
1221 CapturedWindowRect.Right += Buffer->ViewOrigin.X + Buffer->ViewSize.X - 1;
1222 CapturedWindowRect.Bottom += Buffer->ViewOrigin.Y + Buffer->ViewSize.Y - 1;
1223 }
1224
1225 /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */
1226 if ( (CapturedWindowRect.Left < 0) || (CapturedWindowRect.Top < 0) ||
1227 (CapturedWindowRect.Right >= Buffer->ScreenBufferSize.X) ||
1228 (CapturedWindowRect.Bottom >= Buffer->ScreenBufferSize.Y) ||
1229 (CapturedWindowRect.Right <= CapturedWindowRect.Left) ||
1230 (CapturedWindowRect.Bottom <= CapturedWindowRect.Top) )
1231 {
1232 return STATUS_INVALID_PARAMETER;
1233 }
1234
1235 Buffer->ViewOrigin.X = CapturedWindowRect.Left;
1236 Buffer->ViewOrigin.Y = CapturedWindowRect.Top;
1237
1238 Buffer->ViewSize.X = CapturedWindowRect.Right - CapturedWindowRect.Left + 1;
1239 Buffer->ViewSize.Y = CapturedWindowRect.Bottom - CapturedWindowRect.Top + 1;
1240
1241 // TermResizeTerminal(Console);
1242
1243 return STATUS_SUCCESS;
1244 }
1245
1246 /* EOF */