Skip to main content

...

....

C# WPF Tutorial - Writing a Single Instance Application [Intermediate]


Today we are going to be taking a look at how to build a single instance application in WPF. Not a single instance in this sense, but in the sense that you can only run one instance of the application at a time. Generally, you can run as many instances of an app at once (at least until you run out of resources). For instance, Notepad. You can run Notepad a dozen times, and you will get a dozen separate Notepad windows, and a dozen separate lines in "Task Manager" that read "notepad.exe". Killing one of those lines just kills one of those Notepad windows, and the rest live on happily.

On the other hand, you have an application like Firefox. At any given time, there should only be one line in Task Manager that reads "firefox.exe". This is because every time you hit the Firefox shortcut, or double click the executable, instead of running a new instance of the app, the running instance gets a message (which is how Firefox knows to open a new browser window).

So why would you as a developer write an app that behaved in this way? The most common reason has to do with resources - your application needs an exclusive lock on some resource. That resource could be anything from a hardware device to a file on disk. But if your app needs an exclusive lock, you better not let other instances run, because those other instances will fail.

Ok, so how do we do this in .NET (and, more specifically, WPF)? It actually isn't that bad (.NET fortunately has a useful built-in class that we get to use), but it does take some drastic changes to the default structure of a WPF application.

To get started, go and create a new WPF Visual Studio project. By default, it comes up with two main items in the solution - "Window1.xaml" (which I renamed to ExampleWindow.xaml") and "App.xaml". Both of these also have their respective code behind files. So first off, do something you have probably never done before - delete "App.xaml" and "App.xaml.cs". We won't be needing them, because we will be doing our own Application creation.

Now create a new class (I called it "ExampleApplcation"). This will be our application. The two main pieces of logic that this class needs to have are for showing the main window and for processing command line arguments. The first piece will only happen once - the initial application start up. The second, however, will happen every time a user tries to run the app (and we will see how that works in a moment). Take a look at the code:
using System.Windows;

namespace SingleInstanceExample
{
  public class ExampleApplication : Application
  {
    public ExampleWindow MyWindow { get; private set; }

    public ExampleApplication()
      : base()
    { }

    protected override void OnStartup(StartupEventArgs e)
    {
      base.OnStartup(e);

      MyWindow = new ExampleWindow();
      ProcessArgs(e.Args, true);

      MyWindow.Show();
    }

    public void ProcessArgs(string[] args, bool firstInstance)
    {
      //Process Command Line Arguments Here
    }
  }
}
 
OnStartup will only get called once - the very initial application startup. So it is here that we make a new window and show it. We also process the command line arguments, and add a flag saying that these are the arguments to the first instance. We will be calling ProcessArgs from somewhere else when the user tries to start other instances of the app.

Ok, so that code would get a window off the ground - but what calls that code? Well, for that, we need another class (and this class will actually hold the entry point for the application). The important thing for this class is that it has to derive from WindowsFormsApplicationBase. To get that class, you actually need to add a special reference to your Visual Studio project - "Microsoft.VisualBasic.dll". Don't ask me why this class is stuck in that dll - that is just where it happens to be.
using System;
using System.Linq;
using Microsoft.VisualBasic.ApplicationServices;

namespace SingleInstanceExample
{
  public sealed class SingleInstanceManager : WindowsFormsApplicationBase
  {
    [STAThread]
    public static void Main(string[] args)
    { (new SingleInstanceManager()).Run(args); }

    public SingleInstanceManager()
    { IsSingleInstance = true; }

    public ExampleApplication App { get; private set; }

    protected override bool OnStartup(StartupEventArgs e)
    {
      App = new ExampleApplication();
      App.Run();
      return false;
    }

    protected override void OnStartupNextInstance(
      StartupNextInstanceEventArgs eventArgs)
    {
      base.OnStartupNextInstance(eventArgs);
      App.MyWindow.Activate();
      App.ProcessArgs(eventArgs.CommandLine.ToArray(), false);
    }
  }
}
 
It is in this class that all the magic happens. Every time the application is run, it enters the Main method, creates a new instance of this class, and calls Run. If it is the first instance, this will cause OnStartup to get called, and everything goes from there. If it is a not the first, OnStartupNextInstance gets called on the already running instance, and the instance that was just started shuts down.

It really is as simple as that. The command line arguments for subsequent instances are even right there in the handy StartupNextInstanceEventArgs.

By default, this will only work for multiple instances of the exact same build of an application. If you need this to work across multiple builds, there is one more step you have to take. In the AssemblyInfo.cs file of your project (generally under the "Properties" folder") you have to add a GUID for your assembly. This GUID is what will be checked against when Windows sees if it is allowed to start another instance of the app. When there is no GUID explicitly set, Visual Studio generates a new one every time you build (which is why without this change, the single instance manager will only work for other instances of the exact same build). You will want your AssemblyInfo.cs to look something like this (of course, you want to use your own GUID):
using System.Reflection;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("SingleInstanceExample")]
[assembly: AssemblyProduct("SingleInstanceExample")]
[assembly: GuidAttribute("1A6236B4-8CD1-4c76-86FD-F5352330D190")]
 
That is it for writing a single instance application in .NET and WPF. The code for the example (and the associated Visual Studio solution) can be found in the zip file below. 


Source Files:

Comments

Popular posts from this blog

C# Snippet - Shuffling a Dictionary [Beginner]

Randomizing something can be a daunting task, especially with all the algorithms out there. However, sometimes you just need to shuffle things up, in a simple, yet effective manner. Today we are going to take a quick look at an easy and simple way to randomize a dictionary, which is most likely something that you may be using in a complex application. The tricky thing about ordering dictionaries is that...well they are not ordered to begin with. Typically they are a chaotic collection of key/value pairs. There is no first element or last element, just elements. This is why it is a little tricky to randomize them. Before we get started, we need to build a quick dictionary. For this tutorial, we will be doing an extremely simple string/int dictionary, but rest assured the steps we take can be used for any kind of dictionary you can come up with, no matter what object types you use. Dictionary < String , int > origin = new Dictionary < string , int >();

C# WPF Printing Part 2 - Pagination [Intermediate]

About two weeks ago, we had a tutorial here at SOTC on the basics of printing in WPF . It covered the standard stuff, like popping the print dialog, and what you needed to do to print visuals (both created in XAML and on the fly). But really, that's barely scratching the surface - any decent printing system in pretty much any application needs to be able to do a lot more than that. So today, we are going to take one more baby step forward into the world of printing - we are going to take a look at pagination. The main class that we will need to do pagination is the DocumentPaginator . I mentioned this class very briefly in the previous tutorial, but only in the context of the printing methods on PrintDialog , PrintVisual (which we focused on last time) and PrintDocument (which we will be focusing on today). This PrintDocument function takes a DocumentPaginator to print - and this is why we need to create one. Unfortunately, making a DocumentPaginator is not as easy as

C# WPF Tutorial - Implementing IScrollInfo [Advanced]

The ScrollViewer in WPF is pretty handy (and quite flexible) - especially when compared to what you had to work with in WinForms ( ScrollableControl ). 98% of the time, I can make the ScrollViewer do what I need it to for the given situation. Those other 2 percent, though, can get kind of hairy. Fortunately, WPF provides the IScrollInfo interface - which is what we will be talking about today. So what is IScrollInfo ? Well, it is a way to take over the logic behind scrolling, while still maintaining the look and feel of the standard ScrollViewer . Now, first off, why in the world would we want to do that? To answer that question, I'm going to take a an example from a tutorial that is over a year old now - Creating a Custom Panel Control . In that tutorial, we created our own custom WPF panel (that animated!). One of the issues with that panel though (and the WPF WrapPanel in general) is that you have to disable the horizontal scrollbar if you put the panel in a ScrollV