Run the Current Application as Single Instance and Show the Previous Instance

Run the current application as Single Instance and show the previous instance

I propose you a different method, using a combination of the System.Threading.Mutex class and UIAutomation AutomationElement class.

A Mutex can be, as you already know, a simple string. You can assign an application a Mutex in the form of a GUID, but it can be anything else.

Let's assume this is the current Application Mutex:

string ApplicationMutex = "BcFFcd23-3456-6543-Fc44abcd1234";
//Or
string ApplicationMutex = "Global\BcFFcd23-3456-6543-Fc44abcd1234";

Note:

Use the "Global\" Prefix to define the scope of the Mutex. If no prefix is specified, the "Local\" prefix is assumed and used instead. This will prevent a single instance of the process when multiple desktops are active or Terminal Services is running on the server.

If we want to verify whether another running Process has already registered the same Mutex, we try to register our Mutex and if it fails, another instance of our Application is already running.

We let the user know that the Application supports only a single instance, then switch to the running process, showing its interface and finally exit the duplicate Application, disposing of the Mutex.

The method to activate a previous instance of the Application may vary based on the type of the Application, but only some details change.

We can use Process..GetProcesses() to retrieve a list of the running processes and verify if one of them has the same details as ours.

Here, you have a windowed Application (it has an UI), so it's already possible to filter the list, excluding those processes that do not have a MainWindowHandle.

Process[] windowedProcesses = 
Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero).ToArray();

To identify the right one, we could test if the Process.ProcessName is the same.

But this name is tied to the executable name. If the file name changes (someone changes it for some reason), we will never identify the Process this way.

One possible way to identify the right Process is to test the Process.MainModule.FileVersionInfo.ProductName and check whether it's the same.

When found, it's possible to bring the original Application to front with an AutomationElement created using the MainWindowHandle of the identified Process.

The AutomationElement can automate different Patterns (sort of controls that provide automation functionalities for UI elements).

A WindowPattern allows to control a window-base control (the Platform is irrelevant, could be a WinForms' Form or a WPF's Window).

AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
WindowPattern wPattern = element.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern;
wPattern.SetWindowVisualState(WindowVisualState.Normal);

To use the UIAutomation functionalities, you have to add these refereneces in your Project:

- UIAutomationClient
- UIAutomationTypes

UPDATE:
Since the Application's Form might be hidden, Process.GetProcesses() will not find it's Window handle, thus AutomationElement.FromHandle() cannot be used to identify the Form Window.

A possible workaround, without dismissing the UIAutomation "pattern", is to register an Automation event, using Automation.AddAutomationEventHandler, which allows to receive a notification when an UI Automation events occurs, such as a new Window is about to be shown (a Program is run).

The event is registerd only if the Application needs to run as Single Instance. When the event is raised, the new Process AutomationElement Name (the Windows Title Text) is compared to the current and, if it's the same, the hidden Form will un-hide and show itself in Normal state.

As a fail-safe measure, we present an information MessageBox. The MessageBox caption has the same caption as the Application MainForm.

(Tested with a Form with its WindowsState set to Minimized and its Visible property set to false).


After the orginal Process has been brought to front, we just neeed to close the current thread and release the resources we created (mainly the Mutex, in this case).

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Windows.Automation;
using System.Windows.Forms;

