编辑:刚刚发现这只是 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;
};
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