Windows GUI 应用程序中重定向的标准输出上的 WriteFile 返回 ERROR_NO_DATA

问题描述 投票:0回答:1

编辑:刚刚发现这只是 PowerShell 控制台的问题。它似乎可以从 cmd.exe 运行。调查更多...

在 Windows GUI (/SUBSYSTEM:WINDOWS) 应用程序中,附加或创建控制台相对容易,只需将 WriteFile 写入标准输出即可。 (如果想要使用标准 C/C++ API,这可能会涉及到,例如,如何使用 Windows 程序在 C++ 中获取控制台输出?,但如果使用 Win32 API WriteFile,这似乎很简单)。

但是我注意到,当 stdout 被重定向时,代码在控制台应用程序中运行良好,如果是 GUI 应用程序,则代码会崩溃。

基本代码如下(或查看完整示例:https://github.com/billti/WinCons)。只需将以下内容包含为头文件,并在

WinMain
实例化该类后不久,调用
CreateConsole
,然后对
Write
的任何调用都将失败,并显示标有
***
的错误 – 但仅在使用重定向输出启动时(例如
myapp.exe > .\log.txt
)。如果不重定向,它可以正常工作,并且无论哪种方式在控制台应用程序中都可以正常工作。

注意:连接到父控制台可能会导致交错输出混乱,但它确实有效。

知道如何解决这个问题吗?如何从非控制台 Windows 应用程序获取重定向的标准输出来工作?

#include <string>
 
class Log
{
public:
    void CreateConsole() {
        // In a console app, redirected or not, this returns a valid handle.
        // In a non-redirected GUI app, this returns NULL.
        // If redirected GUI (e.g. "winapp.exe > .\log.txt") this returns a valid handle.
        hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
        if (hStdOut == NULL || hStdOut == INVALID_HANDLE_VALUE) {
            // If launched from a console, then Attach work, else must Alloc.
            if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
                if (!AllocConsole()) {
                    throw std::exception("Failed to allocate a console");
                }
            }
            hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
            if (hStdOut == INVALID_HANDLE_VALUE || hStdOut == NULL) {
                throw std::exception("Invalid stdout");
            }
        }
        hasConsole = true;
    }
 
    void Write(const std::string& msg) {
        DWORD written = 0;
        DWORD err = 0;
        if (hasConsole) {
            if (!WriteFile(hStdOut, msg.c_str(), msg.length(), &written, nullptr)) {
                // *** If output is being redirected in a GUI app, this always fails with ***
                //   0xE8 ERROR_NO_DATA "The pipe is being closed."
                err = GetLastError();
                throw std::exception("Failed to write to console");
            }
        }
    }
 
private:
    bool hasConsole = false;
    HANDLE hStdOut = INVALID_HANDLE_VALUE;
};
c windows winapi stdout win32gui
1个回答
0
投票

EDITBIN解决了这个PS问题

editbin /SUBSYTEM:CONSOLE myguiapp.exe

有点奇怪的解决方案,但仍然有效......

editbin 是 VS Tools 的一部分,据我所知

> where editbin
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\bin\Hostx86\x86\editbin.exe
© www.soinside.com 2019 - 2024. All rights reserved.