0

I'm trying to pipe standard output from a WinMain function i a VCL forms application, from a console.

In particular, I need to do this in a console:

mywinprogram.exe -v > toMyFile.txt 

where the -v stands for version. The information passed on is simply the version of the application.

I'm able to get the output to the console using the answer here: How do I get console output in C++ with a Windows program?

but piping the output to a file don't work.

When started without any arguments, the application should behave like a 'normal' windows application.

The ability to get the information this way is for the workings of an automated build system.

Totte Karlsson
  • 1,261
  • 1
  • 20
  • 55

1 Answers1

0

This is a version of what I found in Sev's answer.

Call this function the first thing you do in. _tWinMain():

#include <cstdio>
#include <fcntl.h>
#include <io.h>

void RedirectIOToConsole() {
    if (AttachConsole(ATTACH_PARENT_PROCESS)==false) return;

    HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    int SystemOutput = _open_osfhandle(intptr_t(ConsoleOutput), _O_TEXT);

    // check if output is a console and not redirected to a file
    if(isatty(SystemOutput)==false) return; // return if it's not a TTY

    FILE *COutputHandle = _fdopen(SystemOutput, "w");

    // Get STDERR handle
    HANDLE ConsoleError = GetStdHandle(STD_ERROR_HANDLE);
    int SystemError = _open_osfhandle(intptr_t(ConsoleError), _O_TEXT);
    FILE *CErrorHandle = _fdopen(SystemError, "w");

    // Get STDIN handle
    HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
    int SystemInput = _open_osfhandle(intptr_t(ConsoleInput), _O_TEXT);
    FILE *CInputHandle = _fdopen(SystemInput, "r");

    //make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
    ios::sync_with_stdio(true);

    // Redirect the CRT standard input, output, and error handles to the console
    freopen_s(&CInputHandle, "CONIN$", "r", stdin);
    freopen_s(&COutputHandle, "CONOUT$", "w", stdout);
    freopen_s(&CErrorHandle, "CONOUT$", "w", stderr);

    //Clear the error state for each of the C++ standard stream objects.
    std::wcout.clear();
    std::cout.clear();
    std::wcerr.clear();
    std::cerr.clear();
    std::wcin.clear();
    std::cin.clear();
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Thanks for the response! This application is not allowed to spawn an extra console. Only output of some information to a console if requested (the information is for an automated build system). Any way of suppressing the spawning of an extra console? – Totte Karlsson Feb 20 '20 at 22:44
  • @TotteKarlsson That was just what I was searching for :-) I'm almost certain I did something like this in C++ Builder 4 - but that was a long time ago. Oh well, when Remy sees this, he'll sort it out. – Ted Lyngmo Feb 20 '20 at 22:48
  • 1
    I tried your approach which worked fine. Perfect! However, I'm updating my question to define more of the desired behavior. – Totte Karlsson Feb 20 '20 at 22:53
  • @TotteKarlsson New version ... that seems to work from a WSL (Unbunto on Windows) prompt, but not from a classic `CMD.EXE` prompt... :-/ – Ted Lyngmo Feb 20 '20 at 23:59
  • 1
    Confirmed that this works for a powershell and bash console, but not a 'regular' cmd console. – Totte Karlsson Feb 24 '20 at 18:19
  • @TotteKarlsson Yes, that's what I found too. `CMD.EXE` is nasty that way :-) – Ted Lyngmo Feb 24 '20 at 18:20
  • I believe `freopen_s` (closes and) overwrites the `FILE*` whose address you pass as the first argument, with the `FILE*` you pass as the last argument, after it is reopened. That is, `COutputHandle` will be set to `stdout`, which will refer to CONOUT$. So what is the point of `_open_osfhandle` to get `SystemOutput ` and `_fdopen` to get the initial value of `COutputHandle`? – asynchronos Aug 25 '21 at 01:05