dis*_*fun 3 c++ console winapi
我正在尝试打印到我用 winapi 创建的新屏幕缓冲区,但它会转到旧缓冲区并且不会显示在屏幕上,是否可以重定向cout到使用 winapi 创建的新屏幕缓冲区?
#include <iostream>
#include <Windows.h>
int main() {
HANDLE stdBuf, nBuf;
DWORD numberOfChars;
stdBuf = GetStdHandle(STD_OUTPUT_HANDLE);
nBuf = CreateConsoleScreenBuffer(GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
SetConsoleActiveScreenBuffer(nBuf);
SetStdHandle(STD_OUTPUT_HANDLE, nBuf);
// THIS SHOWING UP ON THE SCREEN
WriteConsole(nBuf, "SECOND BUFFER", 13, &numberOfChars, NULL);
// THIS IS GOING TO THE FIRST BUFFER
std::cout << "SECOND BUFFER with cout" << std::endl;
Sleep(3000);
SetConsoleActiveScreenBuffer(stdBuf);
CloseHandle(nBuf);
int a = 0;
std::cin >> a;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
是的,这是可能的。不,这并不一定是微不足道的。
基本问题相当简单:存在与命名文件对话的现有流缓冲区,但(可能)没有与控制台对话的现有流缓冲区。为了让它发挥作用,您需要一个能够与控制台对话的设备。这是一个相当简单的起点:
class outbuf : public std::streambuf {
HANDLE h;
public:
outbuf(HANDLE h) : h(h) {}
protected:
virtual int_type overflow(int_type c) override {
if (c != EOF) {
DWORD written;
WriteConsole(h, &c, 1, &written, nullptr);
}
return c;
}
virtual std::streamsize xsputn(char_type const *s, std::streamsize count) override {
DWORD written;
WriteConsole(h, s, count, &written, nullptr);
return written;
}
};
Run Code Online (Sandbox Code Playgroud)
[注意:这有点不完整 - 它可以很好地执行控制台输出,但是如果(例如)您复制或分配它,则可能会发生不好的事情 - 像大多数流缓冲区一样,您可能不应该能够复制或分配它分配它。]
一旦你有了一个将其输出写入控制台的流缓冲区,将其连接到cout就非常简单了:
console_stream_buffer buff(nBuf);
std::cout.rdbuf(buff);
std:cout << "bleh"; // should go to the console `nBuf`.
Run Code Online (Sandbox Code Playgroud)
这是一个使用它的快速演示:
int main() {
HANDLE h = CreateConsoleScreenBuffer(GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
HANDLE original = GetStdHandle(STD_OUTPUT_HANDLE);
// Create our stream buffer object
outbuf ob(h);
// write to the original buffer
std::cout << "First console";
// Set cout to go to the second buffer
std::cout.rdbuf(&ob);
// write to it
std::cout << "Second console";
// display the second buffer
SetConsoleActiveScreenBuffer(h);
// show the second buffer for a few seconds:
Sleep(5000);
// restore the original buffer
SetConsoleActiveScreenBuffer(original);
}
Run Code Online (Sandbox Code Playgroud)
当然,如果您愿意,您可以轻松编写一个为其自身分配控制台屏幕缓冲区的流缓冲区。我暂时将其分开,但根据您使用事物的方式,将它们组合起来可能更有意义(并且可能还包括一个activate调用的成员)。SetConsoleActiveScreenBuffer不过,这些都与您原来的问题无关,所以我现在就离开它。