static class Program
{
static Mutex mutex = null;

[STAThread]
static void Main()
{
Application.ThreadExit += ThreadOnExit;
string applicationMutex = @"Global\BcFFcd23-3456-6543-Fc44abcd1234";
mutex = new Mutex(true, applicationMutex);
bool singleInstance = mutex.WaitOne(0, false);
if (!singleInstance)
{
string appProductName = Process.GetCurrentProcess().MainModule.FileVersionInfo.ProductName;
Process[] windowedProcesses =
Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero).ToArray();

foreach (Process process in windowedProcesses.Where(p => p.MainModule.FileVersionInfo.ProductName == appProductName))
{
if (process.Id != Process.GetCurrentProcess().Id)
{
AutomationElement wElement = AutomationElement.FromHandle(process.MainWindowHandle);
if (wElement.Current.IsOffscreen)
{
WindowPattern wPattern = wElement.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern;
#if DEBUG
WindowInteractionState state = wPattern.Current.WindowInteractionState;
Debug.Assert(!(state == WindowInteractionState.NotResponding), "The application is not responding");
Debug.Assert(!(state == WindowInteractionState.BlockedByModalWindow), "Main Window blocked by a Modal Window");
#endif
wPattern.SetWindowVisualState(WindowVisualState.Normal);
break;
}
}
}
Thread.Sleep(200);
MessageBox.Show("Application already running", "MyApplicationName",
MessageBoxButtons.OK, MessageBoxIcon.Information,
MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
}

if (SingleInstance) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyAppMainForm());
}
else {
Application.ExitThread();
}
}
private static void ThreadOnExit(object s, EventArgs e)
{
mutex.Dispose();
Application.ThreadExit -= ThreadOnExit;
Application.Exit();
}
}

In the Application MainForm constructor:

(this is used in case the Application's Main Window is hidden when a new instance is run, hence the procedure in Program.cs cannot find its handle)

public partial class MyAppMainForm : Form
{
public MyAppMainForm()
{
InitializeComponent();
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
AutomationElement.RootElement,
TreeScope.Subtree, (uiElm, evt) =>
{
AutomationElement element = uiElm as AutomationElement;
string windowText = element.Current.Name;
if (element.Current.ProcessId != Process.GetCurrentProcess().Id && windowText == this.Text)
{
this.BeginInvoke(new MethodInvoker(() =>
{
this.WindowState = FormWindowState.Normal;
this.Show();
}));
}
});
}
}

Running only one instance of an application,(Quit new instance and Display old instance or give Focus)

I finally Got what I wanted from Here. My main problem was to bring the old instance from the Icon tray whilst closing the new

 static class Program
{
[STAThread]
static void Main()
{
if (!SingleInstance.Start()) {
SingleInstance.ShowFirstInstance();
return;
}

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

try {
MainForm mainForm = new MainForm();
Application.Run(mainForm);
} catch (Exception e) {
MessageBox.Show(e.Message);
}

SingleInstance.Stop();
}
}
//And secondly within your main form, the following code must be added:

protected override void WndProc(ref Message message)
{
if (message.Msg == SingleInstance.WM_SHOWFIRSTINSTANCE) {
Show

Window();
}
base.WndProc(ref message);
}

public void ShowWindow()
{
// Insert code here to make your form show itself.
WinApi.ShowToFront(this.Handle);
}

How to determine if a previous instance of my application is running?

Jeroen already answered this, but the best way by far is to use a Mutex... not by Process. Here's a fuller answer with code.

I've updated this answer after seeing some comments about a race condition to address that by instead using the Mutex Constructor

Boolean createdNew;
Mutex mutex;

try
{
mutex = new Mutex(false, "SINGLEINSTANCE" out createdNew);
if (createdNew == false)
{
Console.WriteLine("Error : Only 1 instance of this application can run at a time");
Application.Exit();
}

// Run your application
}
catch (Exception e)
{
// Unable to open the mutex for various reasons
}
finally
{
// If this instance created the mutex, ensure that
// it's cleaned up, otherwise we can't restart the
// application
if (mutex && createdNew)
{
mutex.ReleaseMutex();
mutex.Dispose();
}
}

Notice the try{} finally{} block. If you're application crashes or exits cleanly but you don't release the Mutex then you may not be able to restart it again later.

Enforce one instance of an application winform c#

You can use Mutex to ensure a single instance app.
Put the following code in the Main function of your WinForms app:

static class Program
{
static Mutex mutex = new Mutex(true, "<some_guid_or_unique_name>");

[STAThread]
static void Main()
{
if (mutex.WaitOne(TimeSpan.Zero, true))
{
// do the app code
Application.Run();

// release mutex after the form is closed.
mutex.ReleaseMutex();
mutex.Dispose();
}
}
}

maximizing the already running instance of a single instance app in qt

There is an easy setup using QtSingleApplication instead :

QtSingleApplication app("myapp",argc, argv);

