public static void Move(short fromX, short fromY, short fromWidth, short fromHeight, short toX, short toY) { IntPtr buffer = IntPtr.Zero; try { var stdHandle = GetConsoleOutputHandle(); buffer = Marshal.AllocHGlobal(fromWidth * fromHeight * Marshal.SizeOf(typeof(CHAR_INFO))); SMALL_RECT rect = new SMALL_RECT() { Left = fromX, Top = fromY, Right = (short)(fromX + fromWidth), Bottom = (short)(fromY + fromHeight) }; COORD leftTop = new COORD() { X = 0, Y = 0 }; COORD size = new COORD() { X = (short)(fromWidth), Y = fromHeight }; if (!ReadConsoleOutput(stdHandle.DangerousGetHandle(), buffer, size, leftTop, ref rect)) { // 'Not enough storage is available to process this command' may be raised for buffer size > 64K (see ReadConsoleOutput doc.) throw new Win32Exception(Marshal.GetLastWin32Error()); } rect.Left = toX; rect.Top = toY; WriteConsoleOutput(stdHandle.DangerousGetHandle(), buffer, size, leftTop, ref rect); } catch (Exception) { throw; } finally { Marshal.FreeHGlobal(buffer); } }
private static void With(short x, short y, short width, short height, Func <COORD, CHAR_INFO, CHAR_INFO> doAction, bool loadFromScreen, bool writeToBuffer = true) { if (x + width > System.Console.WindowWidth) { width = (short)((System.Console.WindowWidth - 1) - x - 1); } IntPtr buffer = IntPtr.Zero; try { var stdHandle = GetConsoleOutputHandle(); buffer = Marshal.AllocHGlobal(width * height * Marshal.SizeOf(typeof(CHAR_INFO))); SMALL_RECT rect = new SMALL_RECT() { Left = x, Top = y, Right = (short)(x + width), Bottom = (short)(y + height) }; COORD leftTop = new COORD() { X = 0, Y = 0 }; COORD size = new COORD() { X = (short)(width), Y = height }; if (loadFromScreen) { if (!Native.ReadConsoleOutput(stdHandle.DangerousGetHandle(), buffer, size, leftTop, ref rect)) { // 'Not enough storage is available to process this command' may be raised for buffer size > 64K (see ReadConsoleOutput doc.) throw new Win32Exception(Marshal.GetLastWin32Error()); } } long LongPtr = buffer.ToInt64(); // Must work both on x86 and x64 for (short h = 0; h < height; h++) { for (short w = 0; w < width; w++) { IntPtr RectPtr = new IntPtr(LongPtr); CHAR_INFO ci = (CHAR_INFO)Marshal.PtrToStructure(RectPtr, typeof(CHAR_INFO)); ci = doAction(new COORD() { X = w, Y = h }, ci); //save to safeBuffer Marshal.StructureToPtr(ci, RectPtr, true); // You do not need to erase struct in this case LongPtr += Marshal.SizeOf(typeof(CHAR_INFO)); } } if (writeToBuffer) { Native.WriteConsoleOutput(stdHandle.DangerousGetHandle(), buffer, size, leftTop, ref rect); } } catch (Exception) { throw; } finally { Marshal.FreeHGlobal(buffer); } }
public static extern bool WriteConsoleOutput(IntPtr hConsoleOutput, IntPtr lpBuffer, COORD dwBufferSize, COORD dwBufferCoord, ref SMALL_RECT lpWriteRegion);