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