【问题标题】:Trying to redirect stdout and stderr on Windows - _fileno(stdout) returning -2尝试在 Windows 上重定向标准输出和标准错误 - _fileno(stdout) 返回 -2
【发布时间】:2019-01-20 04:58:15
【问题描述】:

这是我的第一个问题!

我即将将一些正常工作的 C++ 代码从 UNIX 移植到 Windows,它通过管道将 stdout 和 stderr 重定向到自定义 GUI 组件。我需要它来显示来自第三方库的反馈,该库仅在我的 GUI 上将消息输出到标准输出。

根据这个答案https://stackoverflow.com/a/617158 这应该可以工作。事实上,链接中的代码在使用 Visual Studio 2017 构建的新命令行应用程序中按预期工作。但是在我现有的 GUI 应用程序中,对 _fileno(stdout)_fileno(stderr) 的调用都返回 -2 而不是预期值1和2,所以什么都没有发生。对相关函数进行硬编码 1 和 2 也无法使其正常工作。

谁能解释一下

  • 返回值 -2 究竟意味着什么? (谷歌搜索了很多 - 没有成功)
  • 如果没有控制台的应用程序甚至可以在 Windows 上实现我想要的功能?
  • 如果可能,有哪些相关步骤可以使其正常工作?

供您参考,我收集了迄今为止在 Linux 和 Mac OS 上编程的主要经验,因此这对于有经验的 Windows 人员来说可能是显而易见的。 GUI 应用程序基于 JUCE 框架,因此我使用的是由 JUCE 工具 Projucer 创建的自动生成的 Visual Studio 项目

【问题讨论】:

    标签: c++ windows pipe


    【解决方案1】:

    与 Unix 类型的系统不同,在 Windows 中,控制台应用程序和 GUI 应用程序是两个不同的东西。 GUI 应用程序没有标准输入、标准输出或标准错误的概念——它们只知道窗口、文本框等。

    documentation for _fileno says

    如果 stdout 或 stderr 没有与输出流相关联(对于 例如,在没有控制台窗口的 Windows 应用程序中),文件 返回的描述符是-2。

    因此,如果您想使用 stdout 和 stderr,您需要将您的应用程序构建为控制台应用程序(您仍然可以使用 GUI)。

    另一种方法是继续将应用程序构建为 GUI,但通过在应用程序的一开始调用 AllocConsole() 分配控制台(即您在 WinMain() 中所做的第一件事),然后关联标准输出和 stderr 文件:

    if(AllocConsole()){
        freopen("CONOUT$", "w", stdout);
        freopen("CONOUT$", "w", stderr);
    }
    

    【讨论】:

    • 我怎么能忽略 _fileno 文档中的“注意”框。谢谢你指点我那里。是否需要在构建时更改某些内容以使应用程序成为具有此功能的控制台应用程序,或者是否可以在运行时使用 AllocConsole 添加控制台 IO(并以某种方式直接隐藏不需要的控制台窗口)以实现我想要的?
    • @PluginPenguin 创建项目时可以设置模式;不确定更改现有项目有多容易。另一种选择是使用EDITBIN,它至少带有某些版本的 Dev/Visual Studio 来切换模式(/SUBSYSTEM:CONSOLE/SUBSYSTEM:WINDOWS)。
    • @PluginPenguin 如果您的应用程序是作为控制台应用程序启动的(或者作为一个单独的应用程序构建,或者使用 EDITBIN 作为上面描述的 TripeHound),那么您已经设置了 stdout 和 stderr。如果您调用AllocConsole,则不必更改其构建方式,但您需要在代码中重新分配stdout和stderr,如答案所示,因为它们不会在启动期间设置。
    【解决方案2】:

    我使用 @DodgyCodeException 建议的 AllocConsole 方法让它工作。最后,我现在在我的 GUI 组件的构造函数中调用以下代码来启动控制台并立即将其隐藏,这样用户就不会被空的控制台窗口混淆:

    if(AllocConsole())
    { 
        freopen ("CONOUT$", "w", stdout); 
        freopen ("CONOUT$", "w", stderr); 
        ShowWindow (FindWindowA ("ConsoleWindowClass", NULL), false); 
    }
    

    这在运行时运行良好,例如这样,在构建相应的 GUI 组件之前不会调用它。此外,这种方法使代码对我来说更可重用,因为将其包含在进一步的项目中只需要添加源文件而不是记住修改构建时间设置的需要。

    【讨论】:

      猜你喜欢
      • 2011-07-08
      • 2012-03-30
      • 2010-10-12
      • 1970-01-01
      • 2011-10-11
      • 2014-03-22
      • 1970-01-01
      相关资源
      最近更新 更多