在 Windows 10 中工作的简化演示,用于从屏幕上指定的 (X, Y) 位置读取单个字符。使用 .NET 4.7.2 测试。
首先,这是用演示网格填充控制台的代码行。请注意,它应该呈现在屏幕的左上角,以便演示工作。
static void Populate_Console()
{
Console.Clear();
Console.Write(@"
┌───────┐
1│C D E F│
2│G H I J│
3│K L M N│
4│O P Q R│
└───────┘
2 4 6 8 ".Trim());
}
应该是这样的:
现在让我们读回一些字符。首先,您需要 stdout 的本机控制台句柄。下面是从 Win32 获取它的 P/Invoke 方法:
[DllImport("kernel32", SetLastError = true)]
static extern IntPtr GetStdHandle(int num);
现在是最酷的部分;到目前为止,这似乎是此页面上唯一使用ReadConsoleOutputCharacter Win32 函数的答案。虽然它不能让您获得字符颜色属性,但这种方法确实省去了处理复制矩形和必须使用CreateConsoleScreenBuffer 分配屏幕缓冲区并在它们之间复制的所有麻烦。
有单独的 Ansi 和 Unicode 版本,您需要根据控制台窗口中的活动代码页调用正确的版本。我在这里展示了两个 P/Invoke 签名,但为了简单起见,在示例中我将继续使用 Ansi 版本:
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.Bool)] // ̲┌──────────────────^
static extern bool ReadConsoleOutputCharacterA(
IntPtr hStdout, // result of 'GetStdHandle(-11)'
out byte ch, // A̲N̲S̲I̲ character result
uint c_in, // (set to '1')
uint coord_XY, // screen location to read, X:loword, Y:hiword
out uint c_out); // (unwanted, discard)
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)] // ̲┌───────────────────^
static extern bool ReadConsoleOutputCharacterW(
IntPtr hStdout, // result of 'GetStdHandle(-11)'
out Char ch, // U̲n̲i̲c̲o̲d̲e̲ character result
uint c_in, // (set to '1')
uint coord_XY, // screen location to read, X:loword, Y:hiword
out uint c_out); // (unwanted, discard)
您可能会注意到我已将这些封送处理减少到了示例代码所需的最低限度,该示例代码旨在一次仅获取一个字符。因此,由于托管指针声明“out byte ch”和“out Char ch”,您可能会发现c_in 必须始终为1。
这就是你真正需要的;如果您限制自己阅读单个字符,则如上所述调用适当的 P/Invoke 函数通常是不言自明的。为了用一个简单的例子来说明这一点,我将完成一个可爱的演示程序,它沿着我们上面绘制的网格的对角线从Console 中读取四个字符。
static void Windows_Console_Readback()
{
var stdout = GetStdHandle(-11);
for (uint coord, y = 1; y <= 4; y++)
{
coord = (5 - y) * 2; // loword <-- X coord to read
coord |= y << 16; // hiword <-- Y coord to read
if (!ReadConsoleOutputCharacterA(
stdout,
out byte chAnsi, // result: single ANSI char
1, // # of chars to read
coord, // (X,Y) screen location to read (see above)
out _)) // result: actual # of chars (unwanted)
throw new Win32Exception();
Console.Write(" " + (Char)chAnsi + " ");
}
}
你有它...