How to make .NET application support both console and GUI mode

I am currently working on a next version of a utility to generate Visual Studio solutions. A new version will be called Solution Maker and add user interface support to a command line option. I wanted to mix console and GUI mode in a single program, but strictly speaking this is impossible. A program is assigned its type at compile time, so any attempt to change it’s behavior at execution time does not alter the application’s nature. A console application may create Windows forms, and a Window-based application may allocate consoles, but they won’t become ducks even if they quack.

But Visual Studio does it, don’t it? You can launch IDE and still you can run “devenv” from a command-line. How does it do it?

Well, actually it doesn’t! Here’s an explanation of the trick. There two binaries: devenv.com and devenv.exe. “Com” is always probed first, and this is the console one. So when you type “devenv” it’s a console version that will be executed. And if it does not get any command-line input, it simply launches devenv.exe. Smart!

And this can be done with any application. Here are the steps:

  1. Write an application with user interface, let’s say it’s called MyProgram.exe. This program should not have anything special.
  2. Write a command line application MyProgram.Command.exe. This program needs a few special lines, we will look at them.
  3. Rename MyProgram.Command.exe to MyProgram.com and copy it to the folder where GUI MyProgram.exe resides.

That’s it. And of course, command-line version of MyProgram needs some special code. Here it is:

class Program
{
    static void Main(string[] args)
    {
        string relayProcessPath = null;

        // Only relay to another application if no command-line arguments are specified
        if (args.Length == 0)
        {
            string thisProcessPath = Process.GetCurrentProcess().MainModule.FileName;
            if (Path.GetExtension(thisProcessPath).ToLower() == ".com")
            {
                // Relay process should only differ in extension
                string expectedRelayPath = Path.ChangeExtension(thisProcessPath, ".exe");
                if (File.Exists(expectedRelayPath))
                {
                    relayProcessPath = expectedRelayPath;
                }
            }
        }

        if (!string.IsNullOrEmpty(relayProcessPath))
        {
            // Launch relay process
            Process.Start(relayProcessPath);
        }
        else
        {
            // Process with a command line
            Console.WriteLine("Hello from command line");
        }
    }
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s