c++ - WinAPI - 如何将程序和外部 DLL 的所有标准输出重定向到 Win32 标准输出句柄?

标签 c++ c windows printf

我希望能够将 Windows 应用程序的所有标准输出重定向到 Win32 标准输出句柄,而不是使用控制台句柄。

对于上下文,Emacs Win32 FAQ 是这样说的:

Programs that explicitly use a handle to the console (CON or CON:) instead of stdin and stdout cannot be used as subprocesses to Emacs, and they will also not work in shell-mode [...] There is no convenient way for either Emacs or any shell used in shell-mode to redirect the input and output of such processes from the console to input and output pipes. The only workaround is to use a different implementation of the program that does not use the console directly. (https://www.gnu.org/software/emacs/manual/html_node/efaq-w32/Subprocess-hang.html)

我遇到了常见问题解答中描述的问题:从 Emacs 启动时,程序将运行,但 Emacs 的 shell 中不会显示任何输出。窗口直到程序退出,就好像 stdout 被缓冲并且在运行时没有刷新一样。如果从 cmd.exe 运行,同一程序将按预期实时输出标准输出。或ConEmu。

我想要完成的是使程序的所有输出都出现在 Emacs shell 中,这样我就可以在打印后立即跳转到编译器错误位置。我愿意重写程序的源代码来实现这一点。我想知道通过使用“stdin 和 stdout”而不是“控制台句柄”来完成此操作需要哪些“不同的实现”细节。

据我了解:

  1. Windows 中有多种 I/O,包括 C 运行时( printf 等)和 Win32 层( ReadFile 等)。
  2. 我假设“stdin 和 stdout”指的是 STD_INPUT_HANDLESTD_OUTPUT_HANDLE可以通过 SetStdHandle() 修改.
  3. 程序加载的外部 DLL 将继承 C 运行时 stdinstdout管道,但这发生在程序初始化时,在调用 SetStdHandle() 之前。被调用,因此您必须执行其他操作来重定向它们的输出。

我尝试过使用此代码:

#include <windows.h>
#include <cstdlib>

int main()
{
    HANDLE hStdout = CreateFile(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    HANDLE hStdin = CreateFile(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    SetStdHandle(STD_OUTPUT_HANDLE, hStdout);
    SetStdHandle(STD_ERROR_HANDLE, hStdout);
    SetStdHandle(STD_INPUT_HANDLE, hStdin);

    std::cout << "Hello, world." << std::endl;
    printf("Hello, world.\n");
    std::cin.get();

    return 0;
}

这达到了预期的效果,但仅限于 printf 的使用和std::cout在与重定向代码相同的二进制文件中。我的程序加载使用 printf 的外部 DLL并且它的输出都没有被​​重定向。

另外,我不想使用AllocConsole()或类似的,因为这会打开一个单独的窗口,该窗口不与父进程(Emacs)集成。我想要的是重定向所有标准输出,以便它显示在运行程序的同一终端/控制台中,而不是显示在不同的窗口中(如果有意义的话)。因为我不使用AllocConsole() ,然后编写类似 _open_osfhandle((long)hStdout, O_WRONLY|O_TEXT) 的代码总是返回-1由于某种原因,我似乎无法使用 dup2()如上所述here .

另请参阅:

最佳答案

我使用了上面提供的代码示例,然后调用 setvbuf(stdout, NULL, _IONBF, 4096) 设置非缓冲输出并获得了所需的结果。

关于c++ - WinAPI - 如何将程序和外部 DLL 的所有标准输出重定向到 Win32 标准输出句柄?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58807775/

相关文章:

c++ - 将 Google Mock 与 boost::bind 结合使用

windows - 如何获得 Windows 版本是 Vista 和 Delphi 上的 XP?

windows - 如何在 Windows 中子类化一个窗口? (使用围棋)

c++ - Tic Tac Toe游戏,用C++发行,具有再次播放功能

c++ - 用C++编号的文件名?

c++ - 如何引发C++异常

C:奇怪的 printf 行为

c++ - 如何将 RSA 公钥和私钥读入单个 RSA 结构?

c++ - FileObject->FileName 不返回文件的完整路径

windows - 使用WinDbg调试0xc000001d异常