WPF Single Instance Application

28 במאי 2010

תגיות: , , , ,
26 תגובות

The Problem


The question this post solves is how to enforce that your WPF application has only one instance?


Solution Source


The solution is based on code found in some WPF reference applications which Microsoft will soon (?) release. I didn’t wrote it, but I used it several times and it’s the best solution I’ve found to date, so I'd hate to see it unpublished.


Solution Advantages


So, what are the advantages of this solution? after all, it’s not the first time someone posts a solution for this problem.


Well, the most important advantage is that it works.
No glitches. No special cases. No inherent race conditions.
It simply works.


Second, it’s easily used. On the next section I’ll show you exactly how to use it.


Third, there’s no constraints on your WPF application. Specifically, your main application / window class doesn’t have to inherit some base class for this to work.


And at last, you don’t need to be dependent on any VB DLL.
I say this because one of the popular solutions for this problem requires your to add a reference to a (WinForms related!) Visual Basic DLL, which may feel strange for some people.


As a bonus, the solution provides to the first instance the parameters of the second instance when run. This is very useful if you want to integrate you application with the Windows 7 taskbar.


Solution Details


So, let’s see how to make your WPF application having just one instance.


Step 1: Add the file SingleInstance.cs to your project.


Step 2: Add a reference to your project: System.Runtime.Remoting


Step 3: Have your application class implement ISingleInstanceApp (defined in SingleInstance.cs).


The only method in this interface is:
bool SignalExternalCommandLineArgs(IList<string> args)


This method is called when a second instance of your application tries to run. It has an args parameter which is the same as the command line arguments passed to the second instance.


Step 4: Define your own Main function that uses the single instance class.


Your App class should now be similar to this:




