Hi,
Here is the class I created and use that is based on your code.
It caters for global or local single instance apps, as well as specifying your own optional application name to lock on, which could be a guid or whatever, or allowing it to automatically generate one from a guid and the full entry assembly name if not specified.
There are several Run overloads for different configurations. All three parameters are optional.
It also switches to the existing application in a slightly different way, without losing the maximise window state, which happens if you restore the window every time. It first checks if the app is minimised before restoring.
Also, to ensure that the window is forced to the foreground under almost all circustances, it attaches the thread input of our thread to that of the application we switching to before doing the switch.
Example use:
To create a global single instance application. That is only, one instance across all user sessions. That is, only one instance on the machine.
<br />
[STAThread]<br />
static void Main() <br />
{<br />
SingletonApplication.Run(new Form1(), true);<br />
}<br />
To create a per user single instance application. This works with terminal services, XP sessions and Citrix.
<br />
[STAThread]<br />
static void Main() <br />
{<br />
SingletonApplication.Run(new Form1());<br />
}<br />
The class:
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace CompanyName.Win32.Util
{
#region SingletonApplication
public sealed class SingletonApplication
{
#region Public Members
#region Run
public static bool Run(string name, System.Windows.Forms.Form form, bool global)
{
if (InternalIsRunning(name, global))
{
SwitchToCurrentInstance();
return false;
}
Application.Run(form);
return true;
}
public static bool Run(string name, System.Windows.Forms.Form form)
{
return Run(name, form, false);
}
public static bool Run(System.Windows.Forms.Form form, bool global)
{
return Run(GetApplicationName(), form, global);
}
public static bool Run(System.Windows.Forms.Form form)
{
return Run(GetApplicationName(), form, false);
}
public static bool Run(string name, bool global)
{
return !InternalIsRunning(name, global);
}
public static bool Run(string name)
{
return Run(name, false);
}
public static bool Run(bool global)
{
return Run(GetApplicationName(), global);
}
public static bool Run()
{
return Run(GetApplicationName(), false);
}
#endregion
#region IsRunning
public static bool IsRunning(string name, bool global)
{
bool createdNew;
Mutex _mutex = new Mutex(true, GetMutexName(name, global), out createdNew);
if (createdNew)
_mutex.ReleaseMutex();
return !createdNew;
}
public static bool IsRunning(string name)
{
return IsRunning(name, false);
}
public static bool IsRunning(bool global)
{
return IsRunning(GetApplicationName(), global);
}
public static bool IsRunning()
{
return IsRunning(GetApplicationName(), false);
}
#endregion
#region GetApplicationName
public static string GetApplicationName()
{
return string.Format("a37e5577-a9c5-4837-ad17-288b9eb7b682, {0}",
Assembly.GetEntryAssembly().GetName().FullName);
}
#endregion
#endregion
#region Private Members
#region InternalIsRunning
private static bool InternalIsRunning(string name, bool global)
{
if (mutex == null)
{
mutex = new Mutex(true, GetMutexName(name, global));
GC.KeepAlive(mutex);
}
return !mutex.WaitOne(0, false);
}
#endregion
#region GetMutexName
private static string GetMutexName(string name, bool global)
{
return string.Format(@"{0}\{1}",
global ? "Global" : "Local", name.Replace(@"\", "_"));
}
#endregion
#region SwitchToCurrentInstance
private static void SwitchToCurrentInstance()
{
IntPtr hWnd = GetCurrentInstanceWindowHandle();
if (hWnd != IntPtr.Zero)
{
IntPtr _hWnd = GetForegroundWindow();
if (IsIconic(hWnd) != 0)
ShowWindow(hWnd, SW_RESTORE);
int hThread = GetWindowThreadProcessId(hWnd, IntPtr.Zero);
int _hThread = GetWindowThreadProcessId(_hWnd, IntPtr.Zero);
if (hThread != _hThread)
{
AttachThreadInput(_hThread, hThread, 1);
SetForegroundWindow(hWnd);
AttachThreadInput(_hThread, hThread, 0);
}
else
SetForegroundWindow(hWnd);
}
}
#endregion
#region GetCurrentInstanceWindowHandle
private static IntPtr GetCurrentInstanceWindowHandle()
{
IntPtr hWnd = IntPtr.Zero;
Process process = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(process.ProcessName);
foreach(Process _process in processes)
{
if (_process.Id != process.Id &&
_process.MainModule.FileName == process.MainModule.FileName &&
_process.MainWindowHandle != IntPtr.Zero)
{
hWnd = _process.MainWindowHandle;
break;
}
}
return hWnd;
}
#endregion
#region API Imports
[DllImport("user32.dll")]
private static extern int ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);
[DllImport("user32.dll")]
private static extern int IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int AttachThreadInput(int idAttach, int idAttachTo, int fAttach);
#endregion
#region Constructor
private SingletonApplication()
{}
#endregion
private const int SW_RESTORE = 9;
private static Mutex mutex;
#endregion
}
#endregion
}
|