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