SetConsoleActiveScreenBuffer 不显示屏幕缓冲区
SetConsoleActiveScreenBuffer does not display screen buffer
我目前正在尝试用 C# 编写一个带有两个屏幕缓冲区的控制台应用程序,这两个缓冲区应该来回交换(很像现代 GPU 上的 VSync)。由于 System.Console
class 没有提供切换缓冲区的方法,我不得不 P/Invoke kernel32.dll.
中的几种方法
这是我当前的代码,经过粗略的简化:
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
设置为零。这为您提供了一个没有访问权限的句柄。在某些极端情况下,这样的句柄很有用,但这不是其中之一。
唯一有点奇怪的是你得到的是 "invalid handle" 而不是 "access denied"。我猜你是 运行 Windows 7,所以句柄是用户模式对象("pseudohandle")而不是内核句柄。
无论如何,您需要将dwDesiredAccess
设置为GENERIC_READ | GENERIC_WRITE
,如图in the sample code。
此外,正如 Hans 在评论中指出的那样,pinvoke.net 上的声明不正确,将最后一个参数指定为四字节整数而不是指针大小的整数。我相信正确的声明是
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateConsoleScreenBuffer(
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwFlags,
IntPtr lpScreenBufferData
);
我目前正在尝试用 C# 编写一个带有两个屏幕缓冲区的控制台应用程序,这两个缓冲区应该来回交换(很像现代 GPU 上的 VSync)。由于 System.Console
class 没有提供切换缓冲区的方法,我不得不 P/Invoke kernel32.dll.
这是我当前的代码,经过粗略的简化:
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
设置为零。这为您提供了一个没有访问权限的句柄。在某些极端情况下,这样的句柄很有用,但这不是其中之一。
唯一有点奇怪的是你得到的是 "invalid handle" 而不是 "access denied"。我猜你是 运行 Windows 7,所以句柄是用户模式对象("pseudohandle")而不是内核句柄。
无论如何,您需要将dwDesiredAccess
设置为GENERIC_READ | GENERIC_WRITE
,如图in the sample code。
此外,正如 Hans 在评论中指出的那样,pinvoke.net 上的声明不正确,将最后一个参数指定为四字节整数而不是指针大小的整数。我相信正确的声明是
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateConsoleScreenBuffer(
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwFlags,
IntPtr lpScreenBufferData
);