SetConsoleActiveScreenBuffer不显示屏幕缓冲区

Mec*_*MK1 2 c# winapi console-application

我目前正在尝试用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);
}
Run Code Online (Sandbox Code Playgroud)

发生了以下事情:

  • 屏幕保持为空,即使它应该显示 newBuffer
  • 当写入oldBuffer而不是时newBuffer,数据立即出现.因此,我写入缓冲区的方式应该是正确的.
  • 在调用时SetConsoleActiveScreenBuffer(newBuffer),错误代码现在是6,这意味着句柄无效.这很奇怪,因为句柄不是-1,文档描述为无效.

我应该注意到,我很少直接使用Win32 API,并且对常见的Win32相关问题知之甚少.我会很感激任何帮助.

Har*_*ton 5

正如IInspectable在评论中指出的那样,你将设置dwDesiredAccess为零.这为您提供了一个没有访问权限的句柄.有一些边缘情况,这样的句柄是有用的,但这不是其中之一.

唯一有点奇怪的是,你得到的是"无效句柄"而不是"拒绝访问".我猜你正在运行Windows 7,因此句柄是用户模式对象("伪句柄")而不是内核句柄.

无论如何,你需要设置dwDesiredAccessGENERIC_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
    );
Run Code Online (Sandbox Code Playgroud)

  • [DllImport]声明也不正确,最后一个参数是IntPtr. (3认同)