[CONDRV]
[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 NTSTATUS
237 ConioResizeBuffer(PCONSOLE Console,
238 PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
239 COORD Size)
240 {
241 PCHAR_INFO Buffer;
242 DWORD Offset = 0;
243 PCHAR_INFO ptr;
244 WORD CurrentAttribute;
245 USHORT CurrentY;
246 PCHAR_INFO OldBuffer;
247 DWORD i;
248 DWORD diff;
249
250 /* Buffer size is not allowed to be smaller than the view size */
251 if (Size.X < ScreenBuffer->ViewSize.X || Size.Y < ScreenBuffer->ViewSize.Y)
252 return STATUS_INVALID_PARAMETER;
253
254 if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y)
255 {
256 // FIXME: Trigger a buffer resize event ??
257 return STATUS_SUCCESS;
258 }
259
260 if (Console->FixedSize)
261 {
262 /*
263 * The console is in fixed-size mode, so we cannot resize anything
264 * at the moment. However, keep those settings somewhere so that
265 * we can try to set them up when we will be allowed to do so.
266 */
267 ScreenBuffer->OldScreenBufferSize = Size;
268 return STATUS_NOT_SUPPORTED; // STATUS_SUCCESS
269 }
270
271 Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size.X * Size.Y * sizeof(CHAR_INFO));
272 if (!Buffer) return STATUS_NO_MEMORY;
273
274 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y);
275 OldBuffer = ScreenBuffer->Buffer;
276
277 for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++)
278 {
279 ptr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
280 if (Size.X <= ScreenBuffer->ScreenBufferSize.X)
281 {
282 /* Reduce size */
283 RtlCopyMemory(Buffer + Offset, ptr, Size.X * sizeof(CHAR_INFO));
284 Offset += Size.X;
285 }
286 else
287 {
288 /* Enlarge size */
289 RtlCopyMemory(Buffer + Offset, ptr, ScreenBuffer->ScreenBufferSize.X * sizeof(CHAR_INFO));
290 Offset += ScreenBuffer->ScreenBufferSize.X;
291
292 /* The attribute to be used is the one of the last cell of the current line */
293 CurrentAttribute = ConioCoordToPointer(ScreenBuffer,
294 ScreenBuffer->ScreenBufferSize.X - 1,
295 CurrentY)->Attributes;
296
297 diff = Size.X - ScreenBuffer->ScreenBufferSize.X;
298
299 /* Zero-out the new part of the buffer */
300 for (i = 0; i < diff; i++)
301 {
302 ptr = Buffer + Offset;
303 ptr->Char.UnicodeChar = L' ';
304 ptr->Attributes = CurrentAttribute;
305 ++Offset;
306 }
307 }
308 }
309
310 if (Size.Y > ScreenBuffer->ScreenBufferSize.Y)
311 {
312 diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y);
313
314 /* Zero-out the new part of the buffer */
315 for (i = 0; i < diff; i++)
316 {
317 ptr = Buffer + Offset;
318 ptr->Char.UnicodeChar = L' ';
319 ptr->Attributes = ScreenBuffer->ScreenDefaultAttrib;
320 ++Offset;
321 }
322 }
323
324 (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer);
325 ConsoleFreeHeap(OldBuffer);
326 ScreenBuffer->ScreenBufferSize = ScreenBuffer->OldScreenBufferSize = Size;
327 ScreenBuffer->VirtualY = 0;
328
329 /* Ensure cursor and window are within buffer */
330 if (ScreenBuffer->CursorPosition.X >= Size.X)
331 ScreenBuffer->CursorPosition.X = Size.X - 1;
332 if (ScreenBuffer->CursorPosition.Y >= Size.Y)
333 ScreenBuffer->CursorPosition.Y = Size.Y - 1;
334 if (ScreenBuffer->ViewOrigin.X > Size.X - ScreenBuffer->ViewSize.X)
335 ScreenBuffer->ViewOrigin.X = Size.X - ScreenBuffer->ViewSize.X;
336 if (ScreenBuffer->ViewOrigin.Y > Size.Y - ScreenBuffer->ViewSize.Y)
337 ScreenBuffer->ViewOrigin.Y = Size.Y - ScreenBuffer->ViewSize.Y;
338
339 /*
340 * Trigger a buffer resize event
341 */
342 if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT)
343 {
344 INPUT_RECORD er;
345
346 er.EventType = WINDOW_BUFFER_SIZE_EVENT;
347 er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize;
348
349 ConioProcessInputEvent(Console, &er);
350 }
351
352 return STATUS_SUCCESS;
353 }
354
355 NTSTATUS NTAPI
356 ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console,
357 IN PTEXTMODE_SCREEN_BUFFER Buffer,
358 IN USHORT NewScreenAttrib,
359 IN USHORT NewPopupAttrib)
360 {
361 DWORD X, Y, Length;
362 PCHAR_INFO Ptr;
363
364 COORD TopLeft = {0};
365 ULONG NumCodesToWrite;
366 USHORT OldScreenAttrib, OldPopupAttrib;
367
368 if (Console == NULL || Buffer == NULL)
369 {
370 return STATUS_INVALID_PARAMETER;
371 }
372
373 /* Validity check */
374 ASSERT(Console == Buffer->Header.Console);
375
376 NumCodesToWrite = Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y;
377 OldScreenAttrib = Buffer->ScreenDefaultAttrib;
378 OldPopupAttrib = Buffer->PopupDefaultAttrib;
379
380 X = TopLeft.X;
381 Y = (TopLeft.Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
382 Length = NumCodesToWrite;
383
384 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
385 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
386
387 while (Length--)
388 {
389 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
390 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
391
392 /*
393 * Change the current colors only if they are the old ones.
394 */
395
396 /* Foreground color */
397 if ((Ptr->Attributes & 0x0F) == (OldScreenAttrib & 0x0F))
398 Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewScreenAttrib & 0x0F);
399 if ((Ptr->Attributes & 0x0F) == (OldPopupAttrib & 0x0F))
400 Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewPopupAttrib & 0x0F);
401
402 /* Background color */
403 if ((Ptr->Attributes & 0xF0) == (OldScreenAttrib & 0xF0))
404 Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewScreenAttrib & 0xF0);
405 if ((Ptr->Attributes & 0xF0) == (OldPopupAttrib & 0xF0))
406 Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewPopupAttrib & 0xF0);
407
408 // ++Ptr;
409
410 if (++X == Buffer->ScreenBufferSize.X)
411 {
412 X = 0;
413
414 if (++Y == Buffer->ScreenBufferSize.Y)
415 {
416 Y = 0;
417 }
418 }
419 }
420
421 /* Save foreground and background colors for both screen and popup */
422 Buffer->ScreenDefaultAttrib = (NewScreenAttrib & 0x00FF);
423 Buffer->PopupDefaultAttrib = (NewPopupAttrib & 0x00FF);
424
425 /* Refresh the display if needed */
426 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
427 {
428 SMALL_RECT UpdateRect;
429 ConioComputeUpdateRect(Buffer, &UpdateRect, &TopLeft, NumCodesToWrite);
430 TermDrawRegion(Console, &UpdateRect);
431 }
432
433 return STATUS_SUCCESS;
434 }
435
436
437 /* PUBLIC DRIVER APIS *********************************************************/
438
439 NTSTATUS NTAPI
440 ConDrvReadConsoleOutput(IN PCONSOLE Console,
441 IN PTEXTMODE_SCREEN_BUFFER Buffer,
442 IN BOOLEAN Unicode,
443 OUT PCHAR_INFO CharInfo/*Buffer*/,
444 IN OUT PSMALL_RECT ReadRegion)
445 {
446 SHORT X, Y;
447 SMALL_RECT ScreenBuffer;
448 PCHAR_INFO CurCharInfo;
449 SMALL_RECT CapturedReadRegion;
450 PCHAR_INFO Ptr;
451
452 if (Console == NULL || Buffer == NULL || CharInfo == NULL || ReadRegion == NULL)
453 {
454 return STATUS_INVALID_PARAMETER;
455 }
456
457 /* Validity check */
458 ASSERT(Console == Buffer->Header.Console);
459
460 CapturedReadRegion = *ReadRegion;
461
462 /* Make sure ReadRegion is inside the screen buffer */
463 ConioInitRect(&ScreenBuffer, 0, 0,
464 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
465 if (!ConioGetIntersection(&CapturedReadRegion, &ScreenBuffer, &CapturedReadRegion))
466 {
467 /*
468 * It is okay to have a ReadRegion completely outside
469 * the screen buffer. No data is read then.
470 */
471 return STATUS_SUCCESS;
472 }
473
474 CurCharInfo = CharInfo;
475
476 for (Y = CapturedReadRegion.Top; Y <= CapturedReadRegion.Bottom; ++Y)
477 {
478 Ptr = ConioCoordToPointer(Buffer, CapturedReadRegion.Left, Y);
479 for (X = CapturedReadRegion.Left; X <= CapturedReadRegion.Right; ++X)
480 {
481 if (Unicode)
482 {
483 CurCharInfo->Char.UnicodeChar = Ptr->Char.UnicodeChar;
484 }
485 else
486 {
487 // ConsoleUnicodeCharToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
488 WideCharToMultiByte(Console->OutputCodePage, 0, &Ptr->Char.UnicodeChar, 1,
489 &CurCharInfo->Char.AsciiChar, 1, NULL, NULL);
490 }
491 CurCharInfo->Attributes = Ptr->Attributes;
492 ++Ptr;
493 ++CurCharInfo;
494 }
495 }
496
497 *ReadRegion = CapturedReadRegion;
498
499 return STATUS_SUCCESS;
500 }
501
502 NTSTATUS NTAPI
503 ConDrvWriteConsoleOutput(IN PCONSOLE Console,
504 IN PTEXTMODE_SCREEN_BUFFER Buffer,
505 IN BOOLEAN Unicode,
506 IN PCHAR_INFO CharInfo/*Buffer*/,
507 IN OUT PSMALL_RECT WriteRegion)
508 {
509 SHORT X, Y;
510 SMALL_RECT ScreenBuffer;
511 PCHAR_INFO CurCharInfo;
512 SMALL_RECT CapturedWriteRegion;
513 PCHAR_INFO Ptr;
514
515 if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL)
516 {
517 return STATUS_INVALID_PARAMETER;
518 }
519
520 /* Validity check */
521 ASSERT(Console == Buffer->Header.Console);
522
523 CapturedWriteRegion = *WriteRegion;
524
525 /* Make sure WriteRegion is inside the screen buffer */
526 ConioInitRect(&ScreenBuffer, 0, 0,
527 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
528 if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
529 {
530 /*
531 * It is okay to have a WriteRegion completely outside
532 * the screen buffer. No data is written then.
533 */
534 return STATUS_SUCCESS;
535 }
536
537 CurCharInfo = CharInfo;
538
539 for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y)
540 {
541 Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
542 for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X)
543 {
544 if (Unicode)
545 {
546 Ptr->Char.UnicodeChar = CurCharInfo->Char.UnicodeChar;
547 }
548 else
549 {
550 ConsoleAnsiCharToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char.AsciiChar);
551 }
552 Ptr->Attributes = CurCharInfo->Attributes;
553 ++Ptr;
554 ++CurCharInfo;
555 }
556 }
557
558 TermDrawRegion(Console, &CapturedWriteRegion);
559
560 *WriteRegion = CapturedWriteRegion;
561
562 return STATUS_SUCCESS;
563 }
564
565 /*
566 * NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput...
567 */
568 NTSTATUS NTAPI
569 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console,
570 IN PTEXTMODE_SCREEN_BUFFER Buffer,
571 IN PCHAR_CELL CharInfo/*Buffer*/,
572 IN COORD CharInfoSize,
573 IN OUT PSMALL_RECT WriteRegion,
574 IN BOOLEAN DrawRegion)
575 {
576 SHORT X, Y;
577 SMALL_RECT ScreenBuffer;
578 PCHAR_CELL CurCharInfo;
579 SMALL_RECT CapturedWriteRegion;
580 PCHAR_INFO Ptr;
581
582 if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL)
583 {
584 return STATUS_INVALID_PARAMETER;
585 }
586
587 /* Validity check */
588 ASSERT(Console == Buffer->Header.Console);
589
590 CapturedWriteRegion = *WriteRegion;
591
592 /* Make sure WriteRegion is inside the screen buffer */
593 ConioInitRect(&ScreenBuffer, 0, 0,
594 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
595 if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
596 {
597 /*
598 * It is okay to have a WriteRegion completely outside
599 * the screen buffer. No data is written then.
600 */
601 return STATUS_SUCCESS;
602 }
603
604 // CurCharInfo = CharInfo;
605
606 for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y)
607 {
608 /**/CurCharInfo = CharInfo + Y * CharInfoSize.X + CapturedWriteRegion.Left;/**/
609
610 Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
611 for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X)
612 {
613 ConsoleAnsiCharToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char);
614 Ptr->Attributes = CurCharInfo->Attributes;
615 ++Ptr;
616 ++CurCharInfo;
617 }
618 }
619
620 if (DrawRegion) TermDrawRegion(Console, &CapturedWriteRegion);
621
622 *WriteRegion = CapturedWriteRegion;
623
624 return STATUS_SUCCESS;
625 }
626
627 NTSTATUS NTAPI
628 ConDrvWriteConsole(IN PCONSOLE Console,
629 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
630 IN BOOLEAN Unicode,
631 IN PVOID StringBuffer,
632 IN ULONG NumCharsToWrite,
633 OUT PULONG NumCharsWritten OPTIONAL)
634 {
635 NTSTATUS Status = STATUS_SUCCESS;
636 PWCHAR Buffer = NULL;
637 ULONG Written = 0;
638 ULONG Length;
639
640 if (Console == NULL || ScreenBuffer == NULL /* || StringBuffer == NULL */)
641 return STATUS_INVALID_PARAMETER;
642
643 /* Validity checks */
644 ASSERT(Console == ScreenBuffer->Header.Console);
645 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCharsToWrite == 0));
646
647 /* Stop here if the console is paused */
648 if (Console->UnpauseEvent != NULL) return STATUS_PENDING;
649
650 /* Convert the string to UNICODE */
651 if (Unicode)
652 {
653 Buffer = StringBuffer;
654 }
655 else
656 {
657 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
658 (PCHAR)StringBuffer,
659 NumCharsToWrite,
660 NULL, 0);
661 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
662 if (Buffer)
663 {
664 MultiByteToWideChar(Console->OutputCodePage, 0,
665 (PCHAR)StringBuffer,
666 NumCharsToWrite,
667 (PWCHAR)Buffer, Length);
668 }
669 else
670 {
671 Status = STATUS_NO_MEMORY;
672 }
673 }
674
675 /* Send it */
676 if (Buffer)
677 {
678 if (NT_SUCCESS(Status))
679 {
680 Status = TermWriteStream(Console,
681 ScreenBuffer,
682 Buffer,
683 NumCharsToWrite,
684 TRUE);
685 if (NT_SUCCESS(Status))
686 {
687 Written = NumCharsToWrite;
688 }
689 }
690
691 if (!Unicode) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
692 }
693
694 if (NumCharsWritten) *NumCharsWritten = Written;
695
696 return Status;
697 }
698
699 NTSTATUS NTAPI
700 ConDrvReadConsoleOutputString(IN PCONSOLE Console,
701 IN PTEXTMODE_SCREEN_BUFFER Buffer,
702 IN CODE_TYPE CodeType,
703 OUT PVOID StringBuffer,
704 IN ULONG NumCodesToRead,
705 IN PCOORD ReadCoord,
706 // OUT PCOORD EndCoord,
707 OUT PULONG NumCodesRead OPTIONAL)
708 {
709 SHORT Xpos, Ypos;
710 PVOID ReadBuffer;
711 ULONG i;
712 ULONG CodeSize;
713 PCHAR_INFO Ptr;
714
715 if (Console == NULL || Buffer == NULL || ReadCoord == NULL /* || EndCoord == NULL */)
716 {
717 return STATUS_INVALID_PARAMETER;
718 }
719
720 /* Validity checks */
721 ASSERT(Console == Buffer->Header.Console);
722 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToRead == 0));
723
724 //
725 // FIXME: Make overflow checks on ReadCoord !!!!!!
726 //
727
728 if (NumCodesRead) *NumCodesRead = 0;
729
730 switch (CodeType)
731 {
732 case CODE_ASCII:
733 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
734 break;
735
736 case CODE_UNICODE:
737 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
738 break;
739
740 case CODE_ATTRIBUTE:
741 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
742 break;
743
744 default:
745 return STATUS_INVALID_PARAMETER;
746 }
747
748 ReadBuffer = StringBuffer;
749 Xpos = ReadCoord->X;
750 Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
751
752 /*
753 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
754 *
755 * If the number of attributes (resp. characters) to be read from extends
756 * beyond the end of the specified screen buffer row, attributes (resp.
757 * characters) are read from the next row. If the number of attributes
758 * (resp. characters) to be read from extends beyond the end of the console
759 * screen buffer, attributes (resp. characters) up to the end of the console
760 * screen buffer are read.
761 *
762 * TODO: Do NOT loop up to NumCodesToRead, but stop before
763 * if we are going to overflow...
764 */
765 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work
766 for (i = 0; i < min(NumCodesToRead, Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y); ++i)
767 {
768 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either
769 Ptr = &Buffer->Buffer[Xpos + Ypos * Buffer->ScreenBufferSize.X];
770
771 switch (CodeType)
772 {
773 case CODE_ASCII:
774 ConsoleUnicodeCharToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
775 break;
776
777 case CODE_UNICODE:
778 *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
779 break;
780
781 case CODE_ATTRIBUTE:
782 *(PWORD)ReadBuffer = Ptr->Attributes;
783 break;
784 }
785 ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
786 // ++Ptr;
787
788 Xpos++;
789
790 if (Xpos == Buffer->ScreenBufferSize.X)
791 {
792 Xpos = 0;
793 Ypos++;
794
795 if (Ypos == Buffer->ScreenBufferSize.Y)
796 {
797 Ypos = 0;
798 }
799 }
800 }
801
802 // EndCoord->X = Xpos;
803 // EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y;
804
805 if (NumCodesRead)
806 *NumCodesRead = (ULONG)((ULONG_PTR)ReadBuffer - (ULONG_PTR)StringBuffer) / CodeSize;
807 // <= NumCodesToRead
808
809 return STATUS_SUCCESS;
810 }
811
812 NTSTATUS NTAPI
813 ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
814 IN PTEXTMODE_SCREEN_BUFFER Buffer,
815 IN CODE_TYPE CodeType,
816 IN PVOID StringBuffer,
817 IN ULONG NumCodesToWrite,
818 IN PCOORD WriteCoord,
819 // OUT PCOORD EndCoord,
820 OUT PULONG NumCodesWritten OPTIONAL)
821 {
822 NTSTATUS Status = STATUS_SUCCESS;
823 PVOID WriteBuffer = NULL;
824 PWCHAR tmpString = NULL;
825 DWORD X, Y, Length; // , Written = 0;
826 ULONG CodeSize;
827 PCHAR_INFO Ptr;
828
829 if (Console == NULL || Buffer == NULL || WriteCoord == NULL /* || EndCoord == NULL */)
830 {
831 return STATUS_INVALID_PARAMETER;
832 }
833
834 /* Validity checks */
835 ASSERT(Console == Buffer->Header.Console);
836 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToWrite == 0));
837
838 //
839 // FIXME: Make overflow checks on WriteCoord !!!!!!
840 //
841
842 if (NumCodesWritten) *NumCodesWritten = 0;
843
844 switch (CodeType)
845 {
846 case CODE_ASCII:
847 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
848 break;
849
850 case CODE_UNICODE:
851 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
852 break;
853
854 case CODE_ATTRIBUTE:
855 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
856 break;
857
858 default:
859 return STATUS_INVALID_PARAMETER;
860 }
861
862 if (CodeType == CODE_ASCII)
863 {
864 /* Convert the ASCII string into Unicode before writing it to the console */
865 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
866 (PCHAR)StringBuffer,
867 NumCodesToWrite,
868 NULL, 0);
869 tmpString = WriteBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
870 if (WriteBuffer)
871 {
872 MultiByteToWideChar(Console->OutputCodePage, 0,
873 (PCHAR)StringBuffer,
874 NumCodesToWrite,
875 (PWCHAR)WriteBuffer, Length);
876 }
877 else
878 {
879 Status = STATUS_NO_MEMORY;
880 }
881
882 // FIXME: Quick fix: fix the CodeType and CodeSize since the
883 // ASCII string was converted into UNICODE.
884 // A proper fix needs to be written.
885 CodeType = CODE_UNICODE;
886 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
887 }
888 else
889 {
890 /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
891 WriteBuffer = StringBuffer;
892 }
893
894 if (WriteBuffer == NULL || !NT_SUCCESS(Status)) goto Cleanup;
895
896 X = WriteCoord->X;
897 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
898 Length = NumCodesToWrite;
899 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
900 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
901
902 while (Length--)
903 {
904 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
905 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
906
907 switch (CodeType)
908 {
909 case CODE_ASCII:
910 case CODE_UNICODE:
911 Ptr->Char.UnicodeChar = *(PWCHAR)WriteBuffer;
912 break;
913
914 case CODE_ATTRIBUTE:
915 Ptr->Attributes = *(PWORD)WriteBuffer;
916 break;
917 }
918 WriteBuffer = (PVOID)((ULONG_PTR)WriteBuffer + CodeSize);
919 // ++Ptr;
920
921 // Written++;
922 if (++X == Buffer->ScreenBufferSize.X)
923 {
924 X = 0;
925
926 if (++Y == Buffer->ScreenBufferSize.Y)
927 {
928 Y = 0;
929 }
930 }
931 }
932
933 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
934 {
935 SMALL_RECT UpdateRect;
936 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
937 TermDrawRegion(Console, &UpdateRect);
938 }
939
940 // EndCoord->X = X;
941 // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
942
943 Cleanup:
944 if (tmpString) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString);
945
946 if (NumCodesWritten) *NumCodesWritten = NumCodesToWrite; // Written;
947 return Status;
948 }
949
950 NTSTATUS NTAPI
951 ConDrvFillConsoleOutput(IN PCONSOLE Console,
952 IN PTEXTMODE_SCREEN_BUFFER Buffer,
953 IN CODE_TYPE CodeType,
954 IN CODE_ELEMENT Code,
955 IN ULONG NumCodesToWrite,
956 IN PCOORD WriteCoord,
957 OUT PULONG NumCodesWritten OPTIONAL)
958 {
959 DWORD X, Y, Length; // , Written = 0;
960 PCHAR_INFO Ptr;
961
962 if (Console == NULL || Buffer == NULL || WriteCoord == NULL)
963 {
964 return STATUS_INVALID_PARAMETER;
965 }
966
967 /* Validity check */
968 ASSERT(Console == Buffer->Header.Console);
969
970 //
971 // FIXME: Make overflow checks on WriteCoord !!!!!!
972 //
973
974 if (NumCodesWritten) *NumCodesWritten = 0;
975
976 if (CodeType == CODE_ASCII)
977 {
978 /* Conversion from the ASCII char to the UNICODE char */
979 CODE_ELEMENT tmp;
980 ConsoleAnsiCharToUnicodeChar(Console, &tmp.UnicodeChar, &Code.AsciiChar);
981 Code = tmp;
982 }
983
984 X = WriteCoord->X;
985 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
986 Length = NumCodesToWrite;
987 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
988 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
989
990 while (Length--)
991 {
992 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
993 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
994
995 switch (CodeType)
996 {
997 case CODE_ASCII:
998 case CODE_UNICODE:
999 Ptr->Char.UnicodeChar = Code.UnicodeChar;
1000 break;
1001
1002 case CODE_ATTRIBUTE:
1003 Ptr->Attributes = Code.Attribute;
1004 break;
1005 }
1006 // ++Ptr;
1007
1008 // Written++;
1009 if (++X == Buffer->ScreenBufferSize.X)
1010 {
1011 X = 0;
1012
1013 if (++Y == Buffer->ScreenBufferSize.Y)
1014 {
1015 Y = 0;
1016 }
1017 }
1018 }
1019
1020 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1021 {
1022 SMALL_RECT UpdateRect;
1023 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
1024 TermDrawRegion(Console, &UpdateRect);
1025 }
1026
1027 if (NumCodesWritten) *NumCodesWritten = NumCodesToWrite; // Written;
1028 return STATUS_SUCCESS;
1029 }
1030
1031 NTSTATUS NTAPI
1032 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console,
1033 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1034 OUT PCOORD ScreenBufferSize,
1035 OUT PCOORD CursorPosition,
1036 OUT PCOORD ViewOrigin,
1037 OUT PCOORD ViewSize,
1038 OUT PCOORD MaximumViewSize,
1039 OUT PWORD Attributes)
1040 {
1041 if (Console == NULL || Buffer == NULL || ScreenBufferSize == NULL ||
1042 CursorPosition == NULL || ViewOrigin == NULL || ViewSize == NULL ||
1043 MaximumViewSize == NULL || Attributes == NULL)
1044 {
1045 return STATUS_INVALID_PARAMETER;
1046 }
1047
1048 /* Validity check */
1049 ASSERT(Console == Buffer->Header.Console);
1050
1051 *ScreenBufferSize = Buffer->ScreenBufferSize;
1052 *CursorPosition = Buffer->CursorPosition;
1053 *ViewOrigin = Buffer->ViewOrigin;
1054 *ViewSize = Buffer->ViewSize;
1055 *Attributes = Buffer->ScreenDefaultAttrib;
1056
1057 // FIXME: Refine the computation
1058 *MaximumViewSize = Buffer->ScreenBufferSize;
1059
1060 return STATUS_SUCCESS;
1061 }
1062
1063 NTSTATUS NTAPI
1064 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
1065 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1066 IN WORD Attributes)
1067 {
1068 if (Console == NULL || Buffer == NULL)
1069 return STATUS_INVALID_PARAMETER;
1070
1071 /* Validity check */
1072 ASSERT(Console == Buffer->Header.Console);
1073
1074 Buffer->ScreenDefaultAttrib = Attributes;
1075 return STATUS_SUCCESS;
1076 }
1077
1078 NTSTATUS NTAPI
1079 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
1080 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1081 IN PCOORD Size)
1082 {
1083 NTSTATUS Status;
1084
1085 if (Console == NULL || Buffer == NULL || Size == NULL)
1086 return STATUS_INVALID_PARAMETER;
1087
1088 /* Validity check */
1089 ASSERT(Console == Buffer->Header.Console);
1090
1091 Status = ConioResizeBuffer(Console, Buffer, *Size);
1092 if (NT_SUCCESS(Status)) TermResizeTerminal(Console);
1093
1094 return Status;
1095 }
1096
1097 NTSTATUS NTAPI
1098 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
1099 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1100 IN BOOLEAN Unicode,
1101 IN PSMALL_RECT ScrollRectangle,
1102 IN BOOLEAN UseClipRectangle,
1103 IN PSMALL_RECT ClipRectangle OPTIONAL,
1104 IN PCOORD DestinationOrigin,
1105 IN CHAR_INFO FillChar)
1106 {
1107 COORD CapturedDestinationOrigin;
1108 SMALL_RECT ScreenBuffer;
1109 SMALL_RECT SrcRegion;
1110 SMALL_RECT DstRegion;
1111 SMALL_RECT UpdateRegion;
1112 SMALL_RECT CapturedClipRectangle;
1113
1114 if (Console == NULL || Buffer == NULL || ScrollRectangle == NULL ||
1115 (UseClipRectangle ? ClipRectangle == NULL : FALSE) || DestinationOrigin == NULL)
1116 {
1117 return STATUS_INVALID_PARAMETER;
1118 }
1119
1120 /* Validity check */
1121 ASSERT(Console == Buffer->Header.Console);
1122
1123 CapturedDestinationOrigin = *DestinationOrigin;
1124
1125 /* Make sure the source rectangle is inside the screen buffer */
1126 ConioInitRect(&ScreenBuffer, 0, 0,
1127 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
1128 if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, ScrollRectangle))
1129 {
1130 return STATUS_SUCCESS;
1131 }
1132
1133 /* If the source was clipped on the left or top, adjust the destination accordingly */
1134 if (ScrollRectangle->Left < 0)
1135 {
1136 CapturedDestinationOrigin.X -= ScrollRectangle->Left;
1137 }
1138 if (ScrollRectangle->Top < 0)
1139 {
1140 CapturedDestinationOrigin.Y -= ScrollRectangle->Top;
1141 }
1142
1143 if (UseClipRectangle)
1144 {
1145 CapturedClipRectangle = *ClipRectangle;
1146 if (!ConioGetIntersection(&CapturedClipRectangle, &CapturedClipRectangle, &ScreenBuffer))
1147 {
1148 return STATUS_SUCCESS;
1149 }
1150 }
1151 else
1152 {
1153 CapturedClipRectangle = ScreenBuffer;
1154 }
1155
1156 ConioInitRect(&DstRegion,
1157 CapturedDestinationOrigin.Y,
1158 CapturedDestinationOrigin.X,
1159 CapturedDestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
1160 CapturedDestinationOrigin.X + ConioRectWidth(&SrcRegion ) - 1);
1161
1162 if (!Unicode)
1163 {
1164 WCHAR tmp;
1165 ConsoleAnsiCharToUnicodeChar(Console, &tmp, &FillChar.Char.AsciiChar);
1166 FillChar.Char.UnicodeChar = tmp;
1167 }
1168
1169 ConioMoveRegion(Buffer, &SrcRegion, &DstRegion, &CapturedClipRectangle, FillChar);
1170
1171 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1172 {
1173 ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
1174 if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &CapturedClipRectangle))
1175 {
1176 /* Draw update region */
1177 TermDrawRegion(Console, &UpdateRegion);
1178 }
1179 }
1180
1181 return STATUS_SUCCESS;
1182 }
1183
1184 NTSTATUS NTAPI
1185 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console,
1186 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1187 IN BOOLEAN Absolute,
1188 IN PSMALL_RECT WindowRect)
1189 {
1190 SMALL_RECT CapturedWindowRect;
1191
1192 if (Console == NULL || Buffer == NULL || WindowRect == NULL)
1193 return STATUS_INVALID_PARAMETER;
1194
1195 /* Validity check */
1196 ASSERT(Console == Buffer->Header.Console);
1197
1198 CapturedWindowRect = *WindowRect;
1199
1200 if (Absolute == FALSE)
1201 {
1202 /* Relative positions given. Transform them to absolute ones */
1203 CapturedWindowRect.Left += Buffer->ViewOrigin.X;
1204 CapturedWindowRect.Top += Buffer->ViewOrigin.Y;
1205 CapturedWindowRect.Right += Buffer->ViewOrigin.X + Buffer->ViewSize.X - 1;
1206 CapturedWindowRect.Bottom += Buffer->ViewOrigin.Y + Buffer->ViewSize.Y - 1;
1207 }
1208
1209 /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */
1210 if ( (CapturedWindowRect.Left < 0) || (CapturedWindowRect.Top < 0) ||
1211 (CapturedWindowRect.Right >= Buffer->ScreenBufferSize.X) ||
1212 (CapturedWindowRect.Bottom >= Buffer->ScreenBufferSize.Y) ||
1213 (CapturedWindowRect.Right <= CapturedWindowRect.Left) ||
1214 (CapturedWindowRect.Bottom <= CapturedWindowRect.Top) )
1215 {
1216 return STATUS_INVALID_PARAMETER;
1217 }
1218
1219 Buffer->ViewOrigin.X = CapturedWindowRect.Left;
1220 Buffer->ViewOrigin.Y = CapturedWindowRect.Top;
1221
1222 Buffer->ViewSize.X = CapturedWindowRect.Right - CapturedWindowRect.Left + 1;
1223 Buffer->ViewSize.Y = CapturedWindowRect.Bottom - CapturedWindowRect.Top + 1;
1224
1225 // TermResizeTerminal(Console);
1226
1227 return STATUS_SUCCESS;
1228 }
1229
1230 /* EOF */