Single instance WPF application using Caliburn.Micro
Asked Answered
A

3

5

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

Anna answered 19/11, 2013 at 20:55 Comment(2)
On the program startup, you can simply check to see if another process with the same image name is running. If so, just exit the application.Scour
@PoweredByOrange thanks, but thats not a very robust approach. I'm currently using a mutex. The question was how to plug that behaviour in calibur.microAnna
H
5

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

Hearttoheart answered 19/11, 2013 at 21:2 Comment(6)
thanks, but I'm already using mutexes. My qyestion is how to plug that behaviour into caliburn.micro since it uses a bootstrapper to load the application.Anna
Do it before you call the bootstrapper. See main method above. Process level behavior does not require the framework.Hearttoheart
But isn't doing application initialization logic the point of having a bootstrapper?Anna
@Anna Caliburn.Micro exposes OnStartup method that you can override in the bootstrapper.Tillo
@PatrykĆwiek so is the onstartup the best place for this kind of stuff? I cannot find any examples of single instance apps using caliburnAnna
@Anna Try it and see, if it works, it works! The goal on single instance is to prevent competition for shared resources and related side effects. As long as you can make the app close before anything inits, bingo!Hearttoheart
B
3

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.

Bison answered 20/5, 2020 at 18:16 Comment(0)
V
0

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();
        }
    }
Vidavidal answered 10/4, 2020 at 20:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.