SetConsoleActiveScreenBuffer不显示屏幕缓冲区
我目前正在尝试使用两个屏幕缓冲区在C#中编写一个控制台应用程序,这些缓冲区应该来回交换(很像现代GPU上的VSync)。 由于System.Console
类没有提供切换缓冲区的方法,我不得不从kernel32.dll P / Invoke几个方法。
这是我目前的代码,大大简化了:
static void Main(string[] args) { IntPtr oldBuffer = GetStdHandle(-11); //Gets the handle for the default console buffer IntPtr newBuffer = CreateConsoleScreenBuffer(0, 0x00000001, IntPtr.Zero, 1, 0); //Creates a new console buffer /* Write data to newBuffer */ SetConsoleActiveScreenBuffer(newBuffer); }
发生以下事情:
- 屏幕保持为空,即使它应该显示
newBuffer
- 当写入
oldBuffer
而不是newBuffer
,数据会立即显示。 因此,我写入缓冲区的方式应该是正确的。 - 在调用
SetConsoleActiveScreenBuffer(newBuffer)
,错误代码现在为6,表示无效句柄。 这很奇怪,因为句柄不是-1,文档描述为无效。
我应该注意到,我很少直接使用Win32 API,并且对常见的Win32相关问题知之甚少。 我会很感激任何帮助。
正如IInspectable在评论中指出的那样,你将dwDesiredAccess
设置为零。 这为您提供了一个没有访问权限的句柄。 有一些边缘情况,这样的句柄是有用的,但这不是其中之一。
唯一有点奇怪的是,你得到的是“无效句柄”而不是“拒绝访问”。 我猜你正在运行Windows 7,因此句柄是用户模式对象(“伪句柄”)而不是内核句柄。
无论如何,您需要将dwDesiredAccess
设置为GENERIC_READ | GENERIC_WRITE
GENERIC_READ | GENERIC_WRITE
,如示例代码所示。
另外,正如Hans在评论中指出的那样,pinvoke.net上的声明是不正确的,将最后一个参数指定为四字节整数而不是指针大小的整数。 我相信正确的声明是
[DllImport("kernel32.dll", SetLastError = true)] static extern IntPtr CreateConsoleScreenBuffer( uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwFlags, IntPtr lpScreenBufferData );