6

I'm trying to make a single instance WPF application using the hints on:

What is the correct way to create a single-instance application?

This ultimately requires changes to Main(). In WPF, Main() seems to be auto-generated. I'd rather not modify autogenerated code. Is there a way to suppress Main from being auto-generated?

(alternatively, if you know of a better single app instance pattern for WPF that doesn't rely on modifying auto-generated code, please suggest it)

Community
  • 1
  • 1
jglouie
  • 12,523
  • 6
  • 48
  • 65

4 Answers4

12

From the blog: http://bengribaudo.com/blog/2010/08/26/136/wpf-where-is-your-static-main-method

The following two methods will avoid the duplicate Main collision:

  1. Tell the compiler that your static Main() method should be the execution entry point—Set your project’s “Startup object” setting to the class containing your static Main() method (right-click on the project in Solution Explorer, choose “Properties,” then look for the “Startup object” setting under the “Application” tab). (This was also mentioned by Bahri Gungor)

  2. Turn off auto-generation of App.g.cs’s static Main() method—In Solution Explorer, right click on App.xaml, choose “Properties,” then change the “Build Action” from “ApplicationDefinition” to “Page”.

jglouie
  • 12,523
  • 6
  • 48
  • 65
  • I tried setting the "Build Action" of App.xaml to "Page", but an error popped up saying "The property value is not valid" with hidden "Details" saying "An error has occurred while saving the edited properties listed below: Build Action One or more values are invalid. Cannot add 'App.xaml' to the project, because the path is explicitly excluded from the project (C:\Program Files\dotnet\sdk\7.0.102\Sdks\Microsoft.NET.Sdk.WindowsDesktop\targets\Microsoft.NET.Sdk.WindowsDesktop.targets (88,5)). – Mike Nakis Jan 28 '23 at 19:31
  • Furthermore, as a result of the above action, Visual Studio 2022 injected the following sabotage into my project file: ` ` So now my App.xml is inaccessible from the solution explorer. (App.xaml.cs shows in its place.) – Mike Nakis Jan 28 '23 at 19:32
  • Needless to say, various other things are broken, so I have to revert. Any other ideas? – Mike Nakis Jan 28 '23 at 19:34
  • 1
    I haven’t used WPF in over a decade so unfortunately won’t have any ideas beyond what’s here. If you are able to unblock yourself please add a modern answer! – jglouie Jan 29 '23 at 02:01
4

Actually, in a default WPF project, the application startup object is the App class (code-behind for app.xaml).

You can write your own class, create the startup code however you like, and start your application like this:

public class Startup
{
    [STAThread]
    public static void Main(string[] args)
    {
        // Check for existing instance (mutex or w/e) here

        //
        App app = new App();
        app.Run();
    }
}

You can change the startup object in your project file.

Bahri Gungor
  • 2,289
  • 15
  • 16
  • Where in the project file is this? – jglouie Feb 29 '12 at 19:07
  • Found it... it's set to (not set) which I guess defaults to App class? – jglouie Feb 29 '12 at 19:09
  • On the Application Tab (C#), Startup Object. – Bahri Gungor Feb 29 '12 at 19:09
  • Yes, the default for a WPF project is the App class. – Bahri Gungor Feb 29 '12 at 19:10
  • @LemonBeagle Using OnStartup event handler in the App class means the WPF application startup code is already running. Many of these answers have you put the code in that event handler and then kill the application, rather than making the check before the App is instantiated, as I suggest. I prefer the cleaner structured approach. – Bahri Gungor Feb 29 '12 at 19:18
  • +1 for this approach @BahriGungor. I found a blog with that and another method of preventing the Main collision. – jglouie Feb 29 '12 at 19:25
1

I wouldn't use the mutex approach for creating a single instance WPF app. I would use the answer described here - https://stackoverflow.com/a/19326/248164.

This is also the approach described in Pro WPF in C# 2010.

Community
  • 1
  • 1
devdigital
  • 34,151
  • 9
  • 98
  • 120
  • Yikes- this relies on the VB assembly?? – jglouie Feb 29 '12 at 19:18
  • Yes, not a huge issue, just one extra dependency to deploy with your app. – devdigital Feb 29 '12 at 19:19
  • Don't be confused by the `Microsoft.VisualBasic`. That isn't part of the VB runtime, but is rather a part of the .net runtime. See http://stackoverflow.com/questions/226517/is-the-microsoft-visualbasic-namespace-true-net-code – N_A Feb 29 '12 at 19:24
  • I'll spend more time explaining its inclusion during code reviews than it's worth in benefits. I do appreciate the alternate suggestion though – jglouie Feb 29 '12 at 19:27
0

I don't knowif it is your question, but I create the mutex in OnStartup. I dont touch the Main().

protected override void OnStartup(StartupEventArgs e) {            
        base.OnStartup(e);            
        m_singleInstanceMutex = new Mutex(false, SINGLE_INSTANCE_MUTEX_ID);
        ...

Important is, that you delete your StartupUri in the XAML-Declarion of your App.xaml. This prevents the runtime to automatically open the specified resource.

HCL
  • 36,053
  • 27
  • 163
  • 213
  • This is an interesting approach. Do you need to check if you can acquire the mutex prior to calling the base.OnStartup(e)? – jglouie Feb 29 '12 at 19:04