Decide an application to be of console/windows subsystem at run time - c++

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.

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.

Related

spawnl and mode commands

I want to use spawnl to restore a DOS terminal session after my application has completed, I'm doing the following:
static char* pszMode = "mode.com";
int intRC = spawnl(P_WAIT, pszMode, pszMode, "co80", NULL);
char szCOM2setup[80];
sprintf(szCOM2setup, "%s:9600,n,8,1", clsPort::mpcszCOM2);
intRC = spawnl(P_WAIT, pszMode, pszMode, szCOM2setup, NULL);
mpcszCOM contains COM2
In both cases intRC contains -1, I've single stepped execution and it doesn't look like these commands are being properly executed, what haven't I done?
I'm using ROM-DOS version 6.22 on an embedded PC104 platform.
I've checking with perrror and using strError, the actual error is:
No such file or directory
But why? The path is set-up before the application is launched and mode.com is accessible from the command line in the same folder as the application.
Tried using spawnlp instead of spawnl, no better same error.
For a reason I don't understand even though the path is set-up correctly, the application was returning "No such file or directory" so I modified the application to include the path and this resolved the issue.

Getting the messages back to the same command line from where the MFC application was launched

I am executing an MFC Application from command line which takes four command line arguments.One of the argument is the directory path.
If the path is wrong then I want to show a Message "Bad Path" on the same command line
Note : For showing I don't want to take a new command line .
Basically that's not supported. There is sort of known "workaround" for that, using AttachConsole(-1) to attach parent process console. Has disadvantages of course (like, parent console will not wait for your EXE to terminate, because it's not a "console" app). Anyways, basic idea:
void WriteToParentConsole()
{
if (AttachConsole(-1))
{
char msg[] = "Bad Path!";
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msg, sizeof(msg), NULL, NULL);
// send ENTER (optional)
// ::SendMessage(GetConsoleWindow(), WM_CHAR, VK_RETURN, 0);
FreeConsole();
}
}
You can check out this article for example, or just google something on AttachConsole/GUI vs Console for more information:
http://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/

printf to both console window and file?

I have a lot of C++ programs that compile with Visual Studio 2005. They're mostly small server modules that run in console windows. Anyway, the problem I'm running into is that text can only be displayed to either the console window or a log file but not both. Each program has a command line option to specify the log file. Here is the function that I call to redirect stdout and stderr to a file.
void consoleobj::setstdouterr(const stringobj& printstr)
{
#if !defined(_WIN32_WCE)
freopen(printstr.c_str(),"w",stdout);
#ifdef _MSC_VER
::SetStdHandle(STD_ERROR_HANDLE,GetStdHandle(STD_OUTPUT_HANDLE));
#endif
#endif
// make log msgs flush to log file(cout does this(on \n?), printf doesn't)
//now if both redir to same log file, msgs should be in right order
setvbuf(stdout, NULL, _IONBF, 0); //no buffering
setvbuf(stderr, NULL, _IONBF, 0); //no buffering
}//end method setstdouterr
Is there any way to set things up so stdout and stderr are written to both the console window and an optional log file simultaneously? I've seen code that redirects cout or a wrapper function, but our print statements all use printf and I'd prefer using a function similar to the one in our consoleobj library to set this up if possible. Thanks!
Instead of implement this functionality in your code.
You can use the well known utility tee in Unix.
There is a Windows version of it called wtee.exe.
C:\> programm | wtee log.txt

C++: How to make a my program open a .exe with optional args

I'm having some trouble with a program. My goal is to have it open several .exe files with optional args passed. For example if I wanted to open up a pdf I could type the string below into a cmd window.
// If used in a cmd window it will open up my PDF reader and load MyPDF.pdf file
"c:\Test space\SumatraPDF.exe" "c:\Test space\Sub\MyPDF.pdf"
Here are two tries I used. The first opens the PDF but of course doesn't load the file. The second simply doesn't work.
// Opens the PDF in my program
system("\"C:\\Test space\\SumatraPDF.exe\"");
// Error I get inside of a cmd window is the comment below
// 'C:\Test' is not recognized as an internal or external command, operable program or batch file.
//system("\"C:\\Test space\\SumatraPDF.exe\" \"C:\\Test space\\Sub\\MyPDF.pdf\"");
I'm unsure of the reason why the second one does not work. It could be I'm misunderstanding something about system, or I'm not using delimiters right.
I feel like there is a library out there designed for this rather than creating a long string that uses so many delimiters.
Thanks for any help.
Welcome to Stack Overflow!
The system method works by passing it's argument to cmd /c. So you will need an extra set of quotes around it. See related question posted by sled.
As an alternative to system, take a look at the ShellExecute or ShellExecuteEx Win32 API function. It has more features although it is not as portable.
// ShellExecute needs COM to be initialized
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
SHELLEXECUTEINFO sei = {0};
sei.cbSize = sizeof(sei);
sei.lpFile = prog; // program like c:\Windows\System32\notepad.exe
sei.lpParameters = args; // program arguments like c:\temp\foo.txt
sei.nShow = SW_NORMAL; // app should be visible and not maximized or minimized
ShellExecuteEx(&sei); // launch program
CoUninitialize();
More information here.

C++ separate command line window?

So I have a GUI program and for some reason it does not let me debug using printf().
When I use printf(), it does not go to the Visual Studio debugger for some reason.
Anyways, I wanted to make my own separate window that opens up when the GUI opens up,
and basically be able to feed information into that console and talk to it.
For example:
void talk(std::string info){
//Add the value of info to the next line in the console
}
Anyone know how to do this?
Basically create a command line and talk to it so I can see output:
CommandLine c;
c.talk("hey!");
You can create a console using AllocConsole to create a console, then write to that explicitly (there are a few methods, GetStdHandle and file write will work). You can also use OutputDebugString to write to the VS output window.
void makeConsole()
{
AllocConsole();
console = GetStdHandle(STD_OUTPUT_HANDLE);
}
void talk(std::string info)
{
WriteFile(console, info.c_str(), info.length()); // To console
OutputDebugString(info.c_str()); // To output window
}
(pseudo-code, functions may not be quite right)
Edit:
If you're writing to the console only through your talk function, this will work fine. If you're using printf/cout throughout your code, you definitely want to use Ben's method (much simpler to use repeatedly).
#peachykeen has half the solution. If you want to make printf and cout work, try this:
AllocConsole();
freopen("CONOUT$", "w", stdout);