command line and GUI at same time
-
Hello everyone.
I have a Windows GUI application which I would like to add command line support to.I use CMAKE + VS.
Basically,
$./myapp.exe
then, GUI show up.
However, if I enter something like
$./myapp.exe -v
Nothing will output to console, because there is a link option SUBSYTEM:WINDOWS. If I change to SUBSYSTEM:CONSOLE, there is always a console widget. That's not what I want. In future plans, I'll control UI in the command line.
I tried lots of solution, AllocConsole will generate a console, not first one.
The best solution I have found is write a new program with SUBSYSTEM:CONSOLE, it will call myapp, and control UI with it too.
Is there a better solution? -
Hello everyone.
I have a Windows GUI application which I would like to add command line support to.I use CMAKE + VS.
Basically,
$./myapp.exe
then, GUI show up.
However, if I enter something like
$./myapp.exe -v
Nothing will output to console, because there is a link option SUBSYTEM:WINDOWS. If I change to SUBSYSTEM:CONSOLE, there is always a console widget. That's not what I want. In future plans, I'll control UI in the command line.
I tried lots of solution, AllocConsole will generate a console, not first one.
The best solution I have found is write a new program with SUBSYSTEM:CONSOLE, it will call myapp, and control UI with it too.
Is there a better solution?@Hu-Junhao
This has been asked before. The choice between a Ui vs a console Windows application must be made at link time via theSUBSYTEM:...
option. That cannot be altered at runtime via an option to the application.There are 3 possible approaches:
- Just supply two different executables and make the user choose which to run.
- Also supply a third "wrapper" program whose only job is to decide which of the two real ones to run depending on the
-v
argument. This program would have to be a console program if it is to inherit an existing console where it is run from. - Yes, the only way to get a single application to do it is that must be
SUBSYSTEM:WINDOWS
and must useAllocConsole
, and attach stdout etc. to that, if it wants to create one at runtime. I'm pretty sure there are some examples out there if you Google.
If you do not need to create a new console, only to use the one if invoked from command-line, have you seen https://doc.qt.io/qt-5/qapplication.html#details? That chooses whether to run as a GUI or non-GUI at runtime by what kind of
Q...Application
it creates. Note that it would always have to be linked asSUBSYTEM:WINDOWS
. -
Hello everyone.
I have a Windows GUI application which I would like to add command line support to.I use CMAKE + VS.
Basically,
$./myapp.exe
then, GUI show up.
However, if I enter something like
$./myapp.exe -v
Nothing will output to console, because there is a link option SUBSYTEM:WINDOWS. If I change to SUBSYSTEM:CONSOLE, there is always a console widget. That's not what I want. In future plans, I'll control UI in the command line.
I tried lots of solution, AllocConsole will generate a console, not first one.
The best solution I have found is write a new program with SUBSYSTEM:CONSOLE, it will call myapp, and control UI with it too.
Is there a better solution?@Hu-Junhao
Depending on what you want to on the CLI, you could add the logic in main.cpp and start the UI only if required. Here is your friend, the command line parser. -
When your app runs as SUBSYTEM:WINDOWS you can try to attach yourself to the parent process console.
If that succeeds it means you're running from console. If it fails it means it was started not from console (e.g. from double click on icon in explorer) and then you can create your own console.
Something like this:
bool attachToConsole() { // attach to existing parent bool attached = AttachConsole(ATTACH_PARENT_PROCESS) != 0; // if failed create a new console if(!attached) { attached = AllocConsole() != 0; } // redirect std out to new console if (attached) { HANDLE out_handle = GetStdHandle(STD_OUTPUT_HANDLE); if (out_handle != INVALID_HANDLE_VALUE) { FILE* new_handle {}; if (freopen_s(&new_handle, "CONOUT$", "w", stdout) != 0) { setvbuf(stdout, NULL, _IONBF, 0); } } } return attached; }
A bit of a caveat is that parent console won't know when your app is finished, so it will just sit there and wait until you press enter. You can fool it by sending a fake enter with
SendInput
or something like that. -
@Hu-Junhao
This has been asked before. The choice between a Ui vs a console Windows application must be made at link time via theSUBSYTEM:...
option. That cannot be altered at runtime via an option to the application.There are 3 possible approaches:
- Just supply two different executables and make the user choose which to run.
- Also supply a third "wrapper" program whose only job is to decide which of the two real ones to run depending on the
-v
argument. This program would have to be a console program if it is to inherit an existing console where it is run from. - Yes, the only way to get a single application to do it is that must be
SUBSYSTEM:WINDOWS
and must useAllocConsole
, and attach stdout etc. to that, if it wants to create one at runtime. I'm pretty sure there are some examples out there if you Google.
If you do not need to create a new console, only to use the one if invoked from command-line, have you seen https://doc.qt.io/qt-5/qapplication.html#details? That chooses whether to run as a GUI or non-GUI at runtime by what kind of
Q...Application
it creates. Note that it would always have to be linked asSUBSYTEM:WINDOWS
. -
@Chris-Kawa Thanks for reply.And then maybe I need QSocketNotifier to listen input from stdout?
-
@Chris-Kawa Thanks for reply.And then maybe I need QSocketNotifier to listen input from stdout?
@Hu-Junhao input from stdout? For input you better redirect stdin stream.
-
@JonB I don't need to create a new console, and I just call GUI function to implement the feature, so QCoreApplication and AllocConsole is not suitable. AttachConsole may be better. I will try first two and AttachConsole.
@Hu-Junhao said in command line and GUI at same time:
I don't need to create a new console, and I just call GUI function to implement the feature, so QCoreApplication and AllocConsole is not suitable. AttachConsole may be better.
If you only wish to inherit any console which may have pre-existed, not create your own, then indeed you need to follow the
AttachConsole(ATTACH_PARENT_PROCESS)
route suggested by @Chris-Kawa. -
@Hu-Junhao input from stdout? For input you better redirect stdin stream.
@Chris-Kawa @JonB Some unexcepted situation occurs.
my program like thisbool attachToConsole() { // attach to existing parent bool attached = AttachConsole(ATTACH_PARENT_PROCESS) != 0; // if failed create a new console if(!attached) { attached = AllocConsole() != 0; } // redirect std out to new console if (attached) { HANDLE out_handle = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE in_handle = GetStdHandle(STD_INPUT_HANDLE); if (out_handle != INVALID_HANDLE_VALUE && in_handle != INVALID_HANDLE_VALUE) { FILE* new_handle1 {}; if (freopen_s(&new_handle1, "CONOUT$", "w", stdout) != 0) { setvbuf(stdout, NULL, _IONBF, 0); } FILE* new_handle2 {}; if (freopen_s(&new_handle2, "CONIN$", "r", stdin) != 0) { setvbuf(stdin, NULL, _IONBF, 0); } } } return attached; } int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; std::string s; w.show(); attachToConsole(); printf("hello"); char aa[100]; scanf("%s", aa); printf("%s", aa); return a.exec(); }
It's good with double click in explorer.
If it's opened in terminal, the cursor will be placed before "hello", when I type, it will cover "hello"
If it's opened in cmd, whatever I input, the input will be handled as next command. The error message "is not recognized as an internal or external command,
operable program or batch file." shows.I tried something else, such as link as SUBSYSTEM:CONSOLE and
auto handle = GetConsoleWindow(); ShowWindow(handle, SW_HIDE, 0, 0) FreeConsole(); SendMessage(handle, WM_CLOSE);
But SendWindow and FreeConsole works, SendMessage does not work. I guess maybe it's a terminal, not real console.
-
When I had this problem I had a look at Visual Studio. The GUI version is called devenv.exe. However, there is also a devenv.com. If you only type
devenv
on the command line the .com will be preferred over the .exe. So, from the same source (with some#ifdef
in my C++ code andCONFIG
parameter in my .pro file) I compile a GUI .exe and a non-GUI .com. If the user typesmyapp -gui
, first the command line .com will be launched which will then launch the .exe instead and close. This seems to be the way it is supposed to work on Windows (only type the "command name" without .exe).Because I couldn't reliably figure out if the app is run from the console I decided against
AttachConsole
. -
When I had this problem I had a look at Visual Studio. The GUI version is called devenv.exe. However, there is also a devenv.com. If you only type
devenv
on the command line the .com will be preferred over the .exe. So, from the same source (with some#ifdef
in my C++ code andCONFIG
parameter in my .pro file) I compile a GUI .exe and a non-GUI .com. If the user typesmyapp -gui
, first the command line .com will be launched which will then launch the .exe instead and close. This seems to be the way it is supposed to work on Windows (only type the "command name" without .exe).Because I couldn't reliably figure out if the app is run from the console I decided against
AttachConsole
.@SimonSchroeder My alternative is similar to yours. I need to use python to manipulate the UI. I generate an App1.exe and App2 .exe, App1 using Console and App2 using Windows. The user always starts App1, if there is no parameter -nogui, start App2 directly, close APP1, if there is, hide after starting APP2, and then interact through IPC.
-
Hello everyone.
I have a Windows GUI application which I would like to add command line support to.I use CMAKE + VS.
Basically,
$./myapp.exe
then, GUI show up.
However, if I enter something like
$./myapp.exe -v
Nothing will output to console, because there is a link option SUBSYTEM:WINDOWS. If I change to SUBSYSTEM:CONSOLE, there is always a console widget. That's not what I want. In future plans, I'll control UI in the command line.
I tried lots of solution, AllocConsole will generate a console, not first one.
The best solution I have found is write a new program with SUBSYSTEM:CONSOLE, it will call myapp, and control UI with it too.
Is there a better solution?Here's a possibly relevant example from the QApplication docs:
Some GUI applications provide a special batch mode ie. provide command line arguments for executing tasks without manual intervention. In such non-GUI mode, it is often sufficient to instantiate a plain QCoreApplication to avoid unnecessarily initializing resources needed for a graphical user interface. The following example shows how to dynamically create an appropriate type of application instance:
QCoreApplication* createApplication(int &argc, char *argv[]) { for (int i = 1; i < argc; ++i) { if (!qstrcmp(argv[i], "-no-gui")) return new QCoreApplication(argc, argv); } return new QApplication(argc, argv); } int main(int argc, char* argv[]) { QScopedPointer<QCoreApplication> app(createApplication(argc, argv)); if (qobject_cast<QApplication *>(app.data())) { // start GUI version... } else { // start non-GUI version... } return app->exec(); }
Cheers.
-