2

I have an MFC application that generates some reports and shows the same in the GUI. I have a requirement of running it as a console application, when passed with certain commandline argument. In the console mode it will generate the reports/errors in standard output/error and I should be able to redirect the same to any file.

For Ex. C:/temp MyApp.exe --console > report.txt should run my exe in console mode and redirect all the output to a text file. But if I run it without any console argument, it should be like a default MFC application.

To achieve my requirement, so far I have done is, changed the Linker > System > Subsytem from Windows to Console and added WinMainCRTStartup at Linker > Advanced > Entry Point

So now my app works fine when I run it with --console parameter from console/batch files. But when I run it directly, it still opens a cmd window (of course because it is now a console application). However, I am using FreeConsole() method to get rid of it but it still flashes for a brief second.

So I am just curious if there is a way to get rid of it completely, either by deciding the application's subsytem at run time or any other trick? Any suggestion will be appreciated.

foobar
  • 2,887
  • 2
  • 30
  • 55
  • 2
    [How do I write a program that can be run either as a console or a GUI application?](http://blogs.msdn.com/b/oldnewthing/archive/2009/01/01/9259142.aspx) – Igor Tandetnik May 24 '15 at 12:43
  • You may want to consider a GUI program which simply doesn't create a window. You'd run it as `C:\temp\MyApp.exe --outputfile report.txt` because the `>` shell redirect wouldn't be supported. – MSalters May 24 '15 at 14:25
  • @MSalters: When you're launching an application through the command processor, I/O stream redirection works regardless of the application's subsystem. – IInspectable May 24 '15 at 14:26

1 Answers1

8

I'd suggest to keep your GUI application with the windows subsystem.

At the very beginning, when parsing command line, instead of creating the GUI windows (MFC inistialisation), you could create a console or attach with AttachConsole()

As a proof of concept, here how it could look like (for example in CxxxApp::InitInstance()):

...  // init code but before the the CMainFrame is created 

if(...) {   // suppose you want to go to the console
    if (! AttachConsole(ATTACH_PARENT_PROCESS))   // try to hijack existing console of command line
        AllocConsole();                           // or create your own.

    DWORD nw,nr;    // demo with windows native console i/o 
    char buff[32]; 
    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), L"Who are you ? ", 14, &nw, NULL); 
    ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE), buff, sizeof(buff), &nr, NULL);
    WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), "Hello ", 6, &nw, NULL);
    WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), buff, nr, &nw, NULL);
    ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE), buff, 1, &nr, NULL);
    ...
}

If you want to use C++ cin/cout, additional work is however needed. This other SO question addresses for example the redirecting of cout.

Community
  • 1
  • 1
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • Since it would always create a new console and never attach to that of the parent, I'm pretty sure redirecting to file from cmd.exe won't work with this approach. Recall that the motivation is to be able to run `MyApp.exe --console > report.txt` from the command line. – Igor Tandetnik May 24 '15 at 12:46
  • @Christophe I actually tried that using `AllocConsole` and `AttachConsole` methods, but then it fails to redirect the output to text file, and also console doesn't wait for the application to finish, and returns which was not desirable. – foobar May 24 '15 at 12:55
  • @IgorTandetnik it first tries to attach that of the parent. In fact if you launch this code from the command line, it stays on existing command line. It creates its own console, only if you launch this application form another GUI (f.ex, the IDE). I've just tested: `cout` output goes properly to the redirected file (even if nothing has been done to see the result on the console). – Christophe May 24 '15 at 12:58
  • @foobar indeed, the WriteConsoleA() output is not redirected. But cout output is (I've just tested with MSVC2013). – Christophe May 24 '15 at 13:01
  • `AttachConsole` is a bad idea if the program expects to read input from the parent's console. It's not that the "console doesn't wait". That makes no sense. It's that the shell, such as cmd.exe, won't wait on the process handle of a GUI application when run from an interactive command prompt. So if you attach back to the shell's console, then both your program and the shell will alternately read input from the console. You'd have to force cmd.exe to wait using `start /w` or by running from a batch file. In that case you may as well have a separate console version. – Eryk Sun May 24 '15 at 23:33
  • @eryksun I agree that attaching to the existing console is not so nice, if reading true (aka non-redirected) console input is needed. In this case the AllocConsole would make more sense. However for silent command processing, it could make sense: cin reads redirected input and cout writes on redirected output, and doing some console output on the cmd processor's windows shouldn't really harm. So it really depends on the OP's use case. – Christophe May 25 '15 at 10:14
  • 1
    Writing to the parent's console shouldn't be a technical problem, but it may be confusing at times. I suggest if it's a status message that you clearly show the source, e.g. `MyApp.exe [PID]: some status message`. – Eryk Sun May 25 '15 at 10:26