HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMajor

Single-instance WPF application

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
instancewpfsingleapplication

Problem

This is the code I implemented so far to create a single instance WPF application:

```
#region Using Directives
using System;
using System.Globalization;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Interop;
#endregion

namespace MyWPF
{
public partial class MainApplication : Application, IDisposable
{
#region Members
private Int32 m_Message;
private Mutex m_Mutex;
#endregion

#region Methods: Functions
private IntPtr HandleMessages(IntPtr handle, Int32 message, IntPtr wParameter, IntPtr lParameter, ref Boolean handled)
{
if (message == m_Message)
{
if (MainWindow.WindowState == WindowState.Minimized)
MainWindow.WindowState = WindowState.Normal;

Boolean topmost = MainWindow.Topmost;

MainWindow.Topmost = true;
MainWindow.Topmost = topmost;
}

return IntPtr.Zero;
}

private void Dispose(Boolean disposing)
{
if (disposing && (m_Mutex != null))
{
m_Mutex.ReleaseMutex();
m_Mutex.Close();
m_Mutex = null;
}
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion

#region Methods: Overrides
protected override void OnStartup(StartupEventArgs e)
{
Assembly assembly = Assembly.GetExecutingAssembly();
Boolean mutexCreated;
String mutexName = String.Format(CultureInfo.InvariantCulture, "Local\\{{{0}}}{{{1}}}", assembly.GetType().GUID, assembly.GetName().Name);

m_Mutex = new Mutex(true, mutexName, out mutexCreated);
m_Message = NativeMethods.RegisterWindowMessage(mutexName);

if (!mutexCreated)
{
m_Mutex = null;

Solution

This might be against the spirit of Code Review, but you don't need to write your own single instance manager for WPF! Microsoft has already written code to accomplish this, but it has been poorly advertised.

Microsoft's single instance manager is extremely comprehensive, and I have yet to find any issues with it. (And if you don't want to use it, it can at least be a good reference for your own implementation.)

How to manage single instances in WPF

Step 1: Add the System.Runtime.Remoting reference to your project.

Step 2: Add this single instance class to your project.

Step 3: Implement the ISingleInstanceApp interface in your main application class in App.xaml.cs (this interface is provided by the SingleInstance.cs file).

For example:

public partial class App : Application, ISingleInstanceApp

Step 4: Change your startup object by going to Project --> Properties in Visual Studio, clicking the Application tab. Locate Startup object: and select the .App option.

Step 5: Define a Main method in App.xaml.cs, and give it a unique string in the Unique variable.

// TODO: Make this unique!
private const string Unique = "Change this to something that uniquely identifies your program.";

[STAThread]
public static void Main()
{   
    if (SingleInstance.InitializeAsFirstInstance(Unique))
    {
        var application = new App();
        application.InitializeComponent();
        application.Run();

        // Allow single instance code to perform cleanup operations
        SingleInstance.Cleanup();
    }
}

#region ISingleInstanceApp Members
public bool SignalExternalCommandLineArgs(IList args)
{
    // Handle command line arguments of second instance
    return true;
}
#endregion


Step 6: Right-click on App.xaml in the Solution Explorer, select Properties, and change the Build Action to Page.

Single Instance techniques

Do nothing when new instance is opened

If you don't want anything to happen when a single instance is launched, you don't need to modify the sample code above.

Activate original window when new instance is opened

Rather than doing nothing when a user attempts to open a second instance of the program, it's often beneficial to Activate the original window and change its window state to WindowState.Normal, which can provide an improved user experience if the original window was minimized.

To activate and make the window visible, modify the SignalExternalCommandLineArgs method as shown . (Note that MainWindow is a property of the App class, not to be confused with an arbitrarily-named MainWindow.xaml.cs class.)

public bool SignalExternalCommandLineArgs(IList args)
{
    // Bring window to foreground
    if (this.MainWindow.WindowState == WindowState.Minimized)
    {
        this.MainWindow.WindowState = WindowState.Normal;
    }

    this.MainWindow.Activate();

    return true;
}

Code Snippets

// TODO: Make this unique!
private const string Unique = "Change this to something that uniquely identifies your program.";

[STAThread]
public static void Main()
{   
    if (SingleInstance<App>.InitializeAsFirstInstance(Unique))
    {
        var application = new App();
        application.InitializeComponent();
        application.Run();

        // Allow single instance code to perform cleanup operations
        SingleInstance<App>.Cleanup();
    }
}

#region ISingleInstanceApp Members
public bool SignalExternalCommandLineArgs(IList<string> args)
{
    // Handle command line arguments of second instance
    return true;
}
#endregion
public bool SignalExternalCommandLineArgs(IList<string> args)
{
    // Bring window to foreground
    if (this.MainWindow.WindowState == WindowState.Minimized)
    {
        this.MainWindow.WindowState = WindowState.Normal;
    }

    this.MainWindow.Activate();

    return true;
}

Context

StackExchange Code Review Q#20871, answer score: 33

Revisions (0)

No revisions yet.