Can One Executable Be Both a Console and Gui Application

Can one executable be both a console and GUI application?

Jdigital's answer points to Raymond Chen's blog, which explains why you can't have an application that's both a console program and a non-console* program: The OS needs to know before the program starts running which subsystem to use. Once the program has started running, it's too late to go back and request the other mode.

Cade's answer points to an article about running a .Net WinForms application with a console. It uses the technique of calling AttachConsole after the program starts running. This has the effect of allowing the program to write back to the console window of the command prompt that started the program. But the comments in that article point out what I consider to be a fatal flaw: The child process doesn't really control the console. The console continues accepting input on behalf of the parent process, and the parent process is not aware that it should wait for the child to finish running before using the console for other things.

Chen's article points to an article by Junfeng Zhang that explains a couple of other techniques.

The first is what devenv uses. It works by actually having two programs. One is devenv.exe, which is the main GUI program, and the other is devenv.com, which handles console-mode tasks, but if it's used in a non-console-like manner, it forwards its tasks to devenv.exe and exits. The technique relies on the Win32 rule that com files get chosen ahead of exe files when you type a command without the file extension.

There's a simpler variation on this that the Windows Script Host does. It provides two completely separate binaries, wscript.exe and cscript.exe. Likewise, Java provides java.exe for console programs and javaw.exe for non-console programs.

Junfeng's second technique is what ildasm uses. He quotes the process that ildasm's author went through when making it run in both modes. Ultimately, here's what it does:

  1. The program is marked as a console-mode binary, so it always starts out with a console. This allows input and output redirection to work as normal.
  2. If the program has no console-mode command-line parameters, it re-launches itself.

It's not enough to simply call FreeConsole to make the first instance cease to be a console program. That's because the process that started the program, cmd.exe, "knows" that it started a console-mode program and is waiting for the program to stop running. Calling FreeConsole would make ildasm stop using the console, but it wouldn't make the parent process start using the console.

So the first instance restarts itself (with an extra command-line parameter, I suppose). When you call CreateProcess, there are two different flags to try, DETACHED_PROCESS and CREATE_NEW_CONSOLE, either of which will ensure that the second instance will not be attached to the parent console. After that, the first instance can terminate and allow the command prompt to resume processing commands.

The side effect of this technique is that when you start the program from a GUI interface, there will still be a console. It will flash on the screen momentarily and then disappear.

The part in Junfeng's article about using editbin to change the program's console-mode flag is a red herring, I think. Your compiler or development environment should provide a setting or option to control which kind of binary it creates. There should be no need to modify anything afterward.

The bottom line, then, is that you can either have two binaries, or you can have a momentary flicker of a console window. Once you decide which is the lesser evil, you have your choice of implementations.

* I say non-console instead of GUI because otherwise it's a false dichotomy. Just because a program doesn't have a console doesn't mean it has a GUI. A service application is a prime example. Also, a program can have a console and windows.

Both CLI and GUI application

The accepted answer in the question you linked to contains this passage:

Junfeng's second technique is what ildasm uses. He quotes the process
that ildasm's author went through when making it run in both modes.
Ultimately, here's what the it does:

The program is marked as a console-mode binary, so it always starts
out with a console. This allows input and output redirection to work
as normal. If the program has no console-mode command-line parameters,
it re-launches itself. It's not enough to simply call FreeConsole to
make the first instance cease to be a console program. That's because
the process that started the program, cmd.exe, "knows" that it started
a console-mode program and is waiting for the program to stop running.
Calling FreeConsole would make ildasm stop using the console, but it
wouldn't make the parent process start using the console.

