C++ WinAPI - GetConsoleScreenBufferInfo 总是因句柄无效而失败(返回 0)

Posted

技术标签:

【中文标题】C++ WinAPI - GetConsoleScreenBufferInfo 总是因句柄无效而失败(返回 0)【英文标题】:C++ WinAPI - GetConsoleScreenBufferInfo always fails by invalid handle (Returns 0) 【发布时间】:2018-11-12 05:31:28 【问题描述】:

我正在编写一个简单的程序,以字符/行的形式输出控制台的正确(和当前)宽度和高度。

#include <iostream>
#include <Windows.h>
using namespace std;

int main()

    CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
    GetConsoleScreenBufferInfo(GetStdHandle(STD_INPUT_HANDLE), &csbiInfo);
    cout << csbiInfo.dwSize.X;
    cout << csbiInfo.srWindow.Bottom - csbiInfo.srWindow.Top;
    system("PAUSE");

但是,虽然 GetStdHandle 不返回 INVALID_HANDLE_VALUE,但 GetConsoleScreenBufferInfo 失败(返回 0),错误代码为 0x6(无效句柄)

我也尝试过使用 GetConsoleWindow();代替 GetStdHandle 无效。

我使用的是 Windows 10 和 VS2017。我觉得我可能是在我的头上,或者推动做一些过于系统特定的事情。

提前感谢您提供任何解决方案/替代方案。

【问题讨论】:

如果你使用STD_OUTPUT_HANDLE而不是输入句柄会发生什么? docs.microsoft.com/en-us/windows/console/console-handles "最初,STDIN 是控制台输入缓冲区的句柄,STDOUT 和 STDERR 是控制台活动屏幕缓冲区的句柄" "Input""screen buffer" 没有重叠。如果您想知道在屏幕缓冲区的一行中可以输出多少个字符,您将不得不使用输出句柄。 【参考方案1】:

STD_INPUT_HANDLE 通常连接到终端键盘。 STD_OUTPUT_HANDLE 和 STD_ERROR_HANDLE 通常用作控制台。假设 STD_INPUT_HANDLE 不能被“GetConsoleScreenBufferInfo()”识别为“控制台句柄”。您可以使用“STD_OUTPUT_HANDLE”来获取控制台句柄。

  #include <iostream>
  #include <Windows.h>
  using namespace std;

  int main()
  
      CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
      GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbiInfo);
      cout << csbiInfo.dwSize.X;
      cout << csbiInfo.srWindow.Bottom - csbiInfo.srWindow.Top;
      system("PAUSE");
  

【讨论】:

找不到句柄怎么办?并使用您已有的。换句话说,这不是答案。【参考方案2】:

虽然 Drake Wu 的回答是一个很好的提示......哦,我在说什么,这个问题同样是一个很好的提示。德雷克的答案是没有答案。

我被这个问题困扰了好几天,并且有解决方案和理由。

问题是 MSDN 对该函数 GetConsoleBufferInfo 的文档不佳。没有人再关心游戏机在其他地方讨论它了。 android 很重要,它让控制台和终端成为中指。

MSDN 声明该句柄必须是控制台输出句柄。它没有告诉你如何得到那个句柄。

HANDLE h_out = CreateFile("CONOUT$",GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

HANDLE h_out = GetStdHandle(STD_OUTPUT_HANDLE);

然后它说句柄必须具有 GENERIC_READ 访问权限。我勒个去!!!控制台输入不是应该具有 GENERIC_READ 访问权限的输入吗???哦!他们可以同时拥有访问权限。

HANDLE h_out = CreateFile("CONOUT$",GENERIC_WRITE|GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

分配给 STD_OUTPUT_HANDLE 的作用类似。这是让 GetConsoleBufferInfo 接受您的句柄的方法。

但是很好,很好!!!一个控制台句柄可以同时拥有两种访问权限。我将使用一个而不是使用两个手柄!!!!就像posix一样。

 char buf[90];
HANDLE fhandle = CreateFile("CONOUT$",GENERIC_WRITE|GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
WriteFile(fhandle,"I am not accepting input from this handle",90,NULL,0);

// ReadFile fails
ReadFile(fhandle,buf,90,NULL,0);

这很糟糕。那么为什么 CONOUT 有 GENERIC_READ 访问权限呢?你知道吗?使用 CreateFile 螺丝打开终端。

PS:微软控制台 api 麻烦多于它的价值。你应该坚持使用 posix 函数 _open、_read、_write;除非您需要或希望做某些事情,例如巧妙地更改文本和背景的颜色。控制台 api 的一个大问题是它在读取大量请求时失败。

Read/WriteFile(handle,buf,65000 bytes!,0,0)  // fails

然而

_read/_write(fd,buf,100000 more bytes) // doesnt fail, plus it has less parameters

PS^2 自从我开始学习 Cpp 以来,我一直在设计实用程序库。这就是我目前支持 Win32 和 Linux 的文件库。如果它们对我的问题有所帮助,我现在想将它们提供给更广泛的公众。我的电子邮件地址是 d.master51@yahoo.com

【讨论】:

以上是关于C++ WinAPI - GetConsoleScreenBufferInfo 总是因句柄无效而失败(返回 0)的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 C++ 和 winAPI 检查目录是不是存在 [重复]

WinAPI - C++ - 将超链接添加到窗口

C++ WinAPI:处理长文件路径/名称

如何安全地调用 TerminateThread 和 FreeLibrary (WinAPI, C++)

为对话框启用关闭按钮 c++ winapi

简单的匿名管道 - 您使用啥包装器模型? (WinAPI, C++)