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.

.NET as Open Source

Microsoft is open sourcing some .NET components. This follows steps taken by Microsoft in this direction in the past few years (some may say baby steps with heavy marketing).

I still remember a time when you had Open Source projects on one side and Microsoft on the other side considering Open Source a “cancer that attaches itself in an intellectual property sense to everything it touches”.

Having worked for years with Open Source software in on different platforms, I didn’t immediately embrace the .NET platform which basically belonged to the Evil Empire. But at some point in my career, I was forced to start working with C#. Even though there were many aspects which I liked, the lack of openness was always an issue for me.

A little bit more than a year ago, I started working on a project where I use the Mono Compiler Service, NRefactory and the Orchard CMS. Even though I had been programming in C# for a few years already, this is about the time when I started writing more articles related to .NET.

So hearing that more .NET component are being released under the MIT license is good news.

Of course, it doesn’t mean that .NET is now a completely open platform. First not all of it is open source and this is (still) a one way street where Microsoft releases something and it then lives a life of its own without taking contributions back to the pieces of software distributed by Microsoft. So saying that Microsoft is open sourcing .NET is not completely true, saying that .NET is now open source is kind of misleading, but it doesn’t mean that this news has to be discarded as some pure publicity stunt from Redmond.

On the other hand, Microsoft has slowly started understanding that we’re in a new kind of market and developer communities play a major role. So going alone the way they did in the past will fail in the long term. The only way to attract more developers and make sure that you will not become obsolete 10 years from now is to open up and create an expanding community based on your products. So of course, every small step in opening .NET will be publicized as a huge step and Microsoft going Open Source but even if you get rid of all the marketing fog, I feel it’s still good news. It shows that the Open Source community has actually reached an important milestone in altering the way our industry works.

Xamarin and the Mono project it’s for sure a very welcome evolution. Just like the availability of Roslyn does open new perspectives for NRefactory and projects using NRefactory, the free availability of this code will hopefully allow many improvements in Mono and also help make its development even faster. And if it means that one day it makes Mono obsolete, as long as there is a multi-platform open alternative, I don’t see why it would be a bad thing.

So I’ll definitely have a look at the .NET Core CLR and the open source ASP.NET components on my Mac and on my Linux machines. And I do sure hope that this open sourcing of some .NET components will be followed by more and will lead to some great new projects. Of course Microsoft has an agenda of its own and open sourcing .NET components is not done just to make the world a better place. But does it really matter ? I’m always ready to complain when Microsoft is using its market strength to push crappy software to the world but whenever a change comes from their side and goes in the right direction, I feel we need to give them a chance.

Of course it’s great to do the right thing because it’s the right to do but doing the right thing because you expect to earn money out of it or just get some positive publicity is still better than not doing it or doing something wrong. So instead of complaining as some immediately did, let’s have a look at it and try to find out what new possibilities this opens.