Create a hybrid WinForms / CLI application
I get to create and maintain various diagnostic tools during my 'day job'. One thing that helps with the versatility of the tools is to create a Hybrid WinForms / CLI application. That way you can use a GUI for one-off scenarios and have CLI arguments for automating repetitous activities.
This article explains how to do that and provides a sample Program.cs file as an example.
References:
- C#: Is it possible to have a single application behave as Console or Windows application depending on switches? [stackoverflow.com]
- Console.Write Not Working In Win Forms App [stackoverflow.com]
- C# application both GUI and commandline [stackoverflow.com]
- FreeConsole function [msdn.microsoft.com]
- AttachConsole function [msdn.microsoft.com]
- pinvoke.net: freeconsole [pinvoke.net]
4 Different Options
There are 4 different options for adding a CLI mode to your application (that I was able to find):
- Just change static void Main() to static void Main(string[] args)
- This gives you access to CLI parameters
- Based on the number / type of argument you can choose to show or hide the Form interface
- Change the Output Type (in the project properties) to Console Application
- This will give you a Command Prompt window whenever you start your Form
- If you want to do more than just write-out to a console, you may want to consider changing Main() to Main(string[] args) so you can use arguments
Here is what the Output Type section looks like:
- Do a P/Invoke to obtain the AttachConsole method
- Keep your application type set to Windows Application
- This lets you ADD a console to your application at any time
- Can be powerful when used in conjuction with CLI arguments ( Main(string[] args) )
- Do a P/Invoke to obtain the FreeConsole method
- Set the application type to Console Application
- Run the FreeConsole function to drop the console if you don't detect relevant CLI arguments
- You will see the Consoel window 'flash' if you go this route and the code path drops the console window. This is not very important in my view.
Example of Method 4: FreeConsole
After evaluating the various options I went with the FreeConsole route. To get this to work I did the following:
- Changed the output type to Console Application
- Added in an arguments parameter to the Main method
- Added a reference to System.Runtime.InteropServices (needed for the P/Invoke)
- Used a P/Invoke to get access to the FreeConsole function
- Added logic to my Program.cs file to drop the console if there are no CLI parameters specified
Here is the code from my Program.cs (Simplified):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WebsiteMonitor {
static class Program {
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args) {
if (args.Length > 1) {
// Kick off CLI actions, then return
return;
}
// Stop the 'console' part of the app from running in WinForms mode
FreeConsole();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormWebSiteMon());
}
///
/// Lets me hide the console part of the app when running in WinForms mode
///
///
[DllImport("kernel32.dll", SetLastError = true)]
private static extern int FreeConsole();
}
}