Warm tip: This article is reproduced from serverfault.com, please click

how to change main window state in a single instance using .Net Core

发布于 2020-11-28 14:33:55

I am trying to leave my application with just one instance.

The code works fine, but I want to manipulate the window that is already open.

How can I bring the window already open to the front when I open more than one instance.

public partial class App : Application {

private static Mutex _mutex = null;

protected override void OnStartup(StartupEventArgs e)
{
    const string appName = "MyAppName";
    bool createdNew;

    _mutex = new Mutex(true, appName, out createdNew);

    if (!createdNew)
    {
        Application.Current.Shutdown();
    }

    base.OnStartup(e);
}          

}

in OnStartup I tried to call the window using MainWindow.WindowState = WindowState.Normal; but it fails in that call noting the error System.Windows.Application.MainWindow.get returned null.

Questioner
robert
Viewed
0
AmRo 2020-11-29 01:10:31

I created a sample project for single instance application in WPF. Maybe helpful:

Wpf Single Instance Application

You need the following native methods:

public static class NativeMethod
{
    public static IntPtr BroadcastHandle => (IntPtr)0xffff;
    public static int ReactivationMessage => RegisterWindowMessage("WM_SHOWME");

    [DllImport("user32")]
    public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
    [DllImport("user32")]
    public static extern int RegisterWindowMessage(string message);
}

In app main window add hook to window messages and when you got activation message you should bring the main window in top of other windows. Like this:

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        RegisterWndProcCallback();
    }

    private void RegisterWndProcCallback()
    {
        var handle = new WindowInteropHelper(this).EnsureHandle();
        var hock = new HwndSourceHook(WndProc);
        var source = HwndSource.FromHwnd(handle);

        source.AddHook(hock);
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == NativeMethod.ReactivationMessage)
            ReactivateMainWindow();

        return IntPtr.Zero;
    }

    private void ReactivateMainWindow()
    {
        if (WindowState == WindowState.Minimized)
            WindowState = WindowState.Normal;

        Topmost = !Topmost;
        Topmost = !Topmost;
    }
}

And in app startup you should check for app instances and if needed you should send a message to the old instance and activate that. Like this:

public partial class App
{
    private static readonly Mutex _singleInstanceMutex =
        new Mutex(true, "{40D7FB99-C91E-471C-9E34-5D4A455E35E1}");

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        if (_singleInstanceMutex.WaitOne(TimeSpan.Zero, true))
        {
            Current.MainWindow = new MainWindow();
            Current.MainWindow.Show();
            Current.MainWindow.Activate();

            _singleInstanceMutex.ReleaseMutex();
        }
        else
        {
            NativeMethod.PostMessage(
                NativeMethod.BroadcastHandle,
                NativeMethod.ReactivationMessage,
                IntPtr.Zero,
                IntPtr.Zero);

            Current.Shutdown();
        }
    }
}