【问题标题】:Windows C++: How can I redirect stderr for calls to fprintf?Windows C++:如何重定向 stderr 以调用 fprintf?
【发布时间】:2010-09-05 16:18:14
【问题描述】:

我正在将现有的 C++ 代码从 BSD 项目包装到我们自己的自定义包装器中,我希望将其集成到我们的代码中,并且尽可能少地进行更改。此代码使用fprintf 打印到stderr 以记录/报告错误。

我想将此重定向到同一进程中的其他位置。在 Unix 上,我使用 socketpairthread 完成此操作:套接字的一端是我发送 stderr 的地方(通过调用 dup2)另一端在一个线程中进行监控,然后我可以在其中处理输出。

这在 Windows 上不起作用,因为套接字与文件句柄不同。

我在网上找到的所有文档都显示了如何重定向子进程的输出,这不是我想要的。如何在写入输出时在同一进程中重定向 stderr 以获取某种回调? (在你这么说之前,我已经尝试过SetStdHandle,但找不到任何方法来完成这项工作)......

【问题讨论】:

    标签: c++ windows redirect


    【解决方案1】:

    您可以在 Windows 上使用类似的技术,您只需为相同的概念使用不同的词。 :) 本文:http://msdn.microsoft.com/en-us/library/ms682499.aspx 使用 win32 管道处理来自另一个进程的 I/O,您只需对同一进程中的线程执行相同的操作。当然,在您的情况下,从流程中的任何位置到 stderr 的所有输出都将重定向到您的消费者。

    实际上,您可能需要的其他拼图是_fdopen_open_osfhandle。事实上,这是我多年前发布的一些code 的相关示例:

    DWORD CALLBACK DoDebugThread(void *)
    {
        AllocConsole();
        SetConsoleTitle("Copilot Debugger");
        // The following is a really disgusting hack to make stdin and stdout attach
        // to the newly created console using the MSVC++ libraries. I hope other
        // operating systems don't need this kind of kludge.. :)
        stdout->_file = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
        stdin->_file  = _open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT);
        debug();
        stdout->_file = -1;
        stdin->_file  = -1;
        FreeConsole();
        CPU_run();
        return 0;
    }   
    

    在这种情况下,主进程是一个 GUI 进程,它根本不以 stdio 句柄开始。它打开一个控制台,然后将正确的句柄推入 stdout 和 stdin 以便 debug() 函数(设计为 stdio 交互函数)可以与新创建的控制台交互。您应该能够打开一些管道并执行相同的操作来重定向 stderr。

    【讨论】:

      【解决方案2】:

      您必须记住,MSVCRT 所称的“操作系统句柄”不是 Win32 句柄,而是添加的另一层句柄只是为了让您感到困惑。 MSVCRT 尝试模拟 stdin = 0、stdout = 1、stderr = 2 等的 Unix 句柄编号。 Win32 句柄的编号不同,并且它们的值总是恰好是 4 的倍数。打开管道并正确配置所有句柄将需要让你的手变得凌乱。可能需要使用 MSVCRT 源代码和调试器。

      【讨论】:

        【解决方案3】:

        您提到您不想将命名管道用于内部使用;可能值得指出的是,CreatePipe() 的文档指出,“匿名管道是使用具有唯一名称的命名管道实现的。因此,您通常可以将匿名管道的句柄传递给需要句柄的函数到一个命名管道。” 所以,我建议你只写一个函数来创建一个类似的管道,并具有正确的异步读取设置。我倾向于使用 GUID 作为字符串(使用 CoCreateGUID()StringFromIID() 生成)给我一个唯一的名称,然后使用重叠 I/O 的正确设置创建命名管道的服务器和客户端(更多详细信息关于这个和代码,在这里:http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html)。

        一旦我连接了一些代码,我必须使用重叠 I/O 和 I/O 完成端口来读取文件,然后,我只会在数据到达时收到数据的异步通知......但是,我有相当多的经过良好测试的库代码,可以让这一切发生......

        可能可以设置命名管道,然后使用 OVERLAPPED 结构中的事件进行重叠读取并检查事件以查看数据是否可用...我没有任何可用的代码但确实如此。

        【讨论】:

          猜你喜欢
          • 2011-07-25
          • 2021-02-04
          • 1970-01-01
          • 2023-04-09
          • 2015-09-02
          • 2022-01-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多