Run single instance of an application using Mutex
I did it this way once, I hope it helps:
bool createdNew;
Mutex m = new Mutex(true, "myApp", out createdNew);
if (!createdNew)
{
// myApp is already running...
MessageBox.Show("myApp is already running!", "Multiple Instances");
return;
}
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();
}
}
}
Force Single Instance with Mutex handling restart application
Single instance apps are well supported by the framework. It supports goodies such as disabling it on-the-fly, what you need here, and getting a notification when another instance is started. You'll want to use that to give your first instance the focus. Rewrite your Program.cs code like this:
using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices; // NOTE: add reference to Microsoft.VisualBasic
namespace WindowsFormsApplication1 {
class Program : WindowsFormsApplicationBase {
public Program() {
EnableVisualStyles = true;
MainForm = new Form1();
IsSingleInstance = true;
}
public static void Main(string[] args) {
Instance = new Program();
Instance.Run(args);
}
protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) {
// Nicety, focus the single instance.
Instance.MainForm.Activate();
}
public static void Restart() {
// What you asked for. Use Program.Restart() in your code
Instance.IsSingleInstance = false;
Application.Restart();
}
private static Program 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();
}));
}
});
}
}
How to run one instance of a c# WinForm application?
I've made some small changes:
namespace CSMutex
{
static class Program
{
[STAThread]
static void Main()
{
bool mutexCreated=true;
using(Mutex mutex = new Mutex(true, "eCS", out mutexCreated))
{
if (mutexCreated)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Login loging = new Login();
Application.Run(loging);
Application.Run(new Main() { UserName = loging.UserName });
}
else
{
Process current = Process.GetCurrentProcess();
foreach (Process process in Process.GetProcessesByName(current.ProcessName))
{
if (process.Id != current.Id)
{
MessageBox.Show("Another instance of eCS is already running.", "eCS already running", MessageBoxButtons.OK, MessageBoxIcon.Information);
//SetForegroundWindow(process.MainWindowHandle);
break;
}
}
}
}
}
}
}
That works as expected - i.e. even when Login
form is closed (and the main application form is started) it doesn't let user run the application once again.
I've decided not to create Main
from within Login
(this is I believe how you application works) and instead I am passing parameter to Main
.
I have also made some small change to Login
so it has UserName
propert (same as Main
).
Mutex does not stop two instances of program from running at once
You can test the below code by running several instances simultaneously.
static void Main(string[] args)
{
using (var mutex = new Mutex(true, "UniqueSystemWideMutexName"))
{
//Timeout is set to zero so we don't block
if (!mutex.WaitOne(0))
{
Console.WriteLine("Program already running");
Console.ReadKey();
return;
}
Console.WriteLine("This is the only program running");
Console.ReadKey();
}
}
If you can't use Dispose
for whatever reason, which the using
block does for us, be sure to call ReleaseMutex
.
You can also use OpenExisting to check if the mutex has already been created, but it's not necessary for this simple use case.
How to allow single instance application from the same directory but several instances from different directories in C#?
You might be able to use Assembly.Location
(or the exe path in general) as the named mutex, with or without your Id.
Gets the full path or UNC location of the loaded file that contains
the manifest.
_mutex = new Mutex(true, directory, out isNewInstance);
or completely overkill
var location = Assembly.GetEntryAssembly().Location;
var hs = System.Security.Cryptography.MD5.Create();
var bytes = hs.ComputeHash(System.Text.Encoding.UTF8.GetBytes(location));
_mutex = new Mutex(true, Convert.ToBase64String(bytes), out isNewInstance);
Single Instance Application in C++/CLI using Mutex
Try this instead of PostMessage()
:
ShowWindowAsync(hWindow, 1); // SW_SHOWNORMAL
SetForegroundWindow(hWindow);
Related Topics
Compiler Ambiguous Invocation Error - Anonymous Method and Method Group with Func<> or Action
How to Delete All Files and Folders in a Directory
What's the Difference Between Task.Start/Wait and Async/Await
Efficient Way to Remove All Whitespace from String
What Does Initializecomponent() Do, and How Does It Work in Wpf
How to Serialize a String as Cdata Using Xmlserializer
How to Use Nuget Packages in My Azure Functions
Authenticate and Request a User's Timeline with Twitter API 1.1 Oauth
Getting the Size of a Field in Bytes with C#
Binding a Button's Visibility to a Bool Value in Viewmodel
Order of Linq Extension Methods Does Not Affect Performance
Passing Values Between Windows Forms C#
Get the Generated SQL Statement from a SQLcommand Object
How to Merge Datagridview Cell in Winforms
Best Way to Specify Whitespace in a String.Split Operation
How to Calculate Distance Similarity Measure of Given 2 Strings