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