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