Thursday, August 30, 2007

Running the same application as Windows Application and Console Application

Say you have a Windows Application (i.e. with GUI and all), and you want to add to it the option to be executed as a Console Application as well. Here are the two steps necessary:

1. Adding Console Application support

You must create your application as a Windows Application. Then open the Project Properties, and under the Application tab set the "Output type" to "Console Application". Once this is set, you must update your Main function to support dual application types. By default, when you create your application as a Windows application, your Main looks like this:

static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}



To support both Console Application and Windows Application, you must change it. For example, you can decide that if it receives as sole argument the string "OpenForm" it will open as a Windows Application, otherwise as a simple Console Application (in which case you'll probably want to take care of the arguments). So you should change your Main as so:


static void Main(string[] args)
{
if (args.Length == 1 && args[0] == "OpenForm")
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else
{
// TODO: Take care of arguments
Console.WriteLine("This is a console application");
}
}



2. Remove the annoying background console


The above code is nice, but has one annoying side-effect - when you open the application as a Windows Application, you constantly have a console open in the background (closing it will close your form). To work around this you must reopen the application (i.e. creating a new process) with the console hidden. This is done as so:


static void Main(string[] args)
{
if (args.Length == 0)
{
Process current = Process.GetCurrentProcess();
string fileName = current.MainModule.FileName;
ProcessStartInfo si = new ProcessStartInfo(fileName, "OpenForm");

si.CreateNoWindow = true;
si.RedirectStandardError = true;
si.RedirectStandardOutput = true;
si.UseShellExecute = false;
Process.Start(si);
}
else if (args.Length == 1 && args[0] == "OpenForm")
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else
{
// TODO: Take care of arguments
Console.WriteLine("This is a console application");
}
}



Explanation:

The assumption is that if you want the application to run as a Windows Application, it doesn't need any argument (though this could also be done easily if required). So if the application starts with no arguments, it will create a new process of itself (through the MainModule we extract the running process' file name), but this time with no console in the background (all the settings on the ProcessStartInfo object). This time, it is called with an argument that knows to load the form (the "OpenForm" argument).



The result is an application that can be run both as Windows Application and Console Application. When you run it as a Windows Application there is a console that opens and closes immediately in the background, but that's all.


Thanks to Ami Bar for helping me with the second step.

2 comments:

matware said...

Thanks a million for that, simple and sweet.

Razor1973 said...

This was exactly what I was looking for and worked like a charm, except for one little detail.

I had to replace the line that reads...

string fileName = current.MainModule.FileName;by...

string fileName = current.MainModule.FileName.Replace(".vshost", "");... because VS was trying to execute "MyApplication.vshost.exe" instead of "MyApplication.exe" and the form wasn't opening. (Maybe this only happens in debug mode.)