To me it looks like the headache of having a binary trying to switch between the console subsystem and GUI subsystem (which really isn't allowed) is more effort than it's worth.

One approach would be to have a separate GUI application .exe. Whenever the console app is started without parameters it launches the GUI app and closes itself.

To prevent code duplication this probably requires all the actual logic of the application to be put in a separate class library.

Program both as Console and GUI

http://blogs.msdn.com/oldnewthing/archive/2009/01/01/9259142.aspx

One executable that starts as a GUI application or console application based on command line in Visual Studio 2005

I think the preferred technique for the situation here is the ".com" and ".exe" method. In Windows from the command line, if you run a program and don't specify an extension, the order of precedence in locating the executable will .com preferred over a .exe file.

Then you can use tricks to have that ".com" be a proxy for the stdin/stdout/stderr and launch the same-named .exe file. This give the behavior of allowing the program to preform in a command-line mode when called form a console (potentially only when certain command-line arguments are detected) while still being able to launch as a GUI application free of a console.

There are various articles describing this, like "How to make an application as both GUI and Console application?" (see references in link below).

I hosted a project called dualsubsystem on google code that updates an old codeguru solution of this technique and provides the source code and working example binaries.

I hope that is helpful!

Is it's possible make GUI and console app in one exe?

Yes, it isn't always easy though and might not be worth it. The general idea is to write a console program that attempts to dynamically load the gui libraries and create a window. If that succeeds, it detaches from the console/controlling terminal and becomes a gui program. On Windows, this may pop up a console window briefly when the user double clicks the exe as it would be created first, then quickly destroyed.

You would want to dynamically load the gui with dlopen/LoadLibrary because the libs might not even be present on the computer you're running on, and if you rely on the system to load them at startup, your program won't run at all when they are missing. This is the most painful part - checking the return value of XOpenDisplay or CreateWindow or whatever is easy, and detaching from a console is easy (FreeConsole or fork). But first you need to get your program to actually start in the worst case scenario of no client side gui libraries at all.

If you're ok with ignoring that case - if the libs are present but the display isn't, you just handle it as a regular runtime error - then it isn't too hard at all.

Windows GUI as well as console application

When the shell launches a console application from an interactive command line, it waits for the application to exit. That's necessary, because it prevents the application and the shell from competing for access to the console's input and output. This also means that the shell knows when to reprint the prompt.

When the shell launches a GUI application from an interactive command line, it doesn't wait. In this case, there's no need, and it would be inconvenient for the user. (It does wait when launching a GUI application from a batch file.)

(The user can override the default behaviour by using start with or without the /wait option.)

By using AttachConsole() you've subverted this mechanism, giving yourself access to the console while the shell believes nothing else is using it. This creates an inherent race condition - your output might wind up before, after, or intermingled with the shell prompt or with the output of other shell commands the user might run. (Also, if you wanted user input, there would be no reliable way to predict which input would go to the shell and which to your process.) The shell has no way to detect this condition and does not even attempt to do so.

The bottom line is that, unfortunately, there is no good way for a single executable to be suitable for both console and GUI use. Instead, create two executables, one for each scenario. If disk space is a concern, it is reasonably easy to make one of the executables very small, doing nothing but calling upon the other one. Better still, you can put the bulk of the application into a single DLL and have both executables load it.

Console Application to be run as GUI as well

OK I thought I'd have a play at this as I was curious.

  • First I updated the Main method in Program.cs to take arguments so I could specify -cli and get the application to run on the command line.
  • Second I changed the project's output type to "console application" in the project properties.
  • Third I added the following methods to Program.cs

    private static void HideConsoleWindow()
    {
    var handle = GetConsoleWindow();

    ShowWindow(handle, 0);
    }

    [DllImport("kernel32.dll")]
    static extern IntPtr GetConsoleWindow();

    [DllImport("user32.dll")]
    static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
  • Fourth I call HideConsoleWindow as the first action in non-CLI mode.

After these steps my (basic) application looks like:

    [STAThread]
static void Main(string[] args)
{
if (args.Any() && args[0] == "-cli")
{
Console.WriteLine("Console app");
}
else
{
HideConsoleWindow();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}

Then if I open the program on the command line with the -cli switch it runs as a command line application and prints content out to the command line and if I run it normally it loads a command line window (extremely) briefly and then loads as a normal application as you'd expect.



Related Topics



Leave a reply



Submit