Reputation: 1868
EDIT: Just found out this is only an issue from a PowerShell console. It seems to work from cmd.exe. Investigating that more...
In a Windows GUI (/SUBSYSTEM:WINDOWS) app, it is relatively easy to attach or create a console, and just WriteFile to stdout. (This can get involved if wanting to use the standard C/C++ APIs, e.g. How do I get console output in C++ with a Windows program?, but if using the Win32 API WriteFile it seems simple enough).
However I notice when stdout is redirected, the code works fine in a console app, blows up if it's a GUI app.
Basic code is below, (or see full sample at https://github.com/billti/WinCons). Just include the below as a header file, and shortly after WinMain
instantiate the class, call CreateConsole
, then any call to Write
will fail with the error marked with ***
– but ONLY if launched with output redirected (e.g. myapp.exe > .\log.txt
). It works fine if not redirected, and either way works fine in a console app.
Note: Attaching to the parent console can result in confusing interleaved output, but it does work.
Any idea how to resolve this? How can I get redirected stdout from a non-console Windows app to work?
#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;
};
Upvotes: 0
Views: 379
Reputation: 1
EDITBIN solves this PS issue
editbin /SUBSYTEM:CONSOLE myguiapp.exe
A bit weird solution but still working...
editbin is a part of VS Tools afaik
> where editbin
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\bin\Hostx86\x86\editbin.exe
Upvotes: -1