Question

I've seen all the other questions regarding creating a single instance app using WPF and I've chosen to use the Microsoft's approach as described here: https://codereview.stackexchange.com/a/25667

This is working fine, but now I'd like to using Caliburn.Micro on this application and this code does not play well with caliburn.

How can I have a single instance wpf application using caliburn micro?

The requirement are quite simple: .net 4.5 and only one instance of the application per user session

Thanks

Was it helpful?

Solution

I use a named mutex in my main method and show a dialog if the mutex already exists.

Check this stack - WPF Single Instance Best Practices

OTHER TIPS

In case anyone is having the same issue, I want to clarify the steps.

First, you have to change what happens in program entry point. As others mentioned, the Main() function that acts as an entry point to WPF programs is auto-generated (App.g.i.cs); So we have to take control of it somehow. As mentioned in this answer, there are several ways to do so. Personally I prefer the Third Approach:

Include another class in your project that defines the Main method as below:

class Startup
{
    [STAThread]
    public static void Main()
    {
        // Your single instance control (shown in below code)
        ...
    }
}

Identify the class whose main you want the application to use as entry point. This can be done via the project properties (right-click on your project >properties. or alt+enter while your project is selected in Solution Explorer). In the Application tab, modify the Startup object properties from the drop down:

Second, you have to decide for a mechanism to know if your program is being run more than once. There are several ways to do that (as the other answers mentioned). The one I prefer is this:

        ...
        // Your single instance control:
        bool firstInstance = true;
        System.Threading.Mutex mutex = new System.Threading.Mutex(true, "some_unique_name_that_only_your_project_will_use", out firstInstance);
        if (firstInstance)
        {
            // Everything that needs to be done in main class, for example:
            YourProject.App app = new YourProject.App();
            app.InitializeComponent();
            app.Run();
        }
        else
        {
            // Your procedure for additional instances of program
            MessageBox.Show("Another instance of this application is already running.");
        }

These two steps together are one of the easiest ways to achieve your goal, even before Caliburn.Micro takes control of your program.

I had difficulty attempting this in the OnStartup() method. Basically, you want to create a Main method (see No Main() in WPF? ) and wrap the contents using the mutex (see What is a good pattern for using a Global Mutex in C#?)

Mine looked like this:

class SingleGlobalInstance : IDisposable

{



    public bool _hasHandle = false;

    Mutex _mutex;



    private void InitMutex()

    {

        string appGuid = "My App Name"; //((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value;

        string mutexId = string.Format("Global\\{{{0}}}", appGuid);

        _mutex = new Mutex(false, mutexId);



        var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);

        var securitySettings = new MutexSecurity();

        securitySettings.AddAccessRule(allowEveryoneRule);

        _mutex.SetAccessControl(securitySettings);

    }



    public SingleGlobalInstance(int timeOut)

    {

        InitMutex();

        try

        {

            if(timeOut < 0)

                _hasHandle = _mutex.WaitOne(Timeout.Infinite, false);

            else

                _hasHandle = _mutex.WaitOne(timeOut, false);



            if (_hasHandle == false)

            {

                MessageBox.Show("Another instance is already running");

                System.Windows.Application.Current.Shutdown();

            }

        }

        catch (AbandonedMutexException)

        {

            _hasHandle = true;

        }

    }





    public void Dispose()

    {

        if (_mutex != null)

        {

            if (_hasHandle)

                _mutex.ReleaseMutex();

            _mutex.Close();

        }

    }

}

And my App.xaml.cs contained:

    [STAThread]
    public static void Main()
    {
        using (new SingleGlobalInstance(1000))
        {
            var application = new App();
            application.InitializeComponent();
            application.Run();
        }
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top