This is my first question here!
I'm about to port some piece of fine working C++ code from UNIX to Windows, which redirects stdout and stderr to a custom GUI Component through pipes. I need it to display feedback from a third party library that only outputs messages to stdout on my GUI.
According to this answer https://stackoverflow.com/a/617158 this should work. In fact the code from the link works as expected in a fresh command line application built with Visual Studio 2017. However in my existing GUI application the call to _fileno(stdout)
as well as to _fileno(stderr)
both return -2 instead of the expected values 1 and 2, so just nothing is happening. Hard coding 1 and 2 to the relevant functions doesn't make it working either.
So could anyone explain
- What return value -2 could exactly mean? (Googled a lot on that - no success)
- If if is even possible to achieve what I want on Windows for an application without a console?
- If it is possible, what are the relevant steps to get it working?
For your information, I gathered my main experience on programming until now on Linux and Mac OS, so this might be something obvious for experienced Windows guys. The GUI application is based on the JUCE framework, so I'm using an auto-generated Visual Studio project created by the JUCE tool Projucer
Unlike Unix-type systems, in Windows a console application and a GUI application are two different things. GUI applications don't have the concept of stdin, stdout or stderr - they only know about windows, textboxes etc.
The documentation for _fileno says:
If stdout or stderr is not associated with an output stream (for
example, in a Windows application without a console window), the file
descriptor returned is -2.
So if you want to use stdout and stderr, you need to build your application as a console application (you can still use a GUI).
An alternative method is to carry on building the application as a GUI, but allocate a console by calling AllocConsole() at the very start of your application (i.e. the first thing you do in WinMain()
) and then associate the stdout and stderr files:
if(AllocConsole()){
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
}
I got it working with the AllocConsole approach @DodgyCodeException proposed. In the end I now call the following code in my GUI Component's constructor to launch a console and hide it right away so that the user is not confused by an empty console Window:
if(AllocConsole())
{
freopen ("CONOUT$", "w", stdout);
freopen ("CONOUT$", "w", stderr);
ShowWindow (FindWindowA ("ConsoleWindowClass", NULL), false);
}
This works well at runtime, e.g. this way it's not called until the corresponding GUI component is constructed. Furthermore this approach makes the code more reusable for me, as including it in further project does need nothing more than adding the source file instead of keeping the need of modifying the buildtime settings in mind.