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 检查目录是不是存在 [重复]