c++ - 将 cout 重定向到使用 winapi 创建的新缓冲区

标签 c++ winapi console

我正在尝试打印到我用 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;
}

最佳答案

是的,这是可能的。不,这不一定完全微不足道。

基本问题相当简单:存在与命名文件对话的现有流缓冲区,但(可能)没有与控制台对话的现有流缓冲区。为了让它工作,你需要一个与控制台对话的人。这是一个相当简单的起点:

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;
    }
};

[注意:这有点不完整——控制台输出正常,但如果(例如)你复制或分配它,可能会发生不好的事情——就像大多数流缓冲区一样,你可能不应该能够复制或分配它。]

一旦你有了一个将输出写入控制台的流缓冲区,将它连接到 cout 就非常简单了:

console_stream_buffer buff(nBuf);

std::cout.rdbuf(buff);

std:cout << "bleh"; // should go to the console `nBuf`.

这是一个使用它的快速演示:

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);
}

当然,如果您愿意,您可以轻松地编写一个流缓冲区,为自己分配一个控制台屏幕缓冲区。我暂时将其分开,但根据您的使用方式,将它们组合起来可能更有意义(并且可能包含一个调用 SetConsoleActiveScreenBufferactivate 成员以及)。不过,这些都与您原来的问题无关,所以我暂时不提了。

关于c++ - 将 cout 重定向到使用 winapi 创建的新缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39110882/

相关文章:

c++ - 如何在 win32 DLL 程序中使用 IntelliProtector API

c++ - Xcode 使用哪个 C/C++ 编译器?

C++ union 用法

c++ - 在 C++ 中,使用终端窗口读取文件后如何使用标准输入?

winapi - BSTR,LPCOLESTR等的含义是什么?

c++ - 为什么 ShellExecute 找不到文件?

batch-file - 从提升的脚本以受限用户身份启动进程

c++ - 确定鼠标光标所在的控制台上的字符

c++ - 异步 Windows 控制台输入同时输出

c++ - 使用 C 代码执行 Bash 命令