Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Tagged as

Enforcing Single Instance WPF Applications

, 1 Aug 2010 LGPL3
Rate this:
Please Sign up or sign in to vote.
IntroductionToday the WPF Disciples, and in particular my good friend and fellow WPF Disciple, Pete O'Hanlon, were sitting around the proverbial campfire, discussing how to enforce single instance WPF apps, for Pete's cool Goldlight project. By single instance WPF apps, I mean limiting an executabl

Introduction

Today the WPF Disciples, and in particular my good friend and fellow WPF Disciple, Pete O'Hanlon, were sitting around the proverbial campfire, discussing how to enforce single instance WPF apps, for Pete's cool Goldlight project. By single instance WPF apps, I mean limiting an executable to only one instance in execution. This can be useful in scenarios where multiple application instances may play havoc with shared state. I took some time away from writing my book, to see if I could come up with something usable.

Building a Single Instance Application Enforcer

The singleton application model works like this:

  1. User starts app1.
  2. User starts app2.
  3. App2 detects app1 is running.
  4. App2 quits.

 

There is, however, a second part to our challenge, as Pete pointed out. What happens if we wish to pass some information from app2 to app1 before app2 quits? If, for example, the application is associated with a particular file type, and the user happens to double click on a file of that type, then we would have app2 tell app1 what file the user was trying to open.

To accomplish this we need a means to communicate between the two application instances. There are a number of approaches that could be taken, and some include:

  • Named pipes
  • Sending a message to the main application's window with a native API call
  • MemoryMappedFile

I chose to go for the MemoryMappedFile, along with an EventWaitHandle. The consensus by the Disciples was for a Mutex (not an EventWaitHandle), but the Mutex turned out not to provide for the initial signaling that I needed. I have encapsulated the logic for the singleton application enforcement, into a class called SingletonApplicationEnforcer (see Listing 1). The class instantiates the EventWaitHandle, and informs the garbage collector via the GC.KeepAlive method, that it should not be garbage collected. If this is the only application that has instantiated the EventWaitHandle with the specified name, then the createdNew argument will be set to true. This is how we determine, if the application is the singleton application.

Listing 1: SingletonApplicationEnforcer Class