/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application, ISingleInstanceApp
{
    private const string Unique = "My_Unique_Application_String";

    [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
}

Step 5: Set new main entry point


Select Project Properties –> Application and set “Startup object” to your App class name instead of “(Not Set)”.


Step 6: Cancel the default WPF main function


Right-click on App.xaml, Properties, set Build Action to "Page" instead of "Application Definition".


Solution Inner Works


I can summarize it as: Mutex and Remoting, done right.
If you want to know more details, just have a look at the code.


You can find a WPF sample application here.


That’s it for now,
Arik Poznanski.

kick it on DotNetKicks.com Shout it

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים

26 תגובות

  1. Olivier DALET28 במאי 2010 ב 13:26

    Hi, this is useful a post!
    I had already implemented the same functionality for winform apps (and got rid of the VB references by reflectoring My namespace generated code…)

    I wonder if your solution could be tweaked not to be WPF specific; what could prevent it from working with winforms (or even console apps)? I know I could try by myself extracting the WPF-specific parts in a sub-class, but maybe you already have the answer?

    להגיב
  2. arik28 במאי 2010 ב 15:53

    From looking at the code, you can see that it does uses some properties of the WPF Application class.

    This could be replaced with analog WinForms properties, but then it won't be the same class anymore.

    להגיב
  3. Huseyin Tufekcilerli28 במאי 2010 ב 22:55

    Nice!

    I have skimmed through the code quickly and noticed some Remoting stuff, is that really necessary? I have implemented a similar technique in one of my recent WPF apps and used the following sample which only uses a named Mutex and Win32 message broadcasting:

    http://sanity-free.org/143/csharp_dotnet_single_instance_application.html

    Is there any advantage of your implementation other then command line arg passing stuff?

    להגיב
  4. Jim S29 במאי 2010 ב 2:04

    I'm having a problem when running TestSingleInstance in VS 2010. I find that your main() is never called unless I rename it to Main() and comment out the Main() method in app.g.cs. Once I do that your code runs as advertised – single instance. The problem is whenever you choose "Clean" in VS and rebuild, the Main() method is recreated in app.g.cs and you get a duplicate "Main" method build error.

    Other than that VS 2010 nusance, the code is nice and solves my problem.

    Could you also give me your opinion on how best to call a method in the main window from the SignalExternalCommandLineArgs. The below code works but looking for second opinion.

    public bool SignalExternalCommandLineArgs(IList args)
    {
    ((Window1)MainWindow).ShowLabel("Some String to display in Window1 when another instance attempts to run");
    return true;
    }

    להגיב
  5. Jim S29 במאי 2010 ב 2:47

    The duplicate Main() method issue I ran into can be avoided by setting the Build Action of App to "Page". See http://learnwpf.com/Posts/Post.aspx?postId=a5643949-ab80-47f9-93c8-f5e8e5782d34

    להגיב
  6. Jim S29 במאי 2010 ב 2:48

    Duh – I just noticed your Step 6 "Right-click on App.xaml, Properties, set Build Action to "Page" instead of "Application Definition". sorry to waste your time.
    Thanks again,
    Jim

    להגיב
  7. arik29 במאי 2010 ב 10:28

    Jim, you are correct.
    I noticed it myself a few hours after posting the original post, and then I've update it and the attached sample.

    That what I get for posting late at night..
    Sorry about that.

    The post version is now correct and works.

    להגיב
  8. Diego Rabelo de França2 ביוני 2010 ב 2:44

    (Sorry arik, your contact session isn't working).

    So, i need your help.

    How may i making to validate process integrity in memory ?

    I was seeing yours good threads about "minersweeper, behind the scenes" and "freecell & hearts, behind the scenes". Well, i was thinking, if it's possible to validate process integrity in memory. In other words, I would preventing that other program can change my process, or identify if a process is trying to change my process.

    Any help is welcome ( =D ).

    My project is making a anti-hack(or anti-cheater) program in C# for a game because many players are using "cheater engine" ( http://www.cheatengine.org/ ). In resume: This program (cheater engine) scans memory, obtains the addresses and the user can change memory value of game putting a speedhack, bullethack and other type of hack.

    OBS: I wait that you understand what did i wrote =). Sorry, my english is not good.

    Graciously,

    Diego Rabelo de França
    graduated in Computer Science – UNIT – Brazil
    diegorf0@gmail.com

    להגיב
  9. arik4 ביוני 2010 ב 1:14

    Well, I can't think of a way to prevent the memory change itself.
    What I would suggest is having some sort of CRC check.
    This is a special variable that is dependent on the other variables you want to protect.
    Suppose you have two variables:
    Speed = 50
    Score = 30
    Then define a new variable:
    CRC = Speed XOR Score (the XOR is just an example, any function between the variables will do)
    Now every time you change the speed or score, change also CRC.

    The important part is to add validation checks thruout the code, to make sure the speed and score checks out, by computing the function again (Speed XOR Score) and comparing to the CRC variable.

    This way, if someone only changes the speed without updating the CRC, the change will get detected, since the CRC will have a different value.

    Of course, they can always disassemble your code to find what the CRC function is, and update the CRC variable. But it does make their life a lot harder.

    Hope this helps,
    Arik Poznanski.

    להגיב
  10. Ed18 באוגוסט 2010 ב 18:50

    Hi,

    I didn't manage to make your code work. I get a single instance all right but then my args are always empty.
    The cmdline.txt file never seems to be created (the file supposed to contain the args if I understand your code right) and I don't understand at which point it is even created.

    Do you have any code sample showing how to use params with your code by any chance?

    להגיב
  11. Leo29 בספטמבר 2010 ב 22:07

    Arik,
    Thanks for sharing the code. What is the license under which this code is shared? The file header states that it’s copyright of Microsoft.
    Thanks,
    Leo

    להגיב
  12. Leo29 בספטמבר 2010 ב 22:44

    Arik,
    Thank you for sharing the code. What license is the code is released under?
    It has Microsoft copyright in the SingleInstance.cs file so it’s not clear how I can use it in my application that is being created for a customer.
    Thanks,
    Leo

    להגיב
  13. Tim1 באוקטובר 2010 ב 3:51

    Arik – would your recommendation cause any issues with using the SplashScreen BuildAction option for an image resource? The splash screen stopped being displayed somewhere along the way a few weeks ago and now that I'm trying to figure it out I noticed that my App.g.cs file looks different than the examples I see. My guess is that it could be due to changing the build action of the App.xaml to "Page"…but I'm not entirely sure).

    Here's my scenario/problem: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/33894287-101a-4c9f-8c6a-f0452ab4ced0

    Thanks.

    להגיב
  14. arik11 באוקטובר 2010 ב 17:23

    Leo, the code is under MS-PL, so you can use it freely.

    להגיב
  15. Robert Ellison13 באפריל 2011 ב 21:50

    Setting App.xaml to Page will break resource loading in the Visual Studio designer. See http://ithoughthecamewithyou.com/post/Merging-Resource-Dictionaries-for-fun-and-profit.aspx for how to fix this.

    להגיב
  16. Michael3 ביולי 2011 ב 13:24

    Great stuff! It's the perfect solution for WPF tray applications, when the window of the first instance is hidden. Thanks a lot for sharing. I really appreciate it!

    להגיב
  17. Zahid19 בספטמבר 2011 ב 4:43

    This is great, never thought it would be this easy. Awesome tute, mind if i make a YouTube tutorial from it?

    להגיב
  18. Vladimir30 בספטמבר 2011 ב 12:52

    This solution doesn't work if an app has a background thread and the thread ends after app has been closed. So at that moment this solutions allows to run second instance of app.

    להגיב
  19. Neomon9 בפברואר 2012 ב 16:02

    Awesome post. As you mentioned, it just works!

    להגיב
  20. OmegaSupreme5 במרץ 2012 ב 16:56

    This crashes when the app is opened via a file association i.e. a file set to "open with" my WPF app. But it's also impossible to debug.

    So any ideas ?

    Cheers.

    להגיב
  21. Michael11 במרץ 2012 ב 4:15

    Any chance of a VB version of this code? Not all of us are C# wizards, but we all need a way to allow only one instance to run. Will this code convert easily if put through a C# to vb website converter?

    להגיב
  22. Nathan Risto22 במרץ 2012 ב 17:08

    We've implemented this solution in our code, but are running into an issue. For the most part everything works, except on scenario. If our application is not running and we navigate using Windows Explorer to a set of files that will trigger our application to start and choose multiple files to open at once, we never get more than just a single file to open at startup. After the application is running, we can choose open on as many files as needed and our app will handle and load them just fine, just not on startup.

    It's almost like instead of sending all the files on a single command line as arguments, it's sending multiple commands with each file as a single argument, and at startup it seems to only get one of those commands and ignores the others. Do you have any advice on how to handle this?

    להגיב
  23. Jeremy White7 ביולי 2012 ב 15:43

    You shouldn't change the build settings from ApplicationDefinition to Page as that will not allow the IDE and other design time things from accessing any static resources in the App resources.

    You should leave that alone and instead remove the startup URI from the main window XAML. This will prevent the main window from being created at startup.

    Application_Startup will still be called (or whatever is in the application xaml points to) : mine is Startup="Application_Startup".

    Then, add the function Application_Startup() like so :

    private void Application_Startup(object sender, StartupEventArgs e)
    {
    // Open a window
    if (SingleInstance.InitializeAsFirstInstance(Unique))
    {
    var window = new WhateverMyFirstWindowIs();
    window.Show();
    }
    }

    להגיב
  24. Jeremy White7 ביולי 2012 ב 15:48

    Correction/Addition :

    In order to stop the application thread running in the background, you might want to also implement it like this :

    // Open a window
    if (SingleInstance.InitializeAsFirstInstance(Unique))
    {
    var window = new Views.MainView();
    window.Show();
    }
    else
    {
    // This is the second instance of the program.
    // Shut down the main application thread started in Main()
    Current.Shutdown();
    }

    להגיב
  25. Pingback: Creating a Single Instance WPF Application – Justin Horner