if (app.isRunning()) {
QListIterator<QString> it(messagestosend);
QString rep("Another instance is running, so I will exit.");
bool sentok = false;
while(it.hasNext()){
sentok = app.sendMessage(it.next(),1000);
if(!sentok)
break;
}
rep += sentok ? " Message sent ok." : " Message sending failed; the other instance may be frozen.";
return 0;
}

To receive this message you should listen with your desired slot to the signal

void QtSingleApplication::messageReceived(const QString&)

WPF Single Instance Best Practices

1) It looks like a standard Dispose implementation to me. It is not really necessary (see point 6) but it does not do any harm. (Cleanup on closing it's a bit like cleaning the house before burning it down, IMHO, but opinions on the matter differs..)

Anyway, why not using "Dispose" as the name of the cleanup method, even if it does not get called directly? You could have called it "Cleanup", but remember you also write code for humans, and Dispose looks familiar and anyone on .NET understands what is it for. So, go for "Dispose".

2) I have always seen m_Mutex = new Mutex(false, mutexName); I think it's more a convention that a technical advantage, however.

3) From MSDN:

If the message is successfully registered, the return value is a message identifier in the range 0xC000 through 0xFFFF.

So I would not worry. Usually, for this class of functions, UInt is not used for "it does not fit in Int, let's use UInt so we have something more" but to clarify a contract "function never returns a negative value".

4) I would avoid calling it if you will shutdown, same reason as #1

5) There are a couple of ways of doing it. The easiest way in Win32 is simply to have the second instance make the call to SetForegroundWindow (Look here: http://blogs.msdn.com/b/oldnewthing/archive/2009/02/20/9435239.aspx); however, I don't know if there is an equivalent WPF functionality or if you need to PInvoke it.

6)

For example... what happens if my application crashes between OnStartup and OnExit?

It's OK: when a process terminates, all handles owned by the process are released; the mutex is released as well.

In short, my recommendations:

  • I would used an approach based on named synchronization objects: it is the more established on the windows platform(s). (Be careful when considering a multi-user system, like terminal server! Name the synchronization object as a combination of, maybe, user name/SID and application name)
  • Use the Windows API to raise the previous instance (see my link at point #5), or the WPF equivalent.
  • You probably do not have to worry about crashes (kernel will decrease the ref counter for the kernel object for you; do a little test anyway), BUT If I may suggest an improvement: what if your first application instance does not crash but hangs? (Happens with Firefox.. I'm sure it happened to you too! No window, ff process, you cannot open a new one). In that case it may be good to combine another technique or two, to a) test if the application/window responds; b) find the hung instance and terminate it

For example, you can use your technique (trying to send/post a message to the window - if does not answer back it is stuck), plus MSK technique, to find and terminate the old process. Then start normally.

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

Here is a very good article regarding the Mutex solution. The approach described by the article is advantageous for two reasons.

First, it does not require a dependency on the Microsoft.VisualBasic assembly. If my project already had a dependency on that assembly, I would probably advocate using the approach shown in another answer. But as it is, I do not use the Microsoft.VisualBasic assembly, and I'd rather not add an unnecessary dependency to my project.

Second, the article shows how to bring the existing instance of the application to the foreground when the user tries to start another instance. That's a very nice touch that the other Mutex solutions described here do not address.


UPDATE

As of 8/1/2014, the article I linked to above is still active, but the blog hasn't been updated in a while. That makes me worry that eventually it might disappear, and with it, the advocated solution. I'm reproducing the content of the article here for posterity. The words belong solely to the blog owner at Sanity Free Coding.

Today I wanted to refactor some code that prohibited my application
from running multiple instances of itself.

Previously I had use System.Diagnostics.Process to search for an
instance of my myapp.exe in the process list. While this works, it
brings on a lot of overhead, and I wanted something cleaner.

Knowing that I could use a mutex for this (but never having done it
before) I set out to cut down my code and simplify my life.

In the class of my application main I created a static named Mutex:

static class Program
{
static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
[STAThread]
...
}

Having a named mutex allows us to stack synchronization across
multiple threads and processes which is just the magic I'm looking
for.

Mutex.WaitOne has an overload that specifies an amount of time for us
to wait. Since we're not actually wanting to synchronizing our code
(more just check if it is currently in use) we use the overload with
two parameters: Mutex.WaitOne(Timespan timeout, bool exitContext).
Wait one returns true if it is able to enter, and false if it wasn't.
In this case, we don't want to wait at all; If our mutex is being
used, skip it, and move on, so we pass in TimeSpan.Zero (wait 0
milliseconds), and set the exitContext to true so we can exit the
synchronization context before we try to aquire a lock on it. Using
this, we wrap our Application.Run code inside something like this:

static class Program
{
static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
[STAThread]
static void Main() {
if(mutex.WaitOne(TimeSpan.Zero, true)) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
mutex.ReleaseMutex();
} else {
MessageBox.Show("only one instance at a time");
}
}
}

So, if our app is running, WaitOne will return false, and we'll get a
message box.

Instead of showing a message box, I opted to utilize a little Win32 to
notify my running instance that someone forgot that it was already
running (by bringing itself to the top of all the other windows). To
achieve this I used PostMessage to broadcast a custom message to every
window (the custom message was registered with RegisterWindowMessage
by my running application, which means only my application knows what
it is) then my second instance exits. The running application instance
would receive that notification and process it. In order to do that, I
overrode WndProc in my main form and listened for my custom
notification. When I received that notification I set the form's
TopMost property to true to bring it up on top.

Here is what I ended up with:

  • Program.cs
static class Program
{
static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
[STAThread]
static void Main() {
if(mutex.WaitOne(TimeSpan.Zero, true)) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
mutex.ReleaseMutex();
} else {
// send our Win32 message to make the currently running instance
// jump on top of all the other windows
NativeMethods.PostMessage(
(IntPtr)NativeMethods.HWND_BROADCAST,
NativeMethods.WM_SHOWME,
IntPtr.Zero,
IntPtr.Zero);
}
}
}
  • NativeMethods.cs
