I've seen all the other questions regarding creating a single instance app using WPF and I've chosen to use the Microsoft's approach as described here: https://codereview.stackexchange.com/a/25667
This is working fine, but now I'd like to using Caliburn.Micro on this application and this code does not play well with caliburn.
How can I have a single instance wpf application using caliburn micro?
The requirement are quite simple: .net 4.5 and only one instance of the application per user session
Thanks
I use a named mutex in my main method and show a dialog if the mutex already exists.
Check this stack - WPF Single Instance Best Practices
In case anyone is having the same issue, I want to clarify the steps.
First, you have to change what happens in program entry point. As others mentioned, the Main() function that acts as an entry point to WPF programs is auto-generated (App.g.i.cs); So we have to take control of it somehow. As mentioned in this answer, there are several ways to do so. Personally I prefer the Third Approach:
Include another class in your project that defines the Main method as below:
class Startup
{
[STAThread]
public static void Main()
{
// Your single instance control (shown in below code)
...
}
}
Identify the class whose main you want the application to use as entry point. This can be done via the project properties (right-click on your project >properties. or alt+enter while your project is selected in Solution Explorer). In the Application tab, modify the Startup object properties from the drop down:
Second, you have to decide for a mechanism to know if your program is being run more than once. There are several ways to do that (as the other answers mentioned). The one I prefer is this:
...
// Your single instance control:
bool firstInstance = true;
System.Threading.Mutex mutex = new System.Threading.Mutex(true, "some_unique_name_that_only_your_project_will_use", out firstInstance);
if (firstInstance)
{
// Everything that needs to be done in main class, for example:
YourProject.App app = new YourProject.App();
app.InitializeComponent();
app.Run();
}
else
{
// Your procedure for additional instances of program
MessageBox.Show("Another instance of this application is already running.");
}
These two steps together are one of the easiest ways to achieve your goal, even before Caliburn.Micro takes control of your program.
I had difficulty attempting this in the OnStartup() method.
Basically, you want to create a Main method (see No Main() in WPF? ) and wrap the contents using the mutex (see What is a good pattern for using a Global Mutex in C#?)
Mine looked like this:
class SingleGlobalInstance : IDisposable
{
public bool _hasHandle = false;
Mutex _mutex;
private void InitMutex()
{
string appGuid = "My App Name"; //((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value;
string mutexId = string.Format("Global\\{{{0}}}", appGuid);
_mutex = new Mutex(false, mutexId);
var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
var securitySettings = new MutexSecurity();
securitySettings.AddAccessRule(allowEveryoneRule);
_mutex.SetAccessControl(securitySettings);
}
public SingleGlobalInstance(int timeOut)
{
InitMutex();
try
{
if(timeOut < 0)
_hasHandle = _mutex.WaitOne(Timeout.Infinite, false);
else
_hasHandle = _mutex.WaitOne(timeOut, false);
if (_hasHandle == false)
{
MessageBox.Show("Another instance is already running");
System.Windows.Application.Current.Shutdown();
}
}
catch (AbandonedMutexException)
{
_hasHandle = true;
}
}
public void Dispose()
{
if (_mutex != null)
{
if (_hasHandle)
_mutex.ReleaseMutex();
_mutex.Close();
}
}
}
And my App.xaml.cs contained:
[STAThread]
public static void Main()
{
using (new SingleGlobalInstance(1000))
{
var application = new App();
application.InitializeComponent();
application.Run();
}
}
Related
I've checked out this question: Codeplex NDde Server how to send multiple items, and this Alternative Of client.Advise += OnAdvise; in vb.net NDDE, and a bunch of other sources, when dealing with this problem; however it seems that either I don't understand some basics, or it's something not explicitly supported in the way I have been trying to do it.
I'm struggling to write a class library that would send some values, about half-a-dozen, to an application that preferrably consumes DDE imputs, several at a time.
What is a source for perplexion for me is, whether I need to just do something like this, to be able to send my items by hot link
public AutoServer(string service, string ItemDataLabel)
: base(service)
{
// Create a timer that will be used to advise clients of new data.
_Timer.Elapsed += this.OnTimerElapsed;
_Timer.Interval = 30;
_Timer.SynchronizingObject = this.Context;
DataLabel = ItemDataLabel;
//OnAdvise(Symbol, DataLabel, 1);
}
private void OnTimerElapsed(object sender, ElapsedEventArgs args)
{
// Advise all topic name and item name pairs.
OnAdvise(Current, DataLabel, 1);
Advise(Current, DataLabel);
}
public string Data;
public string DataLabel;
}
and put there in this fashion several OnAdvises with different string labels, writing out what On Advise should do in case with every label combination, inside OnAdvice itself?
The other option seems to register several Server instances, with writing out in OnAdvice all the details for each case of parameter combinations.
But here comes the most difficult. I tried both approaches, and I'm getting exception that says: Invoke or BeginInvoke cannot be called on a control until the window handle has been created. In other words it comes out that I need a Context for each Server, respectively for each item (all that thing with multiple OnAdvices together doesn't seem to work).
Then would it be right to put form and context initialization in a single method with respective server registration, and so many likewise methods as the items are, and run them together at once?
For example:
namespace lookout_DDE
{
public partial class lookout_DDE_class : AutoGroup
{
public partial class ServerContextForm : Form
{
private DdeContext context = null;
private void ContextRunner()
{
context = new DdeContext(this);
context.Initialize();
}
}
}
}
and
namespace lookout_DDE
{
public partial class lookout_DDE_class : AutoGroup
{
public partial class ServerContextForm : Form
{
public ServerContextForm()
{
InitializeComponent();
ContextRunner();
}
}
}
}
and
[STAThread]
partial void RunServer()
{
using (ServerContextForm ContextForm = new ServerContextForm())
{
Application.Run(ContextForm);
ServerStarter("A1");
}
using (ServerContextForm ContextForm = new ServerContextForm())
{
Application.Run(ContextForm);
ServerStarter("A2");
}
using (ServerContextForm ContextForm = new ServerContextForm())
{
Application.Run(ContextForm);
ServerStarter("A3");
}
using (ServerContextForm ContextForm = new ServerContextForm())
{
Application.Run(ContextForm);
ServerStarter("A4");
}
using (ServerContextForm ContextForm = new ServerContextForm())
{
Application.Run(ContextForm);
ServerStarter("A5");
}
}
Just figured out I have to keep Forms for the contexts to run, so instead of \using\ separate methods would be needed.
So maybe the best way to restate the question would be, whether I need to use multiple forms with contexts, and server instances registered, in order to run multiple items, or somehow I should implement OnAdvice inside Server class?
See, I'm new to C# and programming in general, however, I'm trying to learn programming " in the process". If you can help, please advice. :)
Till now figured out partial solution:
1) There need to be several Server instances, because OnAdvice can be subscribed once by the client application. (And who knows how it does it if you didn't write it)
2) Each Server can require a separate (preferable) context, and respectively, a form, however there can be potentially a single context. Didn't test the last one.
Now, I recollected a bad/good joke about word "potentially". Guess what.
And what a pity of having no opinions at all!
I'm writing a windows phone app which stores data in a local database. There are multiple threads in my app that access the database and up until this point I have used the technique described here with an AutoResetEvent to ensure that only one thread can access the database at any one time.
So far this has worked very reliably, but now I want to add a ScheduledTask to do some work in the background so I've potentially got multiple processes now competing for access to the database.
Can anyone advise how I can adapt the AutoResetEvent technique to be used across multiple processes on Windows Phone?
I have seen approaches using a Mutex. If I acquire the Mutex before each DB call and then release it afterwards (similar to the way I'm using AutoResetEvent), will this do the trick? Is there any potential problems with this technique? eg: performance?
Ok so first of all my problem was actually 2 problems:
Need to ensure that if the foreground app is running, the background process won't run
Need to ensure that only one thread can access the databasse at once and this needs to work across processes to cater for the (admittedly rare, but possible) scenario where the foreground app is started while the background process is in progress.
Based on the good work done in this thread, I created a couple of classes to help.
To solve problem (1), I created the SingleInstanceSynchroniser:
/// <summary>
/// Used to ensure only one instance (foreground app or background app) runs at once
/// </summary>
public class SingleInstanceSynchroniser : IDisposable
{
private bool hasHandle = false;
Mutex mutex;
private void InitMutex()
{
string mutexId = "Global\\SingleInstanceSynchroniser";
mutex = new Mutex(false, mutexId);
}
public SingleInstanceSynchroniser()
{
InitMutex();
hasHandle = mutex.WaitOne(0);
}
public void Dispose()
{
if (hasHandle && mutex != null)
mutex.ReleaseMutex();
}
public bool HasExclusiveHandle { get { return hasHandle; } }
}
Usage:
In App.xaml.cs:
...
SingleInstanceSynchroniser singleInstanceSynchroniser;
public App()
{
singleInstanceSynchroniser = new SingleInstanceSynchroniser();
...
In ScheduledAgent.cs:
SingleInstanceSynchroniser singleInstanceSynchroniser;
protected override void OnInvoke(ScheduledTask task)
{
singleInstanceSynchroniser = new SingleInstanceSynchroniser();
if (singleInstanceSynchroniser.HasExclusiveHandle)
{
//Run background process
...
}
else
{ //Do not run if foreground app is running
NotifyComplete();
}
}
To solve problem (2), I created the SingleAccessSynchroniser:
/// <summary>
/// Used to ensure only one call is made to the database at once
/// </summary>
public class SingleAccessSynchroniser : IDisposable
{
public bool hasHandle = false;
Mutex mutex;
private void InitMutex()
{
string mutexId = "Global\\SingleAccessSynchroniser";
mutex = new Mutex(false, mutexId);
}
public SingleAccessSynchroniser() : this(0)
{ }
public SingleAccessSynchroniser(int TimeOut)
{
InitMutex();
if (TimeOut <= 0)
hasHandle = mutex.WaitOne();
else
hasHandle = mutex.WaitOne(TimeOut);
if (hasHandle == false)
throw new TimeoutException("Timeout waiting for exclusive access on SingleInstance");
}
public void Release()
{
if (hasHandle && mutex != null)
{
mutex.ReleaseMutex();
hasHandle = false;
}
}
public void Dispose()
{
Release();
}
}
Usage: In all database calls:
using (var dbSync = new SingleAccessSynchroniser())
{
//Execute your database calls
}
This has been running reliably for a few weeks now. Hope someone else finds it useful.
I ran into some problems using Bens solution on Windows Phone 8. Please see this thread for a complete documentation of the problems.
I was able to resolve the issues by removing "Global\" from "Global\SingleInstanceSynchroniser".
Concurrent access to a database between an agent and an app shouldn't be an issue. In fact, using Linq2SQL is one of the recommended ways for communicating between the app and agent.
In practice, it's rarely necessary for the app and agent to run at the same time and so it may be more appropriate to prevent that happening instead.
Potential performance issues will be dependent upon what you're doing. You'll need to measure this to see if it's really an issue.
I am trying to automate multiple parallel instances of Office InfoPath 2010 via a windows service. I understand automating Office from a service is not supported however it is a requirement of my customer.
I can automate other Office applications in a parallel fashion, however InfoPath behaves differently.
What I have found is that there will only ever be one instance of the INFOPATH.EXE process created, no matter how many parallel calls to CreateObject("InfoPath.Application") are made. In contrast to this, multiple instances of WINWORD.EXE can be created via the similar mechanism CreateObject("Word.Application")
To reproduce this issue, a simple console application can be used.
static void Main(string[] args) {
// Create two instances of word in parallel
ThreadPool.QueueUserWorkItem(Word1);
ThreadPool.QueueUserWorkItem(Word2);
System.Threading.Thread.Sleep(5000);
// Attempt to create two instances of infopath in parallel
ThreadPool.QueueUserWorkItem(InfoPath1);
ThreadPool.QueueUserWorkItem(InfoPath2);
}
static void Word1(object context) {
OfficeInterop.WordTest word = new OfficeInterop.WordTest();
word.Test();
}
static void Word2(object context) {
OfficeInterop.WordTest word = new OfficeInterop.WordTest();
word.Test();
}
static void InfoPath1(object context) {
OfficeInterop.InfoPathTest infoPath = new OfficeInterop.InfoPathTest();
infoPath.Test();
}
static void InfoPath2(object context) {
OfficeInterop.InfoPathTest infoPath = new OfficeInterop.InfoPathTest();
infoPath.Test();
}
The InfoPathTest and WordTest classes (VB) are in another project.
Public Class InfoPathTest
Public Sub Test()
Dim ip As Microsoft.Office.Interop.InfoPath.Application
ip = CreateObject("InfoPath.Application")
System.Threading.Thread.Sleep(5000)
ip.Quit(False)
End Sub
End Class
Public Class WordTest
Public Sub Test()
Dim app As Microsoft.Office.Interop.Word.Application
app = CreateObject("Word.Application")
System.Threading.Thread.Sleep(5000)
app.Quit(False)
End Sub
End Class
The interop classes simply create the automation objects, sleep and then quit (although in the case of Word, I have completed more complex tests).
When running the console app, I can see (via Task Manager) two WINWORD.EXE processes created in parallel, and only a single INFOPATH.EXE process created. In fact when the first instance of InfoPathTest calls ip.Quit, the INFOPATH.EXE process terminates. When the second instance of InfoPathTest calls ip.Quit, a DCOM timeout exception is thrown - it appears as though the two instances were sharing the same underlying automation object, and that object no longer exists after the first call to ip.Quit.
At this stage my thoughts were only a single INFOPATH.EXE is supported per user login. I expanded the windows service to start two new processes (a console application called InfoPathTest), each running under a different user account. These new processes would then attempt to automate INFOPATH.EXE
Here's where it gets interesting, this actually works, but only on some machines, and I cannot figure out why that is the case.
And the service code (with help from AsproLock):
public partial class InfoPathService : ServiceBase {
private Thread _mainThread;
private bool isStopping = false;
public InfoPathService() {
InitializeComponent();
}
protected override void OnStart(string[] args) {
if (_mainThread == null || _mainThread.IsAlive == false) {
_mainThread = new Thread(ProcessController);
_mainThread.Start();
}
}
protected override void OnStop() {
isStopping = true;
}
public void ProcessController() {
while (isStopping == false) {
try {
IntPtr hWinSta = GetProcessWindowStation();
WindowStationSecurity ws = new WindowStationSecurity(hWinSta, System.Security.AccessControl.AccessControlSections.Access);
ws.AddAccessRule(new WindowStationAccessRule("user1", WindowStationRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
ws.AddAccessRule(new WindowStationAccessRule("user2", WindowStationRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
ws.AcceptChanges();
IntPtr hDesk = GetThreadDesktop(GetCurrentThreadId());
DesktopSecurity ds = new DesktopSecurity(hDesk, System.Security.AccessControl.AccessControlSections.Access);
ds.AddAccessRule(new DesktopAccessRule("user1", DesktopRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
ds.AddAccessRule(new DesktopAccessRule("user2", DesktopRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
ds.AcceptChanges();
ThreadPool.QueueUserWorkItem(Process1);
ThreadPool.QueueUserWorkItem(Process2);
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine(String.Format("{0}: Process Controller Error {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, ex.Message));
}
Thread.Sleep(15000);
}
}
private static void Process1(object context) {
SecureString pwd2;
Process process2 = new Process();
process2.StartInfo.FileName = #"c:\debug\InfoPathTest.exe";
process2.StartInfo.UseShellExecute = false;
process2.StartInfo.LoadUserProfile = true;
process2.StartInfo.WorkingDirectory = #"C:\debug\";
process2.StartInfo.Domain = "DEV01";
pwd2 = new SecureString(); foreach (char c in "password") { pwd2.AppendChar(c); };
process2.StartInfo.Password = pwd2;
process2.StartInfo.UserName = "user1";
process2.Start();
process2.WaitForExit();
}
private static void Process2(object context) {
SecureString pwd2;
Process process2 = new Process();
process2.StartInfo.FileName = #"c:\debug\InfoPathTest.exe";
process2.StartInfo.UseShellExecute = false;
process2.StartInfo.LoadUserProfile = true;
process2.StartInfo.WorkingDirectory = #"C:\debug\";
process2.StartInfo.Domain = "DEV01";
pwd2 = new SecureString(); foreach (char c in "password") { pwd2.AppendChar(c); };
process2.StartInfo.Password = pwd2;
process2.StartInfo.UserName = "user2";
process2.Start();
process2.WaitForExit();
}
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetProcessWindowStation();
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetThreadDesktop(int dwThreadId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int GetCurrentThreadId();
}
The InfoPathTest.exe process simply calls the InfoPathTest.Test() method detailed above.
In summary, this works, but only on certain machines. When it fails, the second INFOPATH.EXE process is actually created, but immediately quits with an exitcode of 0. There is nothing in the event logs, nor any exceptions in the code.
I've looked at many things to try and differentiate between working / non working machines, but I'm now stuck.
Any pointers appreciated, especially if you have other thoughts on how to automate multiple InfoPath instances in parallel.
I'm guessing you'd get similar behavior if you tried to do the same thing with Outlook, which would mean Microsoft thinks it is a bad idea to run multiple copies.
If that is so, I see two options.
Option one is to make your Infopath automation synchronous, running one instance at a time.
Option two, and I have NO idea if it would even work, would be to see if you can launch virtual machines to accomplish youe InfoPath work.
I hope this can at least spark some new train of though that will lead to success.
I’ve encountered a very similar issue with Outlook. The restriction of allowing only a single instance of the application to be running does not apply per user, but per interactive login session. You may read more about it in Investigating Outlook's Single-Instance Restriction:
Outlook was determining whether or not another instance was already running in the interactive login session. […] During Outlook's initialization, it checks to see if a window named "Microsoft Outlook" with class name "mspim_wnd32" exists, and if so, it assumes that another instance is already running.
There are ways of hacking around it – there is a tool for launching multiple Outlook instances on the Hammer of God site (scroll down) – but they will probably involve intercepting Win32 calls.
As for your code only working on certain machines: That’s probably due to a race condition. If both processes manage to start up fast enough simultaneously, then they won’t detect each other’s window, and assume that they’re the only instance running. However, if the machine is slow, one process would open its window before the other, thereby causing the second process to detect the first process’s window and shut itself down. To reproduce, try introducing a delay of several seconds between launching the first process and the second – this way, only the first process should ever succeed.
Okay, so i've created my c# application, created an installer for it and have it working installed on my machine.
The problem is, when the user opens the application exe twice, there will be two instances of the application running. I only ever want one instance of the application to be running at any time, how do I go about doing this?
Thanks for your help,
The common technique for this is to create a named Mutex and check for its presence on application start.
See this or this.
Code from DDJ:
class App : Form
{
Mutex mutex;
App()
{
Text = "Single Instance!";
mutex = new Mutex(false, "SINGLE_INSTANCE_MUTEX");
if (!mutex.WaitOne(0, false))
{
mutex.Close();
mutex = null;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
mutex.ReleaseMutex();
base.Dispose(disposing);
}
static void Main()
{
App app = new App();
if (app.mutex != null) Application.Run(app);
else MessageBox.Show("Instance already running");
}
}
i solved this problem by this
[STAThread]
static void Main()
{
Process[] result = Process.GetProcessesByName("ApplicationName");
if (result.Length > 1)
{
MessageBox.Show("There is already a instance running.", "Information");
System.Environment.Exit(0);
}
// here normal start
}
it is simple, but i had hardly time to check for better solutions.
With thanks to Messrs. Allen and Powell:
static void Main()
{
using (Mutex mutex = new Mutex(false, #"Global\" + appGuid)) {
if (!mutex.WaitOne(0, false)) {
string processName = GetProcessName();
BringOldInstanceToFront(processName);
}
else {
GC.Collect();
Application.Run(new Voting());
}
}
}
private static void BringOldInstanceToFront(string processName) {
Process[] RunningProcesses = Process.GetProcessesByName(processName);
if (RunningProcesses.Length > 0) {
Process runningProcess = RunningProcesses[0];
if (runningProcess != null) {
IntPtr mainWindowHandle = runningProcess.MainWindowHandle;
NativeMethods.ShowWindowAsync(mainWindowHandle, (int) WindowConstants.ShowWindowConstants.SW_SHOWMINIMIZED);
NativeMethods.ShowWindowAsync(mainWindowHandle, (int) WindowConstants.ShowWindowConstants.SW_RESTORE);
}
}
}
I don't know the environment that you are operating in, but something to keep in mind about 'single-instance applications' is how you define single-instance. If the application can be run on multiple workstations at the same time, using a common datasource, is that an issue? Likewise, what about a terminal-services situation (or a "run as" situation) where more than one user is logged into the same computer, do you want to restrict the application in such a way that only one instance per-user, per-computer? Or are you okay with it simply being one instance per user?
The answer to these might lead you in one direction over another. For example, we have a 'single-instance' application with the scope being a group of computers. Only one user is allowed on within that group of workstations. We managed this by have a table in our shared data-source that tracked currently connected users. This is a maintenance issue as you need to be sure that table is 100% accurate all the time. Handling things like unexpected power outages on the workstation, leaving "bogus" records in that table took some careful handling.
In .NET, what's the best way to prevent multiple instances of an app from running at the same time? And if there's no "best" technique, what are some of the caveats to consider with each solution?
Use Mutex. One of the examples above using GetProcessByName has many caveats. Here is a good article on the subject:
http://odetocode.com/Blogs/scott/archive/2004/08/20/401.aspx
[STAThread]
static void Main()
{
using(Mutex mutex = new Mutex(false, "Global\\" + appGuid))
{
if(!mutex.WaitOne(0, false))
{
MessageBox.Show("Instance already running");
return;
}
Application.Run(new Form1());
}
}
private static string appGuid = "c0a76b5a-12ab-45c5-b9d9-d693faa6e7b9";
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
{
AppLog.Write("Application XXXX already running. Only one instance of this application is allowed", AppLog.LogMessageType.Warn);
return;
}
Here is the code you need to ensure that only one instance is running. This is the method of using a named mutex.
public class Program
{
static System.Threading.Mutex singleton = new Mutex(true, "My App Name");
static void Main(string[] args)
{
if (!singleton.WaitOne(TimeSpan.Zero, true))
{
//there is already another instance running!
Application.Exit();
}
}
}
Hanselman has a post on using the WinFormsApplicationBase class from the Microsoft.VisualBasic assembly to do this.
1 - Create a reference in program.cs ->
using System.Diagnostics;
2 - Put into void Main() as the first line of code ->
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return;
That's it.
After trying multiple solutions i the question. I ended up using the example for WPF here: http://www.c-sharpcorner.com/UploadFile/f9f215/how-to-restrict-the-application-to-just-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)
{
//app is already running! Exiting the application
Application.Current.Shutdown();
}
}
}
In App.xaml:
x:Class="*YourNameSpace*.App"
StartupUri="MainWindow.xaml"
Startup="App_Startup"
It sounds like there are 3 fundamental techniques that have been suggested so far.
Derive from the Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase class and set the IsSingleInstance property to true. (I believe a caveat here is that this won't work with WPF applications, will it?)
Use a named mutex and check if it's already been created.
Get a list of running processes and compare the names of the processes. (This has the caveat of requiring your process name to be unique relative to any other processes running on a given user's machine.)
Any caveats I've missed?
i tried all the solutions here and nothing worked in my C# .net 4.0 project. Hoping to help someone here the solution that worked for me:
As main class variables:
private static string appGuid = "WRITE AN UNIQUE GUID HERE";
private static Mutex mutex;
When you need to check if app is already running:
bool mutexCreated;
mutex = new Mutex(true, "Global\\" + appGuid, out mutexCreated);
if (mutexCreated)
mutex.ReleaseMutex();
if (!mutexCreated)
{
//App is already running, close this!
Environment.Exit(0); //i used this because its a console app
}
I needed to close other istances only with some conditions, this worked well for my purpose
Using Visual Studio 2005 or 2008 when you create a project for an executable, on the properties windows inside the "Application" panel there is a check box named “Make single instance application” that you can activate to convert the application on a single instance application.
Here is a capture of the window I'm talking of:
This is a Visual Studio 2008 windows application project.
http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0—Single-Instance_Detection_and_Management
This is the code for VB.Net
Private Shared Sub Main()
Using mutex As New Mutex(False, appGuid)
If Not mutex.WaitOne(0, False) Then
MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End If
Application.Run(New Form1())
End Using
End Sub
This is the code for C#
private static void Main()
{
using (Mutex mutex = new Mutex(false, appGuid)) {
if (!mutex.WaitOne(0, false)) {
MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Application.Run(new Form1());
}
}
Use VB.NET!
No: really ;)
using Microsoft.VisualBasic.ApplicationServices;
The WindowsFormsApplicationBase from VB.Net provides you with a "SingleInstace" Property, which determines other Instances and let only one Instance run.
[STAThread]
static void Main() // args are OK here, of course
{
bool ok;
m = new System.Threading.Mutex(true, "YourNameHere", out ok);
if (! ok)
{
MessageBox.Show("Another instance is already running.");
return;
}
Application.Run(new Form1()); // or whatever was there
GC.KeepAlive(m); // important!
}
From: Ensuring a single instance of .NET Application
and: Single Instance Application Mutex
Same answer as #Smink and #Imjustpondering with a twist:
Jon Skeet's FAQ on C# to find out why GC.KeepAlive matters
This article simply explains how you can create a windows application with control on the number of its instances or run only single instance. This is very typical need of a business application. There are already lots of other possible solutions to control this.
https://web.archive.org/web/20090205153420/http://www.openwinforms.com/single_instance_application.html
http://www.codeproject.com/KB/cs/SingleInstancingWithIpc.aspx
You have to use System.Diagnostics.Process.
Check out: http://www.devx.com/tips/Tip/20044
(Note: this is a fun-solution! It works but uses bad GDI+ design to achieve this.)
Put an image in with your app and load it on startup. Hold it until the app exits. The user wont be able to start a 2nd instance. (Of course the mutex solution is much cleaner)
private static Bitmap randomName = new Bitmap("my_image.jpg");
Simply using a StreamWriter, how about this?
System.IO.File.StreamWriter OpenFlag = null; //globally
and
try
{
OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
Environment.Exit(0);
}
Normally it's done with a named Mutex (use new Mutex( "your app name", true ) and check the return value), but there's also some support classes in Microsoft.VisualBasic.dll that can do it for you.
This worked for me in pure C#. the try/catch is when possibly a process in the list exits during your loop.
using System.Diagnostics;
....
[STAThread]
static void Main()
{
...
int procCount = 0;
foreach (Process pp in Process.GetProcesses())
{
try
{
if (String.Compare(pp.MainModule.FileName, Application.ExecutablePath, true) == 0)
{
procCount++;
if(procCount > 1) {
Application.Exit();
return;
}
}
}
catch { }
}
Application.Run(new Form1());
}
Be sure to consider security when restricting an application to a single instance:
Full article:
https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813
We are using a named mutex with a fixed name in order to detect
whether another copy of the program is running. But that also means an
attacker can create the mutex first, thereby preventing our program
from running at all! How can I prevent this type of denial of service
attack?
...
If the attacker is running in the same security context as your
program is (or would be) running in, then there is nothing you can do.
Whatever "secret handshake" you come up with to determine whether
another copy of your program is running, the attacker can mimic it.
Since it is running in the correct security context, it can do
anything that the "real" program can do.
...
Clearly you can't protect yourself from an attacker running at the
same security privilege, but you can still protect yourself against
unprivileged attackers running at other security privileges.
Try setting a DACL on your mutex, here's the .NET way:
https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx
None of this answers worked for me because I needed this to work under Linux using monodevelop. This works great for me:
Call this method passing it a unique ID
public static void PreventMultipleInstance(string applicationId)
{
// Under Windows this is:
// C:\Users\SomeUser\AppData\Local\Temp\
// Linux this is:
// /tmp/
var temporaryDirectory = Path.GetTempPath();
// Application ID (Make sure this guid is different accross your different applications!
var applicationGuid = applicationId + ".process-lock";
// file that will serve as our lock
var fileFulePath = Path.Combine(temporaryDirectory, applicationGuid);
try
{
// Prevents other processes from reading from or writing to this file
var _InstanceLock = new FileStream(fileFulePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
_InstanceLock.Lock(0, 0);
MonoApp.Logger.LogToDisk(LogType.Notification, "04ZH-EQP0", "Aquired Lock", fileFulePath);
// todo investigate why we need a reference to file stream. Without this GC releases the lock!
System.Timers.Timer t = new System.Timers.Timer()
{
Interval = 500000,
Enabled = true,
};
t.Elapsed += (a, b) =>
{
try
{
_InstanceLock.Lock(0, 0);
}
catch
{
MonoApp.Logger.Log(LogType.Error, "AOI7-QMCT", "Unable to lock file");
}
};
t.Start();
}
catch
{
// Terminate application because another instance with this ID is running
Environment.Exit(102534);
}
}