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!
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.