Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. command line and GUI at same time
Forum Updated to NodeBB v4.3 + New Features

command line and GUI at same time

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 6 Posters 1.6k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    Hu Junhao
    wrote on last edited by
    #1

    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?

    JonBJ Axel SpoerlA Paul ColbyP 3 Replies Last reply
    0
    • H Hu Junhao

      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?

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @Hu-Junhao
      This has been asked before. The choice between a Ui vs a console Windows application must be made at link time via the SUBSYTEM:... 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 use AllocConsole, 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 as SUBSYTEM:WINDOWS.

      H 1 Reply Last reply
      1
      • H Hu Junhao

        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?

        Axel SpoerlA Offline
        Axel SpoerlA Offline
        Axel Spoerl
        Moderators
        wrote on last edited by
        #3

        @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.

        Software Engineer
        The Qt Company, Oslo

        1 Reply Last reply
        0
        • Chris KawaC Online
          Chris KawaC Online
          Chris Kawa
          Lifetime Qt Champion
          wrote on last edited by
          #4

          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.

          1 Reply Last reply
          3
          • JonBJ JonB

            @Hu-Junhao
            This has been asked before. The choice between a Ui vs a console Windows application must be made at link time via the SUBSYTEM:... 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 use AllocConsole, 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 as SUBSYTEM:WINDOWS.

            H Offline
            H Offline
            Hu Junhao
            wrote on last edited by
            #5

            @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.

            JonBJ 1 Reply Last reply
            0
            • H Offline
              H Offline
              Hu Junhao
              wrote on last edited by
              #6

              @Chris-Kawa Thanks for reply.And then maybe I need QSocketNotifier to listen input from stdout?

              Chris KawaC 1 Reply Last reply
              0
              • H Hu Junhao

                @Chris-Kawa Thanks for reply.And then maybe I need QSocketNotifier to listen input from stdout?

                Chris KawaC Online
                Chris KawaC Online
                Chris Kawa
                Lifetime Qt Champion
                wrote on last edited by
                #7

                @Hu-Junhao input from stdout? For input you better redirect stdin stream.

                H 1 Reply Last reply
                0
                • H Hu Junhao

                  @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.

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by
                  #8

                  @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.

                  1 Reply Last reply
                  0
                  • Chris KawaC Chris Kawa

                    @Hu-Junhao input from stdout? For input you better redirect stdin stream.

                    H Offline
                    H Offline
                    Hu Junhao
                    wrote on last edited by Hu Junhao
                    #9

                    @Chris-Kawa @JonB Some unexcepted situation occurs.
                    my program 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);
                            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.

                    1 Reply Last reply
                    0
                    • S Offline
                      S Offline
                      SimonSchroeder
                      wrote on last edited by
                      #10

                      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 and CONFIG parameter in my .pro file) I compile a GUI .exe and a non-GUI .com. If the user types myapp -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.

                      H 1 Reply Last reply
                      0
                      • S SimonSchroeder

                        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 and CONFIG parameter in my .pro file) I compile a GUI .exe and a non-GUI .com. If the user types myapp -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.

                        H Offline
                        H Offline
                        Hu Junhao
                        wrote on last edited by
                        #11

                        @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.

                        1 Reply Last reply
                        0
                        • H Hu Junhao

                          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?

                          Paul ColbyP Offline
                          Paul ColbyP Offline
                          Paul Colby
                          wrote on last edited by
                          #12

                          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.

                          1 Reply Last reply
                          1
                          • H Hu Junhao has marked this topic as solved on

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved