C#: WPF / Console Hybrid Application

I am working on a WPF application which needs to also provide a command line interface running as a console application. This means that depending on how it is started, it should either work as a console application or start with a GUI.

In my case I already had a WPF application by the time this requirement came in. So I had to adapt my existing application to make it an hybrid application.

First I created a new class Program with a Main method:

using System;

namespace HybridApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
        }
    }
}

You might get an error saying that there are two Main methods, so you will have to select this new class as Startup object in the project properties.

Then you need to set the output type to “Console Application” in the project properties:

Output Type Console Application

This is required so that your application doesn’t automatically start with a GUI.

Now we’ll need either keep running as a Console application or start the WPF application depending on how the application was started.

First in order to be able to start the WPF application, you’ll need to add the STAThread attribute to your main method:

using System;

namespace HybridApp
{
    public class Program
    {
        [STAThread]
        public static void Main(string[] args)
        {
        }
    }
}

We’ll now assume that in order to start the UI, we’ll call the application with the -g argument. In order to start the GUI, all you need is to call the Main method of your WPF application:

using System;

namespace HybridApp
{
    public class Program
    {
        [STAThread]
        public static void Main(string[] args)
        {
			if (args.Length > 0 && args[0] == "-g") {
				// GUI mode
				App.Main();
			}
			else {
				// console mode
			}
        }
    }
}

Now, you’ll notice that when starting in GUI mode, you will still have a Console window displayed. This doesn’t look good. I did not find a way to completely get rid of it but at least managed to hide it before starting the UI so that you only see the console window for a very short time. In order to do this, you need to use GetConsoleWindow from kernel32.dll in order to get the handle of the console window and ShowWindow from user32.dll in order to hide it:

using System;
using System.Runtime.InteropServices;

namespace HybridApp
{
    public class Program
    {
        [DllImport("kernel32.dll")]
        private static extern IntPtr GetConsoleWindow();

        [DllImport("user32.dll")]
        private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [STAThread]
        public static void Main(string[] args)
        {
			if (args.Length > 0 && args[0] == "-g") {
				// GUI mode
				ShowWindow(GetConsoleWindow(), 0 /*SW_HIDE*/);
				App.Main();
			}
			else {
				// console mode
			}
        }
    }
}

Now all you need is to implement the logic for the console mode and you’re done !

 

Update: The problem with this solution is the console shortly flickering on the screen before it is hidden (when you start the GUI mode). I also tried another solution, making my application a Windows application and using AttachConsole to connect to the parent console. This kind of works. Your GUI will start without console being shortly displayed. And the output of your command line code will be displayed on the console. The problem is that as a Windows application, your application will fork on startup and even though it still writes to the console, it will not control it. So control will be immediately returned to the calling application/user. This is of course not what you’d expect from a command line application. The only way to retain control of the console is to make your application a Console application.

Update: Another solution is to implement the way Microsoft build devenv (Visual Studio) or the way the Windows Script Host does it. There are two executables devenv.com and devenv.exe (or wscript.exe and cscript.exe). One is used from the command line and the other to start the GUI. If you need to start one and then switch to another mode, you can start the second one and exit. For devenv, it also relies on the fact that com files get picked before exe files when you call it from the command line without the file extension. But in my case I just didn’t want to produce two executables so I decided to live with the short console flickering.