private static void WriteConsoleOutputPlain(ConsoleHandle consoleHandle, Coordinates origin, BufferCell[,] contents) { int rows = contents.GetLength(0); int cols = contents.GetLength(1); if ((rows <= 0) || cols <= 0) { tracer.WriteLine("contents passed in has 0 rows and columns"); return; } int bufferLimit = 2 * 1024; // Limit is 8K bytes as each CHAR_INFO takes 4 bytes COORD bufferCoord; bufferCoord.X = 0; bufferCoord.Y = 0; // keeps track of which screen area write SMALL_RECT writeRegion; writeRegion.Top = (short)origin.Y; int rowsRemaining = rows; while (rowsRemaining > 0) { // Iteration of columns is nested inside iteration of rows. // If the size of contents exceeds the buffer limit, writing is // done in blocks of size equal to the bufferlimit from left to right // then top to bottom. // For each iteration of rows, // - writeRegion.Left and bufferSize.X are reset // - rowsRemaining, writeRegion.Top, writeRegion.Bottom, and bufferSize.Y // are updated // For each iteration of columns, // - writeRegion.Left, writeRegion.Right and bufferSize.X are updated writeRegion.Left = (short)origin.X; COORD bufferSize; bufferSize.X = (short)Math.Min(cols, bufferLimit); bufferSize.Y = (short)Math.Min ( rowsRemaining, bufferLimit / bufferSize.X ); writeRegion.Bottom = (short)(writeRegion.Top + bufferSize.Y - 1); // atRow is at which row of contents a particular iteration is operating int atRow = rows - rowsRemaining + contents.GetLowerBound(0); // number of columns yet to be written int colsRemaining = cols; while (colsRemaining > 0) { writeRegion.Right = (short)(writeRegion.Left + bufferSize.X - 1); // atCol is at which column of contents a particular iteration is operating int atCol = cols - colsRemaining + contents.GetLowerBound(1); CHAR_INFO[] characterBuffer = new CHAR_INFO[bufferSize.Y * bufferSize.X]; // copy characterBuffer to contents; for (int r = atRow, characterBufferIndex = 0; r < bufferSize.Y + atRow; r++) { for (int c = atCol; c < bufferSize.X + atCol; c++, characterBufferIndex++) { characterBuffer[characterBufferIndex].UnicodeChar = (ushort)contents[r, c].Character; characterBuffer[characterBufferIndex].Attributes = ColorToWORD(contents[r, c].ForegroundColor, contents[r, c].BackgroundColor); } } // Now writeRegion, bufferSize and characterBuffer are updated. // Call NativeMethods.WriteConsoleOutput bool result = NativeMethods.WriteConsoleOutput( consoleHandle.DangerousGetHandle(), characterBuffer, bufferSize, bufferCoord, ref writeRegion); if (result == false) { // When WriteConsoleOutput fails, half bufferLimit if (bufferLimit < 2) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "WriteConsoleOutput", ErrorCategory.WriteError, ConsoleControlStrings.WriteConsoleOutputExceptionTemplate); throw e; } bufferLimit /= 2; if (cols == colsRemaining) { // if cols == colsRemaining, nothing is guaranteed written in this pass and // the unwritten area is still rectangular bufferSize.Y = 0; break; } else { // some areas have been written. This could only happen when the number of columns // to write is larger than bufferLimit. In that case, the algorithm writes one row // at a time => bufferSize.Y == 1. Then, we can safely leave bufferSize.Y unchanged // to retry with a smaller bufferSize.X. Dbg.Assert(bufferSize.Y == 1, string.Format(CultureInfo.InvariantCulture, "bufferSize.Y should be 1, but is {0}", bufferSize.Y)); bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); continue; } } colsRemaining -= bufferSize.X; writeRegion.Left += bufferSize.X; bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); } // column iteration rowsRemaining -= bufferSize.Y; writeRegion.Top += bufferSize.Y; } // row iteration }
private static void ReadConsoleOutputPlain ( ConsoleHandle consoleHandle, Coordinates origin, Rectangle contentsRegion, ref BufferCell[,] contents ) { int rows = contentsRegion.Bottom - contentsRegion.Top + 1; int cols = contentsRegion.Right - contentsRegion.Left + 1; if ((rows <= 0) || cols <= 0) { tracer.WriteLine("invalid contents region"); return; } int bufferLimit = 2 * 1024; // Limit is 8K bytes as each CHAR_INFO takes 4 bytes COORD bufferCoord; bufferCoord.X = 0; bufferCoord.Y = 0; // keeps track of which screen area read SMALL_RECT readRegion; readRegion.Top = (short)origin.Y; int rowsRemaining = rows; while (rowsRemaining > 0) { // Iteration of columns is nested inside iteration of rows. // If the size of contents exceeds the buffer limit, reading is // done in blocks of size equal to the bufferlimit from left to right // then top to bottom. // For each iteration of rows, // - readRegion.Left and bufferSize.X are reset // - rowsRemaining, readRegion.Top, readRegion.Bottom, and bufferSize.Y // are updated // For each iteration of columns, // - readRegion.Left, readRegion.Right and bufferSize.X are updated readRegion.Left = (short)origin.X; COORD bufferSize; bufferSize.X = (short)Math.Min(cols, bufferLimit); bufferSize.Y = (short)Math.Min ( rowsRemaining, bufferLimit / bufferSize.X ); readRegion.Bottom = (short)(readRegion.Top + bufferSize.Y - 1); // atContentsRow is at which row of contents a particular iteration is operating int atContentsRow = rows - rowsRemaining + contentsRegion.Top; // number of columns yet to be read int colsRemaining = cols; while (colsRemaining > 0) { readRegion.Right = (short)(readRegion.Left + bufferSize.X - 1); // Now readRegion and bufferSize are updated. // Call NativeMethods.ReadConsoleOutput CHAR_INFO[] characterBuffer = new CHAR_INFO[bufferSize.Y * bufferSize.X]; bool result = NativeMethods.ReadConsoleOutput( consoleHandle.DangerousGetHandle(), characterBuffer, bufferSize, bufferCoord, ref readRegion); if (result == false) { // When WriteConsoleOutput fails, half bufferLimit if (bufferLimit < 2) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "ReadConsoleOutput", ErrorCategory.ReadError, ConsoleControlStrings.ReadConsoleOutputExceptionTemplate); throw e; } // if cols == colsRemaining, nothing is guaranteed read in this pass and // the unread area is still rectangular bufferLimit /= 2; if (cols == colsRemaining) { bufferSize.Y = 0; break; } else { // some areas have been read. This could only happen when the number of columns // to write is larger than bufferLimit. In that case, the algorithm reads one row // at a time => bufferSize.Y == 1. Then, we can safely leave bufferSize.Y unchanged // to retry with a smaller bufferSize.X. Dbg.Assert(bufferSize.Y == 1, string.Format(CultureInfo.InvariantCulture, "bufferSize.Y should be 1, but is {0}", bufferSize.Y)); bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); continue; } } // atContentsCol is at which column of contents a particular iteration is operating int atContentsCol = cols - colsRemaining + contentsRegion.Left; // copy characterBuffer to contents; int characterBufferIndex = 0; for (int r = atContentsRow; r < bufferSize.Y + atContentsRow; r++) { for (int c = atContentsCol; c < bufferSize.X + atContentsCol; c++, characterBufferIndex++) { contents[r, c].Character = (char) characterBuffer[characterBufferIndex].UnicodeChar; ConsoleColor fgColor, bgColor; WORDToColor(characterBuffer[characterBufferIndex].Attributes, out fgColor, out bgColor); contents[r, c].ForegroundColor = fgColor; contents[r, c].BackgroundColor = bgColor; } } colsRemaining -= bufferSize.X; readRegion.Left += bufferSize.X; bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); } // column iteration rowsRemaining -= bufferSize.Y; readRegion.Top += bufferSize.Y; } // row iteration // The following nested loop set the value of the empty cells in contents: // character to ' ' // foreground color to console's foreground color // background color to console's background color int rowIndex = contents.GetLowerBound(0); int rowEnd = contents.GetUpperBound(0); int colBegin = contents.GetLowerBound(1); int colEnd = contents.GetUpperBound(1); CONSOLE_SCREEN_BUFFER_INFO bufferInfo = GetConsoleScreenBufferInfo(consoleHandle); ConsoleColor foreground = 0; ConsoleColor background = 0; WORDToColor( bufferInfo.Attributes, out foreground, out background ); while (rowIndex <= rowEnd) { int colIndex = colBegin; while (true) { // if contents[rowIndex,colIndex] is in contentsRegion, hence a non-empty cell, // move colIndex to one past the right end of contentsRegion if (contentsRegion.Top <= rowIndex && rowIndex <= contentsRegion.Bottom && contentsRegion.Left <= colIndex && colIndex <= contentsRegion.Right) { colIndex = contentsRegion.Right + 1; } // colIndex past contents last column if (colIndex > colEnd) { break; } contents[rowIndex, colIndex].Character = ' '; contents[rowIndex, colIndex].ForegroundColor = foreground; contents[rowIndex, colIndex].BackgroundColor = background; colIndex++; } rowIndex++; } }
/// <summary> /// Wrap32 WriteConsoleOutput. /// This wrapper is not limited to 64K or 8K CHAR_INFO to which Win32's WriteConsoleOutput /// is constrained. /// </summary> /// <param name="consoleHandle"> /// /// handle for the console where output is written /// /// </param> /// <param name="origin"> /// /// location on screen buffer where writing starts /// /// </param> /// <param name="contents"> /// /// 2D array of cells. Caller needs to ensure that the array is 2D. /// /// </param> /// <exception cref="HostException"> /// If Win32's GetConsoleScreenBufferInfo fails /// If there is not enough memory to complete calls to Win32's WriteConsoleOutput /// </exception> /// <exception cref="ArgumentNullException"> /// If <paramref name="contents"/> is null /// </exception> /// <exception cref="ArgumentException"> /// If it is illegal to write <paramref name="contents"/> to the output buffer /// </exception> internal static void WriteConsoleOutput(ConsoleHandle consoleHandle, Coordinates origin, BufferCell[,] contents) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); if (contents == null) { throw PSTraceSource.NewArgumentNullException("contents"); } uint codePage; if (IsCJKOutputCodePage(out codePage)) { // contentsRegion indicates the area in contents (declared below) in which // the data read from ReadConsoleOutput is stored. Rectangle contentsRegion = new Rectangle(); ConsoleControl.CONSOLE_SCREEN_BUFFER_INFO bufferInfo = GetConsoleScreenBufferInfo(consoleHandle); int bufferWidth = bufferInfo.BufferSize.X; int bufferHeight = bufferInfo.BufferSize.Y; Rectangle screenRegion = new Rectangle( origin.X, origin.Y, Math.Min(origin.X + contents.GetLength(1) - 1, bufferWidth - 1), Math.Min(origin.Y + contents.GetLength(0) - 1, bufferHeight - 1)); contentsRegion.Left = contents.GetLowerBound(1); contentsRegion.Top = contents.GetLowerBound(0); contentsRegion.Right = contentsRegion.Left + screenRegion.Right - screenRegion.Left; contentsRegion.Bottom = contentsRegion.Top + screenRegion.Bottom - screenRegion.Top; #if DEBUG //Check contents in contentsRegion CheckWriteConsoleOutputContents(contents, contentsRegion); #endif //Identify edges and areas of identical contiguous edges in contentsRegion List<BufferCellArrayRowTypeRange> sameEdgeAreas = new List<BufferCellArrayRowTypeRange>(); int firstLeftTrailingRow = -1, firstRightLeadingRow = -1; BuildEdgeTypeInfo(contentsRegion, contents, sameEdgeAreas, out firstLeftTrailingRow, out firstRightLeadingRow); #if DEBUG CheckWriteEdges(consoleHandle, codePage, origin, contents, contentsRegion, bufferInfo, firstLeftTrailingRow, firstRightLeadingRow); #endif foreach (BufferCellArrayRowTypeRange area in sameEdgeAreas) { Coordinates o = new Coordinates(origin.X, origin.Y + area.Start - contentsRegion.Top); Rectangle contRegion = new Rectangle( contentsRegion.Left, area.Start, contentsRegion.Right, area.End); if ((area.Type & BufferCellArrayRowType.LeftTrailing) != 0) { contRegion.Left++; o.X++; if (o.X >= bufferWidth || contRegion.Right < contRegion.Left) { return; } } WriteConsoleOutputCJK(consoleHandle, o, contRegion, contents, area.Type); } } else { WriteConsoleOutputPlain(consoleHandle, origin, contents); } }
internal static void ReadConsoleOutputCJK(SafeFileHandle consoleHandle, uint codePage, Coordinates origin, Rectangle contentsRegion, ref BufferCell[,] contents) { int bottom = contentsRegion.Bottom - contentsRegion.Top + 1; int right = contentsRegion.Right - contentsRegion.Left + 1; if (bottom <= 0 || right <= 0) { ConsoleControl.tracer.WriteLine("invalid contents region", new object[0]); return; } else { int num = 0x800; ConsoleControl.SMALL_RECT y; y.Top = (short)origin.Y; int y1 = bottom; while (y1 > 0) { y.Left = (short)origin.X; ConsoleControl.COORD cOORD; cOORD.X = (short)Math.Min(right, num); cOORD.Y = (short)Math.Min(y1, num / cOORD.X); y.Bottom = (short)(y.Top + cOORD.Y - 1); int top = bottom - y1 + contentsRegion.Top; int x = right; while (x > 0) { int left = right - x + contentsRegion.Left; y.Right = (short)(y.Left + cOORD.X - 1); Rectangle rectangle = new Rectangle(left, top, left + cOORD.X - 1, top + cOORD.Y - 1); bool flag = ConsoleControl.ReadConsoleOutputCJKSmall(consoleHandle, codePage, new Coordinates(y.Left, y.Top), rectangle, ref contents); if (flag) { x = x - cOORD.X; y.Left = (short)(y.Left + cOORD.X); if (x > 0 && cOORD.Y == 1 && contents[rectangle.Bottom, rectangle.Right].Character == ' ') { x++; y.Left = (short)(y.Left - 1); } cOORD.X = (short)Math.Min(x, num); } else { if (num >= 2) { num = num / 2; if (right != x) { cOORD.X = (short)Math.Min(x, num); } else { cOORD.Y = 0; break; } } else { int lastWin32Error = Marshal.GetLastWin32Error(); HostException hostException = ConsoleControl.CreateHostException(lastWin32Error, "ReadConsoleOutput", ErrorCategory.ReadError, ConsoleControlStrings.ReadConsoleOutputExceptionTemplate); throw hostException; } } } y1 = y1 - cOORD.Y; y.Top = (short)(y.Top + cOORD.Y); } int lowerBound = contents.GetLowerBound(0); int upperBound = contents.GetUpperBound(0); int lowerBound1 = contents.GetLowerBound(1); int upperBound1 = contents.GetUpperBound(1); ConsoleControl.CONSOLE_SCREEN_BUFFER_INFO consoleScreenBufferInfo = ConsoleControl.GetConsoleScreenBufferInfo(consoleHandle); ConsoleColor consoleColor = ConsoleColor.Black; ConsoleColor consoleColor1 = ConsoleColor.Black; ConsoleControl.WORDToColor(consoleScreenBufferInfo.Attributes, out consoleColor, out consoleColor1); while (lowerBound <= upperBound) { int right1 = lowerBound1; while (true) { if (contentsRegion.Top <= lowerBound && lowerBound <= contentsRegion.Bottom && contentsRegion.Left <= right1 && right1 <= contentsRegion.Right) { right1 = contentsRegion.Right + 1; } if (right1 > upperBound1) { break; } contents[lowerBound, right1] = new BufferCell(' ', consoleColor, consoleColor1, BufferCellType.Complete); right1++; } lowerBound++; } return; } }
private static void WriteConsoleOutputPlain(SafeFileHandle consoleHandle, Coordinates origin, BufferCell[,] contents) { int length = contents.GetLength(0); int num = contents.GetLength(1); if (length <= 0 || num <= 0) { ConsoleControl.tracer.WriteLine("contents passed in has 0 rows and columns", new object[0]); return; } else { int num1 = 0x800; ConsoleControl.COORD cOORD; cOORD.X = 0; cOORD.Y = 0; ConsoleControl.SMALL_RECT y; y.Top = (short)origin.Y; int y1 = length; while (y1 > 0) { y.Left = (short)origin.X; ConsoleControl.COORD cOORD1; cOORD1.X = (short)Math.Min(num, num1); cOORD1.Y = (short)Math.Min(y1, num1 / cOORD1.X); y.Bottom = (short)(y.Top + cOORD1.Y - 1); int lowerBound = length - y1 + contents.GetLowerBound(0); int x = num; while (x > 0) { y.Right = (short)(y.Left + cOORD1.X - 1); int lowerBound1 = num - x + contents.GetLowerBound(1); ConsoleControl.CHAR_INFO[] character = new ConsoleControl.CHAR_INFO[cOORD1.Y * cOORD1.X]; int num2 = lowerBound; int num3 = 0; while (num2 < cOORD1.Y + lowerBound) { int num4 = lowerBound1; while (num4 < cOORD1.X + lowerBound1) { character[num3].UnicodeChar = contents[num2, num4].Character; character[num3].Attributes = ConsoleControl.ColorToWORD(contents[num2, num4].ForegroundColor, contents[num2, num4].BackgroundColor); num4++; num3++; } num2++; } bool flag = ConsoleControl.NativeMethods.WriteConsoleOutput(consoleHandle.DangerousGetHandle(), character, cOORD1, cOORD, ref y); if (flag) { x = x - cOORD1.X; y.Left = (short)(y.Left + cOORD1.X); cOORD1.X = (short)Math.Min(x, num1); } else { if (num1 >= 2) { num1 = num1 / 2; if (num != x) { cOORD1.X = (short)Math.Min(x, num1); } else { cOORD1.Y = 0; break; } } else { int lastWin32Error = Marshal.GetLastWin32Error(); HostException hostException = ConsoleControl.CreateHostException(lastWin32Error, "WriteConsoleOutput", ErrorCategory.WriteError, ConsoleControlStrings.WriteConsoleOutputExceptionTemplate); throw hostException; } } } y1 = y1 - cOORD1.Y; y.Top = (short)(y.Top + cOORD1.Y); } return; } }
internal static void WriteConsoleOutput(SafeFileHandle consoleHandle, Coordinates origin, BufferCell[,] contents) { uint num = 0; if (contents != null) { if (!ConsoleControl.IsCJKOutputCodePage(out num)) { ConsoleControl.WriteConsoleOutputPlain(consoleHandle, origin, contents); } else { Rectangle lowerBound = new Rectangle(); ConsoleControl.CONSOLE_SCREEN_BUFFER_INFO consoleScreenBufferInfo = ConsoleControl.GetConsoleScreenBufferInfo(consoleHandle); int x = consoleScreenBufferInfo.BufferSize.X; int y = consoleScreenBufferInfo.BufferSize.Y; Rectangle rectangle = new Rectangle(origin.X, origin.Y, Math.Min(origin.X + contents.GetLength(1) - 1, x - 1), Math.Min(origin.Y + contents.GetLength(0) - 1, y - 1)); lowerBound.Left = contents.GetLowerBound(1); lowerBound.Top = contents.GetLowerBound(0); lowerBound.Right = lowerBound.Left + rectangle.Right - rectangle.Left; lowerBound.Bottom = lowerBound.Top + rectangle.Bottom - rectangle.Top; ConsoleControl.CheckWriteConsoleOutputContents(contents, lowerBound); List<ConsoleControl.BufferCellArrayRowTypeRange> bufferCellArrayRowTypeRanges = new List<ConsoleControl.BufferCellArrayRowTypeRange>(); int num1 = -1; int num2 = -1; ConsoleControl.BuildEdgeTypeInfo(lowerBound, contents, bufferCellArrayRowTypeRanges, out num1, out num2); ConsoleControl.CheckWriteEdges(consoleHandle, num, origin, contents, lowerBound, consoleScreenBufferInfo, num1, num2); foreach (ConsoleControl.BufferCellArrayRowTypeRange bufferCellArrayRowTypeRange in bufferCellArrayRowTypeRanges) { Coordinates coordinate = new Coordinates(origin.X, origin.Y + bufferCellArrayRowTypeRange.Start - lowerBound.Top); Rectangle left = new Rectangle(lowerBound.Left, bufferCellArrayRowTypeRange.Start, lowerBound.Right, bufferCellArrayRowTypeRange.End); if ((bufferCellArrayRowTypeRange.Type & ConsoleControl.BufferCellArrayRowType.LeftTrailing) != 0) { left.Left = left.Left + 1; coordinate.X = coordinate.X + 1; if (coordinate.X >= x || left.Right < left.Left) { return; } } ConsoleControl.WriteConsoleOutputCJK(consoleHandle, coordinate, left, contents, bufferCellArrayRowTypeRange.Type); } } return; } else { throw PSTraceSource.NewArgumentNullException("contents"); } }
private static void ReadConsoleOutputPlain(SafeFileHandle consoleHandle, Coordinates origin, Rectangle contentsRegion, ref BufferCell[,] contents) { ConsoleColor consoleColor = ConsoleColor.Black; ConsoleColor consoleColor1 = ConsoleColor.Black; int bottom = contentsRegion.Bottom - contentsRegion.Top + 1; int right = contentsRegion.Right - contentsRegion.Left + 1; if (bottom <= 0 || right <= 0) { ConsoleControl.tracer.WriteLine("invalid contents region", new object[0]); return; } else { int num = 0x800; ConsoleControl.COORD cOORD; cOORD.X = 0; cOORD.Y = 0; ConsoleControl.SMALL_RECT y; y.Top = (short)origin.Y; int y1 = bottom; while (y1 > 0) { y.Left = (short)origin.X; ConsoleControl.COORD cOORD1; cOORD1.X = (short)Math.Min(right, num); cOORD1.Y = (short)Math.Min(y1, num / cOORD1.X); y.Bottom = (short)(y.Top + cOORD1.Y - 1); int top = bottom - y1 + contentsRegion.Top; int x = right; while (x > 0) { y.Right = (short)(y.Left + cOORD1.X - 1); ConsoleControl.CHAR_INFO[] cHARINFOArray = new ConsoleControl.CHAR_INFO[cOORD1.Y * cOORD1.X]; bool flag = ConsoleControl.NativeMethods.ReadConsoleOutput(consoleHandle.DangerousGetHandle(), cHARINFOArray, cOORD1, cOORD, ref y); if (flag) { int left = right - x + contentsRegion.Left; int num1 = 0; for (int i = top; i < cOORD1.Y + top; i++) { int num2 = left; while (num2 < cOORD1.X + left) { contents[i, num2].Character = Convert.ToChar(cHARINFOArray[num1].UnicodeChar); ConsoleControl.WORDToColor(cHARINFOArray[num1].Attributes, out consoleColor, out consoleColor1); contents[i, num2].ForegroundColor = consoleColor; contents[i, num2].BackgroundColor = consoleColor1; num2++; num1++; } } x = x - cOORD1.X; y.Left = (short)(y.Left + cOORD1.X); cOORD1.X = (short)Math.Min(x, num); } else { if (num >= 2) { num = num / 2; if (right != x) { cOORD1.X = (short)Math.Min(x, num); } else { cOORD1.Y = 0; break; } } else { int lastWin32Error = Marshal.GetLastWin32Error(); HostException hostException = ConsoleControl.CreateHostException(lastWin32Error, "ReadConsoleOutput", ErrorCategory.ReadError, ConsoleControlStrings.ReadConsoleOutputExceptionTemplate); throw hostException; } } } y1 = y1 - cOORD1.Y; y.Top = (short)(y.Top + cOORD1.Y); } int lowerBound = contents.GetLowerBound(0); int upperBound = contents.GetUpperBound(0); int lowerBound1 = contents.GetLowerBound(1); int upperBound1 = contents.GetUpperBound(1); ConsoleControl.CONSOLE_SCREEN_BUFFER_INFO consoleScreenBufferInfo = ConsoleControl.GetConsoleScreenBufferInfo(consoleHandle); ConsoleColor consoleColor2 = ConsoleColor.Black; ConsoleColor consoleColor3 = ConsoleColor.Black; ConsoleControl.WORDToColor(consoleScreenBufferInfo.Attributes, out consoleColor2, out consoleColor3); while (lowerBound <= upperBound) { int right1 = lowerBound1; while (true) { if (contentsRegion.Top <= lowerBound && lowerBound <= contentsRegion.Bottom && contentsRegion.Left <= right1 && right1 <= contentsRegion.Right) { right1 = contentsRegion.Right + 1; } if (right1 > upperBound1) { break; } contents[lowerBound, right1].Character = ' '; contents[lowerBound, right1].ForegroundColor = consoleColor2; contents[lowerBound, right1].BackgroundColor = consoleColor3; right1++; } lowerBound++; } return; } }