// this class just wraps some Win32 stuff that we're going to use
internal class NativeMethods
{
public const int HWND_BROADCAST = 0xffff;
public static readonly int WM_SHOWME = 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);
}
  • Form1.cs (front side partial)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void WndProc(ref Message m)
{
if(m.Msg == NativeMethods.WM_SHOWME) {
ShowMe();
}
base.WndProc(ref m);
}
private void ShowMe()
{
if(WindowState == FormWindowState.Minimized) {
WindowState = FormWindowState.Normal;
}
// get our current "TopMost" value (ours will always be false though)
bool top = TopMost;
// make our form jump to the top of everything
TopMost = true;
// set it back to whatever it was
TopMost = top;
}
}

How to invoke a method on the STA thread when you have nothing to invoke on?

I managed to solve it like this:

public partial class NotifyIconAndMenu : UserControl
{
private Form? mainForm = null;
private FormWindowState mainFormState = FormWindowState.Normal;
private readonly Func<Form> NewForm;

public NotifyIconAndMenu(Func<Form> newForm)
{
NewForm = newForm;
if (!this.InitSingleInstance("GROWPLENTYOFCHEESE4444", NewInstanceAttempt))
return;
InitializeComponent();
FormShowLoop();
Application.Run();
}

private async void FormShowLoop()
{
while (!IsDisposed)
{
await Task.Run(() =>
{
lock (this)
{
Monitor.Wait(this);
}
});
if(!IsDisposed)
ShowMainForm();
}
}

private void ShowMainForm()
{
if (mainForm == null || mainForm.IsDisposed)
{
mainForm = NewForm();
mainForm.Resize += MainForm_Resize;
mainForm.Visible = true;
}
mainForm.WindowState = mainFormState;
}

private void Pulse()
{
lock (this)
{
Monitor.Pulse(this);
}
}

private void Quit()
{
Dispose();
Pulse();
Application.Exit();
}

private void MainForm_Resize(object? sender, EventArgs e)
{
if (mainForm != null && mainForm.WindowState != FormWindowState.Minimized)
mainFormState = mainForm.WindowState;
}

private void NewInstanceAttempt() => Pulse();

private void IconMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
if (e.ClickedItem == MI_Show) Pulse();
else
if (e.ClickedItem == MI_Quit) Quit();
}
}


Related Topics



Leave a reply



Submit