<span class="rem">/// <summary></span>
<span class="rem">/// This class allows restricting the number of executables in execution, to one.</span>
<span class="rem">/// </summary></span>
<span class="kwrd">public</span> <span class="kwrd">sealed</span> <span class="kwrd">class</span> SingletonApplicationEnforcer
{
    <span class="kwrd">readonly</span> Action<IEnumerable<<span class="kwrd">string</span>>

If the process happens to be the singleton application, then a new thread is started that will block until it receives a signal (via the argsWaitHandle). This signal indicates that the MemoryMappedFile contains data to be read. It is non-singleton applications instances that perform this signalling, via the argsWaitHandle.Set method, after the string arguments have been written to the MemoryMappedFile.

Demonstrating the SingletonApplicationEnforcer Class

The downloadable code includes two solutions, and two projects. Each use the SingletonApplicationEnforcer class in their respective App (App.xaml.cs) classes. To try out the sample, open both solutions. Start debuging the SingleApp project first, and then launch the SingleApp2 project. What will hopefully result is that the SingleApp2 project will detect that it is not the singleton application, and it will write its command line arguments to a MemoryMappedFile. The SingleApp application will detect that data has been written to the file, and present the command line arguments in its main window (see Figure 1).

Figure 1: The demo application consists of a single window, which displays received command line arguments.

 

The entry point for either projects is the App class. It is in this class that we consume the SingletonApplicationEnforcer class, to detect whether the application should be allowed to execute (see Listing 2). The App classes constructor uses the SingletonApplicationEnforcer's ShouldApplicationExit method; which, as we saw in Listing 1, uses an EventWaitHandle to determine if it is the only instance in execution. If it isn't then the method returns true, and the application is explicitly shutdown.

Listing 2: App Class

<span class="rem">/// <summary></span>
<span class="rem">/// Interaction logic for App.xaml</span>
<span class="rem">/// </summary></span>
<span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> App : Application
{
    <span class="kwrd">readonly</span> SingletonApplicationEnforcer enforcer = <span class="kwrd">new</span> SingletonApplicationEnforcer(DisplayArgs);

    <span class="kwrd">public</span> App()
    {
        <span class="kwrd">if</span> (enforcer.ShouldApplicationExit())
        {
            <span class="kwrd">this</span>.Shutdown();
        }
    }

    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> DisplayArgs(IEnumerable<<span class="kwrd">string</span>>

As usual, this application uses the MVVM pattern. The MainWindow has its DataContext property set to an instance of the MainWindowViewModel (see Listing 3).

Listing 3: MainWindow XAML

<span class="kwrd"><</span><span class="html">Window</span> <span class="attr">x:Class</span><span class="kwrd">="SingleApp.MainWindow"</span>
        <span class="attr">xmlns</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
        <span class="attr">xmlns:x</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml"</span>
        <span class="attr">Title</span><span class="kwrd">="Singleton Application Enforcer Example"</span> 
        <span class="attr">Height</span><span class="kwrd">="350"</span> <span class="attr">Width</span><span class="kwrd">="525"</span> <span class="attr">ResizeMode</span><span class="kwrd">="NoResize"</span> <span class="attr">Background</span><span class="kwrd">="Black"</span><span class="kwrd">></span>
    <span class="kwrd"><</span><span class="html">StackPanel</span><span class="kwrd">></span>
        <span class="kwrd"><</span><span class="html">Image</span> <span class="attr">Source</span><span class="kwrd">="Images/DisciplesBackground.jpg"</span> <span class="kwrd">/></span>
        <span class="kwrd"><</span><span class="html">StackPanel</span> <span class="attr">Margin</span><span class="kwrd">="10"</span><span class="kwrd">></span>
            <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">="Received Args:"</span> <span class="attr">FontSize</span><span class="kwrd">="16"</span> <span class="attr">Padding</span><span class="kwrd">="10"</span> <span class="attr">Foreground</span><span class="kwrd">="White"</span><span class="kwrd">/></span>
            <span class="kwrd"><</span><span class="html">ListBox</span> <span class="attr">ItemsSource</span><span class="kwrd">="{Binding Args}"</span> 
                     <span class="attr">VerticalAlignment</span><span class="kwrd">="Stretch"</span> <span class="attr">Height</span><span class="kwrd">="185"</span> <span class="kwrd">/></span>
        <span class="kwrd"></</span><span class="html">StackPanel</span><span class="kwrd">></span>
    <span class="kwrd"></</span><span class="html">StackPanel</span><span class="kwrd">></span>
<span class="kwrd"></</span><span class="html">Window</span><span class="kwrd">></span>

The viewmodel (MainWindowViewModel), shown in Listing 2, exposes an ObsertableCollection of strings, that reflect arguments that are passed to the application, from other application instances.

Listing 4: MainWindowViewModel

<span class="kwrd">public</span> <span class="kwrd">class</span> MainWindowViewModel : INotifyPropertyChanged
{
    <span class="kwrd">static</span> ObservableCollection<<span class="kwrd">string</span>>


Conclusion

In this post we have seen how a MemoryMappedFile can be used in conjunction with a EventWaitHandle, to provide for cross process communication in order to limit execution to a single application instance. We also saw how to communicate command line arguments to the singleton application, so that it can respond adequately to user intent.

I hope you enjoyed this post, and that you find the code and ideas presented here useful.

Download code: SingletonEnforcement.zip (337.49 kb)

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

Share

About the Author

Daniel Vaughan
President Outcoder
Switzerland Switzerland
Daniel Vaughan is a Microsoft MVP and co-founder of Outcoder, a Swiss software and consulting company dedicated to creating best-of-breed user experiences and leading-edge back-end solutions, using the Microsoft stack of technologies--in particular WPF, WinRT, Windows Phone, and also Xamarin.Forms.
 
Daniel is the author of Windows Phone 8 Unleashed and Windows Phone 7.5 Unleashed, both published by SAMS.
 
Daniel is the developer behind several acclaimed Windows Phone apps including Surfy, Intellicam, and Splashbox; and is the creator of a number of popular open-source projects including Calcium SDK, and Clog.
 
Would you like Daniel to bring value to your organisation? Please contact

Daniel's Blog | MVP profile | Follow on Twitter
 
Windows Phone Experts
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
GeneralDoesn't Work for .Net Framework 3.5 - VS2008 PinmemberRoger Templeton6-Aug-10 8:50 
GeneralRe: Doesn't Work for .Net Framework 3.5 - VS2008 PinmvpDaniel Vaughan6-Aug-10 12:23 
GeneralMy vote of 5 Pinmembersam.hill3-Aug-10 19:11 
GeneralRe: My vote of 5 PinmvpDaniel Vaughan4-Aug-10 3:58 
GeneralRe: My vote of 5 Pinmembersam.hill4-Aug-10 8:52 
GeneralRe: My vote of 5 PinmvpDaniel Vaughan4-Aug-10 9:33 
GeneralRe: My vote of 5 Pinmembersam.hill4-Aug-10 19:11 
GeneralMy vote of 5 Pinmemberlinuxjr1-Aug-10 13:49 
Thank you for sharing your work.
GeneralRe: My vote of 5 PinmvpDaniel Vaughan2-Aug-10 1:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 1 Aug 2010
Article Copyright 2010 by Daniel Vaughan
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid