WPF, how to make a single instance and shows the MainWindow when another instance is launched in c#

StackOverflow https://stackoverflow.com/questions/17772425

  •  03-06-2022
  •  | 
  •  

Question

As the title state, I want to make a single instance program and show MainWindow when another instance is launched. I have acheived showing message that only one instance is allowed.

public class MyApplication
{
static Mutex mutex = new Mutex(true, "FirstInstance");
    [STAThread]
    public static void Main(string[] args)
    {
        if (mutex.WaitOne(TimeSpan.Zero, true))
        {
            App app = new App();
            app.InitializeComponent();
            app.Run();
        }
        else
        {
            MessageBox.Show("only one instance at a time");
        }
    }
}

This works fine but I want to show MainWindow rather than a message, so I tried with

static Application app;//change app to static
if (mutex.WaitOne(TimeSpan.Zero, true))
        {
            app = new App();
            app.InitializeComponent();
            app.Run();
        }  
else
{
    app.MainWindow.WindowState = WindowState.Normal;
}

I get "System.NullReferenceException: Object reference not set to an instance of an object". It seems MainWindow in app(which is static) is null which I don't get why.

So I tried this article http://sanity-free.org/143/csharp_dotnet_single_instance_application.html But WndProc method doesn't exist in WPF.

I'd appreciate if you can help me. Thanks!

Was it helpful?

Solution

I created a sample WPF app and only changed the App.xaml.cs file. If the single-instance window is already open, this code will find any process that matches the name of the current process, and if that process has a window, shows it:

public partial class App : Application
{
    // signals to restore the window to its normal state
    private const int SW_SHOWNORMAL = 1;

    // create the mutex
    private const string MUTEXNAME = "FirstInstance";
    private readonly Mutex _mutex = new Mutex(true, MUTEXNAME);

    public App()
    {
        if (!_mutex.WaitOne(TimeSpan.Zero))
        {
            ShowExistingWindow();
            Shutdown();
        }
    }

    [DllImport("User32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);

    [DllImport("user32.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    // shows the window of the single-instance that is already open
    private void ShowExistingWindow()
    {
        var currentProcess = Process.GetCurrentProcess();
        var processes = Process.GetProcessesByName(currentProcess.ProcessName);
        foreach (var process in processes)
        {
            // the single-instance already open should have a MainWindowHandle
            if (process.MainWindowHandle != IntPtr.Zero)
            {
                // restores the window in case it was minimized
                ShowWindow(process.MainWindowHandle, SW_SHOWNORMAL);

                // brings the window to the foreground
                SetForegroundWindow(process.MainWindowHandle);

                return;
            }
        }
    }
}

FYI, this does not work in debug mode because .vshost becomes part of the process name. If you need it to work in debug mode, you need to iterate through all processes instead of calling Process.GetProcessesByName.

OTHER TIPS

If I havent misunderstood your question try something like this

[STAThread]
    public static void Main(string[] args)
    {
        Task task = new Task(() => { Thread.Sleep(200); MessageBox.Show("what a marvelous engineering"); });
        task.Start();
        //If you want application not to run untill task is complete then just use wait
        task.Wait();

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

But I am wondering if you want your C# work done before the your MainWindow instantiate why dont you just do your other wor just before App app=new App() and let the code run sequentially.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top