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 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++; } }
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; } }