I got an interesting question recently emphasis mine:
I am regular reader of you blog. I need some help in single instance winform. I have to open application when a file (.ext) is clicked (File is associated with that application like .doc with WINWORD). Application should be single instance. When I click the .ext file it should open the application with that content. If an instance is runnng it should ask the user whether you want to close this application and then open the new .ext file. Need help in C#.
Some questions are more interesting than others, but I think we've all had to solve this "Single Instance" problem over and over again over the last 15 years. I did this with a Dan Appleman VBX in Visual Basic 3 and I've seen piles of solutions with Mutexes and all sorts of overly complex dancing to solve this apparently simple problem. This is a really old technique, but three years later, there's just not enough people that know that the WindowsFormsApplicationBase class exists and has a lot of useful functionality in it.
There was an interesting thread over here about handling this. Someone asked the question and someone said "WinForms 2.0 has support for single instance apps built in." and the next guy said "Only for Visual Basic applications, though."
Microsoft.VisualBasic.dll has got to be one of the most useful standard installed parts of the .NET Framework out there. Folks are afraid to reference it from C#. It feels wrong.
Kind of like busting out with French words in the middle of English sentences, referencing Microsoft.VisualBasic.dll has that je ne sais quoi that tends to give C# folks a feeling of mal de mer but that assembly has a specific raison d'être. See? Feels wrong, but it still works. There's good stuff in Microsoft.VisualBasic.dll, and just because it isn't System.Something doesn't mean you shouldn't reference it with abandon. Go nuts.
Back to the problem. There's many examples, but the easiest one I've seen was over at OpenWinForms.com and it was written in C# referencing Microsoft.VisualBasic.dll. I've modified it here to make a single instance app that will open a text file name passed in on the command line. If you call the same application a second time, it'll take the new command line argument and load that text file in the first instance.
Launching it as "SuperSingleInstance foo.txt" from a command line...
Then, from the same command line, while the first one runs, launching a second "SuperSingleInstance bar.txt" from a command line. The first instance is reused, brought to the front, and gets an event letting us know someone tried to launch us and that event includes the new command line.
The code is really cool as all the work is in WindowsFormsApplicationBase. It's a little confusing because you have to call a controller instance and tell it about your MainForm, rather than calling Application.Run(). The StartupNextInstance event is called in your first application when a second instance of your app gets fired up. It talks cross process between the new second instance and your original one and passes over the command line.
using System;using System.Windows.Forms;using Microsoft.VisualBasic.ApplicationServices;namespace SuperSingleInstance{ static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); string[] args = Environment.GetCommandLineArgs(); SingleInstanceController controller = new SingleInstanceController(); controller.Run(args); } } public class SingleInstanceController : WindowsFormsApplicationBase { public SingleInstanceController() { IsSingleInstance = true; StartupNextInstance += this_StartupNextInstance; } void this_StartupNextInstance(object sender, StartupNextInstanceEventArgs e) { Form1 form = MainForm as Form1; //My derived form type form.LoadFile(e.CommandLine[1]); } protected override void OnCreateMainForm() { MainForm = new Form1(); } }}
The Form is trivial, just loading the text from the file into a TextBox.
using System;using System.Windows.Forms;using System.IO;namespace SuperSingleInstance{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); string[] args = Environment.GetCommandLineArgs(); LoadFile(args[1]); } public void LoadFile(string file) { textBox1.Text = File.ReadAllText(file); } }}
There's other nice functionality in WindowsFormsApplicationBase like support for SplashScreens and network availability events. Again, check out the good stuff over at http://www.openwinforms.com/, like the Controller I used in this post.
Remember Me
a@href@title, b, blockquote@cite, em, i, pre, strike, strong, sub, super, u
Ads by The Lounge