什么是创build单实例应用程序的正确方法?
在.NET(而不是Windows窗体或控制台)下使用C#和WPF,创build只能作为单个实例运行的应用程序的正确方法是什么?
我知道这与一个叫做互斥体的神秘事物有关,很less我能find一个麻烦停下来解释这个是什么的人。
该代码还需要通知已经运行的实例,用户试图启动第二个,也可能传递任何命令行参数(如果存在的话)。
这是一个非常好的关于互斥解决scheme的文章 。 由于两个原因,文章描述的方法是有利的。
首先,它不需要依赖Microsoft.VisualBasic程序集。 如果我的项目已经依赖于该程序集,我可能会主张使用接受答案中显示的方法。 但事实上,我不使用Microsoft.VisualBasic程序集,我宁愿不添加一个不必要的依赖项到我的项目。
其次,文章展示了当用户尝试启动另一个实例时,如何将应用程序的现有实例置于前台。 这是一个非常好的触摸,这里描述的其他Mutex解决scheme没有解决。
UPDATE
截至2014年8月1日,我链接到上面的文章仍然活跃,但博客没有更新一段时间。 这让我担心,最终可能会消失,并由此提出主张的解决scheme。 我在这里为后人重现了这篇文章的内容。 这些词完全属于Sanity Free Coding的博客所有者。
今天我想重构一些禁止我的应用程序运行自己的多个实例的代码。
以前,我使用System.Diagnostics.Process在进程列表中searchmyapp.exe的实例。 虽然这个工作,它带来了很多的开销,我想要更干净的东西。
知道我可以使用一个互斥体(但从来没有做过),我开始削减我的代码,并简化了我的生活。
在我的应用程序主类我创build了一个静态名为Mutex :
static class Program { static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}"); [STAThread] ... }
拥有一个命名的互斥体允许我们跨多个线程和进程堆栈同步,这只是我正在寻找的魔法。
Mutex.WaitOne有一个重载,指定我们等待的时间。 由于我们实际上并不想同步我们的代码(更多的是检查它是否正在使用),我们使用带有两个参数的重载: Mutex.WaitOne(Timespan timeout,bool exitContext) 。 如果能够input,等待一个返回true,否则返回false。 在这种情况下,我们不想等待; 如果我们正在使用互斥锁,请跳过它,继续前进,所以我们传入TimeSpan.Zero(等待0毫秒),并将exitContext设置为true,以便在尝试获取同步上下文之前,我们可以退出同步上下文。 使用这个,我们把我们的Application.Run代码包装在这样的东西里面:
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"); } } }
所以,如果我们的应用程序正在运行,WaitOne将返回false,我们会得到一个消息框。
我没有显示消息框,而是select使用一个小的Win32通知我的正在运行的实例,有人忘记了它已经在运行(通过使自己到所有其他窗口的顶部)。 为了达到这个目的,我使用了PostMessage向每个窗口广播自定义消息(自定义消息是通过运行的应用程序向RegisterWindowMessage注册的,这意味着只有我的应用程序知道它是什么)然后我的第二个实例退出。 正在运行的应用程序实例将收到该通知并处理它。 为了做到这一点,我重写了我的主要forms的WndProc ,并听取我的自定义通知。 当我收到通知时,我将表单的TopMost属性设置为true,将其置于顶部。
这是我最后的结果:
- 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(正面部分)
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; } }
你可以使用Mutex类,但你很快就会发现你将需要实现代码来传递参数等。 那么,当我阅读Chris Sell的书时,我在WinForms编程中学到了一个技巧。 这个技巧使用框架中已经提供给我们的逻辑。 我不了解你,但是当我了解可以在框架中重复使用的东西时,通常是我所采取的路线,而不是重新发明轮子。 当然,除非我不想做任何事情。
当我进入WPF时,我想出了一种使用相同代码的方式,但在WPF应用程序中。 这个解决scheme应该基于你的问题来满足你的需求。
首先,我们需要创build我们的应用程序类。 在这个类中,我们将覆盖OnStartup事件并创build一个名为Activate的方法,稍后将使用它。
public class SingleInstanceApplication : System.Windows.Application { protected override void OnStartup(System.Windows.StartupEventArgs e) { // Call the OnStartup event on our base class base.OnStartup(e); // Create our MainWindow and show it MainWindow window = new MainWindow(); window.Show(); } public void Activate() { // Reactivate the main window MainWindow.Activate(); } }
其次,我们需要创build一个可以pipe理我们实例的类。 在我们完成之前,我们实际上将重用Microsoft.VisualBasic程序集中的一些代码。 因为我在这个例子中使用了C#,所以我不得不引用这个程序集。 如果你使用VB.NET,你不需要做任何事情。 我们要使用的类是WindowsFormsApplicationBase,并inheritance我们的实例pipe理器,然后利用属性和事件来处理单个实例。
public class SingleInstanceManager : Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase { private SingleInstanceApplication _application; private System.Collections.ObjectModel.ReadOnlyCollection<string> _commandLine; public SingleInstanceManager() { IsSingleInstance = true; } protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs eventArgs) { // First time _application is launched _commandLine = eventArgs.CommandLine; _application = new SingleInstanceApplication(); _application.Run(); return false; } protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) { // Subsequent launches base.OnStartupNextInstance(eventArgs); _commandLine = eventArgs.CommandLine; _application.Activate(); } }
基本上,我们使用VB位来检测单个实例并相应地进行处理。 OnStartup将在第一个实例加载时触发。 应用程序再次重新运行时,会触发OnStartupNextInstance。 正如你所看到的,我可以通过事件参数得到命令行上传递的内容。 我将该值设置为实例字段。 您可以在这里parsing命令行,也可以通过构造函数和对Activate方法的调用将它传递给应用程序。
第三,现在是创build我们的入口点的时候了。 而不是像通常那样新build应用程序,我们将利用我们的SingleInstanceManager。
public class EntryPoint { [STAThread] public static void Main(string[] args) { SingleInstanceManager manager = new SingleInstanceManager(); manager.Run(args); } }
那么,我希望你能够遵循一切,并能够使用这个实现,并使之成为你自己的。
从这里 。
跨进程互斥的常见用法是确保一次只能运行一个程序的实例。 这是如何完成的:
class OneAtATimePlease { // Use a name unique to the application (eg include your company URL) static Mutex mutex = new Mutex (false, "oreilly.com OneAtATimeDemo"); static void Main() { // Wait 5 seconds if contended – in case another instance // of the program is in the process of shutting down. if (!mutex.WaitOne(TimeSpan.FromSeconds (5), false)) { Console.WriteLine("Another instance of the app is running. Bye!"); return; } try { Console.WriteLine("Running - press Enter to exit"); Console.ReadLine(); } finally { mutex.ReleaseMutex(); } } }
Mutex的一个很好的特性是,如果应用程序在没有释放ReleaseMutex的情况下终止,CLR将自动释放Mutex。
MSDN实际上有一个示例应用程序的C#和VB完成此操作: http : //msdn.microsoft.com/en-us/library/ms771662(v=VS.90).aspx
开发单实例检测最常用和最可靠的技术是使用Microsoft .NET Framework远程处理基础结构(System.Remoting)。 Microsoft .NET Framework(2.0版)包含一个typesWindowsFormsApplicationBase,它封装了所需的远程function。 要将此types并入WPF应用程序中,types需要从中派生出来,并用作应用程序静态入口点方法Main和WPF应用程序的Applicationtypes之间的填充。 Shim可以检测应用程序何时首次启动以及何时尝试后续启动,并控制WPF应用程序types以确定如何处理启动。
- 对于C#人来说,只要深呼吸,忘记整个“我不想包含VisualBasic DLL”。 正因为如此 , Scott Hanselman所说的以及事实上这个问题是最简洁的解决scheme,并且是由比您更了解框架的人devise的。
- 从可用性的angular度来看,事实是,如果你的用户正在加载一个应用程序,它已经打开,你给他们一个错误信息,如
'Another instance of the app is running. Bye'
'Another instance of the app is running. Bye'
那么他们不会是一个非常高兴的用户。 您只需(在GUI应用程序中)切换到该应用程序并传递所提供的参数 – 或者如果命令行参数没有意义,则必须popup可能已被最小化的应用程序。
这个框架已经有了这个支持 – 它只是一个白痴命名的DLL Microsoft.VisualBasic
它没有得到放入Microsoft.ApplicationUtils
或类似的东西。 克服它 – 或打开reflection器。
提示:如果你完全按照这个方法使用这个方法,并且你已经有一个App.xaml和资源等等,你也可以看看这个 。
这个代码应该去主要的方法。 在这里看看有关WPF中主要方法的更多信息。
[DllImport("user32.dll")] private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow); private const int SW_SHOWMAXIMIZED = 3; static void Main() { Process currentProcess = Process.GetCurrentProcess(); var runningProcess = (from process in Process.GetProcesses() where process.Id != currentProcess.Id && process.ProcessName.Equals( currentProcess.ProcessName, StringComparison.Ordinal) select process).FirstOrDefault(); if (runningProcess != null) { ShowWindow(runningProcess.MainWindowHandle, SW_SHOWMAXIMIZED); return; } }
方法2
static void Main() { string procName = Process.GetCurrentProcess().ProcessName; // get the list of all processes by that name Process[] processes=Process.GetProcessesByName(procName); if (processes.Length > 1) { MessageBox.Show(procName + " already running"); return; } else { // Application.Run(...); } }
注意:以上方法假定您的stream程/应用程序具有唯一的名称。 因为它使用进程名称来查找是否存在任何处理器。 所以,如果你的应用程序有一个非常普通的名称(即:记事本),上面的方法将不起作用。
一个使用Mutex和IPC的新东西,并且将任何命令行parameter passing给正在运行的实例,是WPF单实例应用程序 。
那么,我有一个一次性类,这对于大多数用例很容易工作:
像这样使用它:
static void Main() { using (SingleInstanceMutex sim = new SingleInstanceMutex()) { if (sim.IsOtherInstanceRunning) { Application.Exit(); } // Initialize program here. } }
这里是:
/// <summary> /// Represents a <see cref="SingleInstanceMutex"/> class. /// </summary> public partial class SingleInstanceMutex : IDisposable { #region Fields /// <summary> /// Indicator whether another instance of this application is running or not. /// </summary> private bool isNoOtherInstanceRunning; /// <summary> /// The <see cref="Mutex"/> used to ask for other instances of this application. /// </summary> private Mutex singleInstanceMutex = null; /// <summary> /// An indicator whether this object is beeing actively disposed or not. /// </summary> private bool disposed; #endregion #region Constructor /// <summary> /// Initializes a new instance of the <see cref="SingleInstanceMutex"/> class. /// </summary> public SingleInstanceMutex() { this.singleInstanceMutex = new Mutex(true, Assembly.GetCallingAssembly().FullName, out this.isNoOtherInstanceRunning); } #endregion #region Properties /// <summary> /// Gets an indicator whether another instance of the application is running or not. /// </summary> public bool IsOtherInstanceRunning { get { return !this.isNoOtherInstanceRunning; } } #endregion #region Methods /// <summary> /// Closes the <see cref="SingleInstanceMutex"/>. /// </summary> public void Close() { this.ThrowIfDisposed(); this.singleInstanceMutex.Close(); } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (!this.disposed) { /* Release unmanaged ressources */ if (disposing) { /* Release managed ressources */ this.Close(); } this.disposed = true; } } /// <summary> /// Throws an exception if something is tried to be done with an already disposed object. /// </summary> /// <remarks> /// All public methods of the class must first call this. /// </remarks> public void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(this.GetType().Name); } } #endregion }
这里是一个例子,允许你有一个应用程序的单个实例。 当任何新实例加载时,它们将parameter passing给正在运行的主实例。
public partial class App : Application { private static Mutex SingleMutex; public static uint MessageId; private void Application_Startup(object sender, StartupEventArgs e) { IntPtr Result; IntPtr SendOk; Win32.COPYDATASTRUCT CopyData; string[] Args; IntPtr CopyDataMem; bool AllowMultipleInstances = false; Args = Environment.GetCommandLineArgs(); // TODO: Replace {00000000-0000-0000-0000-000000000000} with your application's GUID MessageId = Win32.RegisterWindowMessage("{00000000-0000-0000-0000-000000000000}"); SingleMutex = new Mutex(false, "AppName"); if ((AllowMultipleInstances) || (!AllowMultipleInstances && SingleMutex.WaitOne(1, true))) { new Main(); } else if (Args.Length > 1) { foreach (Process Proc in Process.GetProcesses()) { SendOk = Win32.SendMessageTimeout(Proc.MainWindowHandle, MessageId, IntPtr.Zero, IntPtr.Zero, Win32.SendMessageTimeoutFlags.SMTO_BLOCK | Win32.SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 2000, out Result); if (SendOk == IntPtr.Zero) continue; if ((uint)Result != MessageId) continue; CopyDataMem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Win32.COPYDATASTRUCT))); CopyData.dwData = IntPtr.Zero; CopyData.cbData = Args[1].Length*2; CopyData.lpData = Marshal.StringToHGlobalUni(Args[1]); Marshal.StructureToPtr(CopyData, CopyDataMem, false); Win32.SendMessageTimeout(Proc.MainWindowHandle, Win32.WM_COPYDATA, IntPtr.Zero, CopyDataMem, Win32.SendMessageTimeoutFlags.SMTO_BLOCK | Win32.SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 5000, out Result); Marshal.FreeHGlobal(CopyData.lpData); Marshal.FreeHGlobal(CopyDataMem); } Shutdown(0); } } } public partial class Main : Window { private void Window_Loaded(object sender, RoutedEventArgs e) { HwndSource Source; Source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle); Source.AddHook(new HwndSourceHook(Window_Proc)); } private IntPtr Window_Proc(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam, ref bool Handled) { Win32.COPYDATASTRUCT CopyData; string Path; if (Msg == Win32.WM_COPYDATA) { CopyData = (Win32.COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(Win32.COPYDATASTRUCT)); Path = Marshal.PtrToStringUni(CopyData.lpData, CopyData.cbData / 2); if (WindowState == WindowState.Minimized) { // Restore window from tray } // Do whatever we want with information Activate(); Focus(); } if (Msg == App.MessageId) { Handled = true; return new IntPtr(App.MessageId); } return IntPtr.Zero; } } public class Win32 { public const uint WM_COPYDATA = 0x004A; public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; public IntPtr lpData; } [Flags] public enum SendMessageTimeoutFlags : uint { SMTO_NORMAL = 0x0000, SMTO_BLOCK = 0x0001, SMTO_ABORTIFHUNG = 0x0002, SMTO_NOTIMEOUTIFNOTHUNG = 0x0008 } [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] public static extern uint RegisterWindowMessage(string lpString); [DllImport("user32.dll")] public static extern IntPtr SendMessageTimeout( IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags fuFlags, uint uTimeout, out IntPtr lpdwResult); }
只是有些想法:有些情况下,只要有一个应用程序的实例不是“蹩脚的”,就像有些人会相信的那样。 如果允许单个用户访问数据库的应用程序的多个实例,则数据库应用程序等等的难度将更加困难(您知道,所有更新应用程序在用户的多个实例中打开的所有logging机器等)。 首先,对于名称冲突的事情,不要使用人类可读的名字,而应该使用GUID,或者更好地使用GUID +人类可读的名字。名字冲突的机会刚刚从雷达上掉下来,互斥体并不关心。正如有人指出的那样,DOS攻击会很糟糕,但是如果恶意人员已经不习惯将互斥体名称并入到应用程序中,那么无论如何您都将成为攻击目标,并且还需要做更多的事情来保护而且,如果使用new Mutex(true,“some GUID plus Name”,out AIsFirstInstance)的变体,那么您已经有了关于Mutex是否是第一个实例的指示器。
作为标记答案的参考的代码C#.NET单实例应用程序是一个很好的开始。
但是,我发现它不能很好地处理已经存在的实例已经打开模式对话框的情况,不pipe该对话框是托pipe对话框(如另一个表格,如关于框),还是非托pipe对话框即使在使用标准.NET类时也是OpenFileDialog)。 使用原始代码,主窗体被激活,但是模式窗体保持无效,这看起来很奇怪,再加上用户必须点击它才能继续使用应用程序。
所以,我创build了一个SingleInstance实用程序类来为Winforms和WPF应用程序自动处理所有这些。
Winforms :
1)像这样修改程序类:
static class Program { public static readonly SingleInstance Singleton = new SingleInstance(typeof(Program).FullName); [STAThread] static void Main(string[] args) { // NOTE: if this always return false, close & restart Visual Studio // this is probably due to the vshost.exe thing Singleton.RunFirstInstance(() => { SingleInstanceMain(args); }); } public static void SingleInstanceMain(string[] args) { // standard code that was in Main now goes here Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } }
2)像这样修改主窗口类:
public partial class Form1 : Form { public Form1() { InitializeComponent(); } protected override void WndProc(ref Message m) { // if needed, the singleton will restore this window Program.Singleton.OnWndProc(this, m, true); // TODO: handle specific messages here if needed base.WndProc(ref m); } }
WPF:
1)像这样修改App页面(并确保将其构build操作设置为页面以便能够重新定义Main方法):
public partial class App : Application { public static readonly SingleInstance Singleton = new SingleInstance(typeof(App).FullName); [STAThread] public static void Main(string[] args) { // NOTE: if this always return false, close & restart Visual Studio // this is probably due to the vshost.exe thing Singleton.RunFirstInstance(() => { SingleInstanceMain(args); }); } public static void SingleInstanceMain(string[] args) { // standard code that was in Main now goes here App app = new App(); app.InitializeComponent(); app.Run(); } }
2)像这样修改主窗口类:
public partial class MainWindow : Window { private HwndSource _source; public MainWindow() { InitializeComponent(); } protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); _source = (HwndSource)PresentationSource.FromVisual(this); _source.AddHook(HwndSourceHook); } protected virtual IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { // if needed, the singleton will restore this window App.Singleton.OnWndProc(hwnd, msg, wParam, lParam, true, true); // TODO: handle other specific message return IntPtr.Zero; }
这里是实用程序类:
using System; using System.ComponentModel; using System.Runtime.InteropServices; using System.Threading; namespace SingleInstanceUtilities { public sealed class SingleInstance { private const int HWND_BROADCAST = 0xFFFF; [DllImport("user32.dll")] private static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam); [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int RegisterWindowMessage(string message); [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd); public SingleInstance(string uniqueName) { if (uniqueName == null) throw new ArgumentNullException("uniqueName"); Mutex = new Mutex(true, uniqueName); Message = RegisterWindowMessage("WM_" + uniqueName); } public Mutex Mutex { get; private set; } public int Message { get; private set; } public void RunFirstInstance(Action action) { RunFirstInstance(action, IntPtr.Zero, IntPtr.Zero); } // NOTE: if this always return false, close & restart Visual Studio // this is probably due to the vshost.exe thing public void RunFirstInstance(Action action, IntPtr wParam, IntPtr lParam) { if (action == null) throw new ArgumentNullException("action"); if (WaitForMutext(wParam, lParam)) { try { action(); } finally { ReleaseMutex(); } } } public static void ActivateWindow(IntPtr hwnd) { if (hwnd == IntPtr.Zero) return; FormUtilities.ActivateWindow(FormUtilities.GetModalWindow(hwnd)); } public void OnWndProc(IntPtr hwnd, int m, IntPtr wParam, IntPtr lParam, bool restorePlacement, bool activate) { if (m == Message) { if (restorePlacement) { WindowPlacement placement = WindowPlacement.GetPlacement(hwnd, false); if (placement.IsValid && placement.IsMinimized) { const int SW_SHOWNORMAL = 1; placement.ShowCmd = SW_SHOWNORMAL; placement.SetPlacement(hwnd); } } if (activate) { SetForegroundWindow(hwnd); FormUtilities.ActivateWindow(FormUtilities.GetModalWindow(hwnd)); } } } #if WINFORMS // define this for Winforms apps public void OnWndProc(System.Windows.Forms.Form form, int m, IntPtr wParam, IntPtr lParam, bool activate) { if (form == null) throw new ArgumentNullException("form"); if (m == Message) { if (activate) { if (form.WindowState == System.Windows.Forms.FormWindowState.Minimized) { form.WindowState = System.Windows.Forms.FormWindowState.Normal; } form.Activate(); FormUtilities.ActivateWindow(FormUtilities.GetModalWindow(form.Handle)); } } } public void OnWndProc(System.Windows.Forms.Form form, System.Windows.Forms.Message m, bool activate) { if (form == null) throw new ArgumentNullException("form"); OnWndProc(form, m.Msg, m.WParam, m.LParam, activate); } #endif public void ReleaseMutex() { Mutex.ReleaseMutex(); } public bool WaitForMutext(bool force, IntPtr wParam, IntPtr lParam) { bool b = PrivateWaitForMutext(force); if (!b) { PostMessage((IntPtr)HWND_BROADCAST, Message, wParam, lParam); } return b; } public bool WaitForMutext(IntPtr wParam, IntPtr lParam) { return WaitForMutext(false, wParam, lParam); } private bool PrivateWaitForMutext(bool force) { if (force) return true; try { return Mutex.WaitOne(TimeSpan.Zero, true); } catch (AbandonedMutexException) { return true; } } } // NOTE: don't add any field or public get/set property, as this must exactly map to Windows' WINDOWPLACEMENT structure [StructLayout(LayoutKind.Sequential)] public struct WindowPlacement { public int Length { get; set; } public int Flags { get; set; } public int ShowCmd { get; set; } public int MinPositionX { get; set; } public int MinPositionY { get; set; } public int MaxPositionX { get; set; } public int MaxPositionY { get; set; } public int NormalPositionLeft { get; set; } public int NormalPositionTop { get; set; } public int NormalPositionRight { get; set; } public int NormalPositionBottom { get; set; } [DllImport("user32.dll", SetLastError = true)] private static extern bool SetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl); [DllImport("user32.dll", SetLastError = true)] private static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl); private const int SW_SHOWMINIMIZED = 2; public bool IsMinimized { get { return ShowCmd == SW_SHOWMINIMIZED; } } public bool IsValid { get { return Length == Marshal.SizeOf(typeof(WindowPlacement)); } } public void SetPlacement(IntPtr windowHandle) { SetWindowPlacement(windowHandle, ref this); } public static WindowPlacement GetPlacement(IntPtr windowHandle, bool throwOnError) { WindowPlacement placement = new WindowPlacement(); if (windowHandle == IntPtr.Zero) return placement; placement.Length = Marshal.SizeOf(typeof(WindowPlacement)); if (!GetWindowPlacement(windowHandle, ref placement)) { if (throwOnError) throw new Win32Exception(Marshal.GetLastWin32Error()); return new WindowPlacement(); } return placement; } } public static class FormUtilities { [DllImport("user32.dll")] private static extern IntPtr GetWindow(IntPtr hWnd, int uCmd); [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetActiveWindow(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("kernel32.dll")] public static extern int GetCurrentThreadId(); private delegate bool EnumChildrenCallback(IntPtr hwnd, IntPtr lParam); [DllImport("user32.dll")] private static extern bool EnumThreadWindows(int dwThreadId, EnumChildrenCallback lpEnumFunc, IntPtr lParam); private class ModalWindowUtil { private const int GW_OWNER = 4; private int _maxOwnershipLevel; private IntPtr _maxOwnershipHandle; private bool EnumChildren(IntPtr hwnd, IntPtr lParam) { int level = 1; if (IsWindowVisible(hwnd) && IsOwned(lParam, hwnd, ref level)) { if (level > _maxOwnershipLevel) { _maxOwnershipHandle = hwnd; _maxOwnershipLevel = level; } } return true; } private static bool IsOwned(IntPtr owner, IntPtr hwnd, ref int level) { IntPtr o = GetWindow(hwnd, GW_OWNER); if (o == IntPtr.Zero) return false; if (o == owner) return true; level++; return IsOwned(owner, o, ref level); } public static void ActivateWindow(IntPtr hwnd) { if (hwnd != IntPtr.Zero) { SetActiveWindow(hwnd); } } public static IntPtr GetModalWindow(IntPtr owner) { ModalWindowUtil util = new ModalWindowUtil(); EnumThreadWindows(GetCurrentThreadId(), util.EnumChildren, owner); return util._maxOwnershipHandle; // may be IntPtr.Zero } } public static void ActivateWindow(IntPtr hwnd) { ModalWindowUtil.ActivateWindow(hwnd); } public static IntPtr GetModalWindow(IntPtr owner) { return ModalWindowUtil.GetModalWindow(owner); } } }
So many answers to such a seemingly simple question. Just to shake things up a little bit here is my solution to this problem.
Creating a Mutex can be troublesome because the JIT-er only sees you using it for a small portion of your code and wants to mark it as ready for garbage collection. It pretty much wants to out-smart you thinking you are not going to be using that Mutex for that long. In reality you want to hang onto this Mutex for as long as your application is running. The best way to tell the garbage collector to leave you Mutex alone is to tell it to keep it alive though out the different generations of garage collection. 例:
var m = new Mutex(...); ... GC.KeepAlive(m);
I lifted the idea from this page: http://www.ai.uga.edu/~mc/SingleInstance.html
It looks like there is a really good way to handle this:
WPF Single Instance Application
This provides a class you can add that manages all the mutex and messaging cruff to simplify the your implementation to the point where it's simply trivial.
The following code is my WCF named pipes solution to register a single-instance application. It's nice because it also raises an event when another instance attempts to start, and receives the command line of the other instance.
It's geared toward WPF because it uses the System.Windows.StartupEventHandler
class, but this could be easily modified.
This code requires a reference to PresentationFramework
, and System.ServiceModel
.
用法:
class Program { static void Main() { var applicationId = new Guid("b54f7b0d-87f9-4df9-9686-4d8fd76066dc"); if (SingleInstanceManager.VerifySingleInstance(applicationId)) { SingleInstanceManager.OtherInstanceStarted += OnOtherInstanceStarted; // Start the application } } static void OnOtherInstanceStarted(object sender, StartupEventArgs e) { // Do something in response to another instance starting up. } }
Source Code:
/// <summary> /// A class to use for single-instance applications. /// </summary> public static class SingleInstanceManager { /// <summary> /// Raised when another instance attempts to start up. /// </summary> public static event StartupEventHandler OtherInstanceStarted; /// <summary> /// Checks to see if this instance is the first instance running on this machine. If it is not, this method will /// send the main instance this instance's startup information. /// </summary> /// <param name="guid">The application's unique identifier.</param> /// <returns>True if this instance is the main instance.</returns> public static bool VerifySingleInstace(Guid guid) { if (!AttemptPublishService(guid)) { NotifyMainInstance(guid); return false; } return true; } /// <summary> /// Attempts to publish the service. /// </summary> /// <param name="guid">The application's unique identifier.</param> /// <returns>True if the service was published successfully.</returns> private static bool AttemptPublishService(Guid guid) { try { ServiceHost serviceHost = new ServiceHost(typeof(SingleInstance)); NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); serviceHost.AddServiceEndpoint(typeof(ISingleInstance), binding, CreateAddress(guid)); serviceHost.Open(); return true; } catch { return false; } } /// <summary> /// Notifies the main instance that this instance is attempting to start up. /// </summary> /// <param name="guid">The application's unique identifier.</param> private static void NotifyMainInstance(Guid guid) { NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); EndpointAddress remoteAddress = new EndpointAddress(CreateAddress(guid)); using (ChannelFactory<ISingleInstance> factory = new ChannelFactory<ISingleInstance>(binding, remoteAddress)) { ISingleInstance singleInstance = factory.CreateChannel(); singleInstance.NotifyMainInstance(Environment.GetCommandLineArgs()); } } /// <summary> /// Creates an address to publish/contact the service at based on a globally unique identifier. /// </summary> /// <param name="guid">The identifier for the application.</param> /// <returns>The address to publish/contact the service.</returns> private static string CreateAddress(Guid guid) { return string.Format(CultureInfo.CurrentCulture, "net.pipe://localhost/{0}", guid); } /// <summary> /// The interface that describes the single instance service. /// </summary> [ServiceContract] private interface ISingleInstance { /// <summary> /// Notifies the main instance that another instance of the application attempted to start. /// </summary> /// <param name="args">The other instance's command-line arguments.</param> [OperationContract] void NotifyMainInstance(string[] args); } /// <summary> /// The implementation of the single instance service interface. /// </summary> private class SingleInstance : ISingleInstance { /// <summary> /// Notifies the main instance that another instance of the application attempted to start. /// </summary> /// <param name="args">The other instance's command-line arguments.</param> public void NotifyMainInstance(string[] args) { if (OtherInstanceStarted != null) { Type type = typeof(StartupEventArgs); ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null); StartupEventArgs e = (StartupEventArgs)constructor.Invoke(null); FieldInfo argsField = type.GetField("_args", BindingFlags.Instance | BindingFlags.NonPublic); Debug.Assert(argsField != null); argsField.SetValue(e, args); OtherInstanceStarted(null, e); } } } }
You should never use a named mutex to implement a single-instance application (or at least not for production code). Malicious code can easily DoS ( Denial of Service ) your ass…
Here is what I use. It combined process enumeration to perform switching and mutex to safeguard from "active clickers":
public partial class App { [DllImport("user32")] private static extern int OpenIcon(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd); protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); var p = Process .GetProcessesByName(Process.GetCurrentProcess().ProcessName); foreach (var t in p.Where(t => t.MainWindowHandle != IntPtr.Zero)) { OpenIcon(t.MainWindowHandle); SetForegroundWindow(t.MainWindowHandle); Current.Shutdown(); return; } // there is a chance the user tries to click on the icon repeatedly // and the process cannot be discovered yet bool createdNew; var mutex = new Mutex(true, "MyAwesomeApp", out createdNew); // must be a variable, though it is unused - // we just need a bit of time until the process shows up if (!createdNew) { Current.Shutdown(); return; } new Bootstrapper().Run(); } }
I found the simpler solution, similar to Dale Ragan's, but slightly modified. It does practically everything you need and based on the standard Microsoft WindowsFormsApplicationBase class.
Firstly, you create SingleInstanceController class, which you can use in all other single-instance applications, which use Windows Forms:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using Microsoft.VisualBasic.ApplicationServices; namespace SingleInstanceController_NET { public class SingleInstanceController : WindowsFormsApplicationBase { public delegate Form CreateMainForm(); public delegate void StartNextInstanceDelegate(Form mainWindow); CreateMainForm formCreation; StartNextInstanceDelegate onStartNextInstance; public SingleInstanceController(CreateMainForm formCreation, StartNextInstanceDelegate onStartNextInstance) { // Set whether the application is single instance this.formCreation = formCreation; this.onStartNextInstance = onStartNextInstance; this.IsSingleInstance = true; this.StartupNextInstance += new StartupNextInstanceEventHandler(this_StartupNextInstance); } void this_StartupNextInstance(object sender, StartupNextInstanceEventArgs e) { if (onStartNextInstance != null) { onStartNextInstance(this.MainForm); // This code will be executed when the user tries to start the running program again, // for example, by clicking on the exe file. } // This code can determine how to re-activate the existing main window of the running application. } protected override void OnCreateMainForm() { // Instantiate your main application form this.MainForm = formCreation(); } public void Run() { string[] commandLine = new string[0]; base.Run(commandLine); } } }
Then you can use it in your program as follows:
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using SingleInstanceController_NET; namespace SingleInstance { static class Program { /// <summary> /// The main entry point for the application. /// </summary> static Form CreateForm() { return new Form1(); // Form1 is used for the main window. } static void OnStartNextInstance(Form mainWindow) // When the user tries to restart the application again, // the main window is activated again. { mainWindow.WindowState = FormWindowState.Maximized; } [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); SingleInstanceController controller = new SingleInstanceController(CreateForm, OnStartNextInstance); controller.Run(); } } }
Both the program and the SingleInstanceController_NET solution should reference Microsoft.VisualBasic . If you just want to reactivate the running application as a normal window when the user tries to restart the running program, the second parameter in the SingleInstanceController can be null. In the given example, the window is maximized.
Look at the folllowing code. It is a great and simple solution to prevent multiple instances of a WPF application.
private void Application_Startup(object sender, StartupEventArgs e) { Process thisProc = Process.GetCurrentProcess(); if (Process.GetProcessesByName(thisProc.ProcessName).Length > 1) { MessageBox.Show("Application running"); Application.Current.Shutdown(); return; } var wLogin = new LoginWindow(); if (wLogin.ShowDialog() == true) { var wMain = new Main(); wMain.WindowState = WindowState.Maximized; wMain.Show(); } else { Application.Current.Shutdown(); } }
Not using Mutex though, simple answer:
System.Diagnostics; ... string thisprocessname = Process.GetCurrentProcess().ProcessName; if (Process.GetProcesses().Count(p => p.ProcessName == thisprocessname) > 1) return;
Put it inside the Program.Main()
.
例如 :
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; using System.Diagnostics; namespace Sample { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { //simple add Diagnostics namespace, and these 3 lines below string thisprocessname = Process.GetCurrentProcess().ProcessName; if (Process.GetProcesses().Count(p => p.ProcessName == thisprocessname) > 1) return; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Sample()); } } }
You can add MessageBox.Show
to the if
-statement and put "Application already running".
This might be helpful to someone.
Update 2017-01-25. After trying few things, I decided to go with VisualBasic.dll it is easier and works better (at least for me). I let my previous answer just as reference…
Just as reference, this is how I did without passing arguments (which I can't find any reason to do so… I mean a single app with arguments that as to be passed out from one instance to another one). If file association is required, then an app should (per users standard expectation) be instanciated for each doc. If you have to pass args to existing app, I think I would used vb dll.
Not passing args (just single instance app), I prefer not registering a new Window message and not override the message loop as defined in Matt Davis Solution. Although it's not a big deal to add a VisualBasic dll, but I prefer not add a new reference just to do single instance app. Also, I do prefer instanciate a new class with Main instead of calling Shutdown from App.Startup override to ensure to exit as soon as possible.
In hope that anybody will like it… or will inspire a little bit 🙂
Project startup class should be set as 'SingleInstanceApp'.
public class SingleInstanceApp { [STAThread] public static void Main(string[] args) { Mutex _mutexSingleInstance = new Mutex(true, "MonitorMeSingleInstance"); if (_mutexSingleInstance.WaitOne(TimeSpan.Zero, true)) { try { var app = new App(); app.InitializeComponent(); app.Run(); } finally { _mutexSingleInstance.ReleaseMutex(); _mutexSingleInstance.Close(); } } else { MessageBox.Show("One instance is already running."); var processes = Process.GetProcessesByName(Assembly.GetEntryAssembly().GetName().Name); { if (processes.Length > 1) { foreach (var process in processes) { if (process.Id != Process.GetCurrentProcess().Id) { WindowHelper.SetForegroundWindow(process.MainWindowHandle); } } } } } } }
WindowHelper:
using System; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; using System.Windows.Threading; namespace HQ.Util.Unmanaged { public class WindowHelper { [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetForegroundWindow(IntPtr hWnd);
Use mutex solution:
using System; using System.Windows.Forms; using System.Threading; namespace OneAndOnlyOne { static class Program { static String _mutexID = " // generate guid" /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Boolean _isNotRunning; using (Mutex _mutex = new Mutex(true, _mutexID, out _isNotRunning)) { if (_isNotRunning) { Application.Run(new Form1()); } else { MessageBox.Show("An instance is already running."); return; } } } } }
Here's a lightweight solution I use which allows the application to bring an already existing window to the foreground without resorting to custom windows messages or blindly searching process names.
[DllImport("user32.dll")] static extern bool SetForegroundWindow(IntPtr hWnd); static readonly string guid = "<Application Guid>"; static void Main() { Mutex mutex = null; if (!CreateMutex(out mutex)) return; // Application startup code. Environment.SetEnvironmentVariable(guid, null, EnvironmentVariableTarget.User); } static bool CreateMutex(out Mutex mutex) { bool createdNew = false; mutex = new Mutex(false, guid, out createdNew); if (createdNew) { Process process = Process.GetCurrentProcess(); string value = process.Id.ToString(); Environment.SetEnvironmentVariable(guid, value, EnvironmentVariableTarget.User); } else { string value = Environment.GetEnvironmentVariable(guid, EnvironmentVariableTarget.User); Process process = null; int processId = -1; if (int.TryParse(value, out processId)) process = Process.GetProcessById(processId); if (process == null || !SetForegroundWindow(process.MainWindowHandle)) MessageBox.Show("Unable to start application. An instance of this application is already running."); } return createdNew; }
Edit: You can also store and initialize mutex and createdNew statically, but you'll need to explicitly dispose/release the mutex once you're done with it. Personally, I prefer keeping the mutex local as it will be automatically disposed of even if the application closes without ever reaching the end of Main.
You can also use the CodeFluent Runtime which is free set of tools. It provides a SingleInstance class to implement a single instance application.
I added a sendMessage Method to the NativeMethods Class.
Apparently the postmessage method dosent work, if the application is not show in the taskbar, however using the sendmessage method solves this.
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.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); [DllImport("user32")] public static extern int RegisterWindowMessage(string message); }
Usually whenever we execute an .exe, every time it creates a separate windows process with its own address space, resources and so on. But we do not want this criteria as this would prevent us from creating single process. Single instance applications can be created using the Mutex in C# which is discussed in this article
Moreover if we want to bring the application on top we can do it using
[DllImport("user32")] static extern IntPtr SetForegroundWindow(IntPtr hWnd);
Normally, this is the code I use for single-instance Windows Forms applications:
[STAThread] public static void Main() { String assemblyName = Assembly.GetExecutingAssembly().GetName().Name; using (Mutex mutex = new Mutex(false, assemblyName)) { if (!mutex.WaitOne(0, false)) { Boolean shownProcess = false; Process currentProcess = Process.GetCurrentProcess(); foreach (Process process in Process.GetProcessesByName(currentProcess.ProcessName)) { if (!process.Id.Equals(currentProcess.Id) && process.MainModule.FileName.Equals(currentProcess.MainModule.FileName) && !process.MainWindowHandle.Equals(IntPtr.Zero)) { IntPtr windowHandle = process.MainWindowHandle; if (NativeMethods.IsIconic(windowHandle)) NativeMethods.ShowWindow(windowHandle, ShowWindowCommand.Restore); NativeMethods.SetForegroundWindow(windowHandle); shownProcess = true; } } if (!shownProcess) MessageBox.Show(String.Format(CultureInfo.CurrentCulture, "An instance of {0} is already running!", assemblyName), assemblyName, MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1, (MessageBoxOptions)0); } else { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form()); } } }
Where native components are:
[DllImport("User32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern Boolean IsIconic([In] IntPtr windowHandle); [DllImport("User32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern Boolean SetForegroundWindow([In] IntPtr windowHandle); [DllImport("User32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern Boolean ShowWindow([In] IntPtr windowHandle, [In] ShowWindowCommand command); public enum ShowWindowCommand : int { Hide = 0x0, ShowNormal = 0x1, ShowMinimized = 0x2, ShowMaximized = 0x3, ShowNormalNotActive = 0x4, Minimize = 0x6, ShowMinimizedNotActive = 0x7, ShowCurrentNotActive = 0x8, Restore = 0x9, ShowDefault = 0xA, ForceMinimize = 0xB }
Here is a solution:
Protected Overrides Sub OnStartup(e As StartupEventArgs) Const appName As String = "TestApp" Dim createdNew As Boolean _mutex = New Mutex(True, appName, createdNew) If Not createdNew Then 'app is already running! Exiting the application MessageBox.Show("Application is already running.") Application.Current.Shutdown() End If MyBase.OnStartup(e) End Sub
Here's the same thing implemented via Event.
public enum ApplicationSingleInstanceMode { CurrentUserSession, AllSessionsOfCurrentUser, Pc } public class ApplicationSingleInstancePerUser: IDisposable { private readonly EventWaitHandle _event; /// <summary> /// Shows if the current instance of ghost is the first /// </summary> public bool FirstInstance { get; private set; } /// <summary> /// Initializes /// </summary> /// <param name="applicationName">The application name</param> /// <param name="mode">The single mode</param> public ApplicationSingleInstancePerUser(string applicationName, ApplicationSingleInstanceMode mode = ApplicationSingleInstanceMode.CurrentUserSession) { string name; if (mode == ApplicationSingleInstanceMode.CurrentUserSession) name = $"Local\\{applicationName}"; else if (mode == ApplicationSingleInstanceMode.AllSessionsOfCurrentUser) name = $"Global\\{applicationName}{Environment.UserDomainName}"; else name = $"Global\\{applicationName}"; try { bool created; _event = new EventWaitHandle(false, EventResetMode.ManualReset, name, out created); FirstInstance = created; } catch { } } public void Dispose() { _event.Dispose(); } }
This is how I ended up taking care of this issue. Note that debug code is still in there for testing. This code is within the OnStartup in the App.xaml.cs file. (WPF)
// Process already running ? if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1) { // Show your error message MessageBox.Show("xxx is already running. \r\n\r\nIf the original process is hung up you may need to restart your computer, or kill the current xxx process using the task manager.", "xxx is already running!", MessageBoxButton.OK, MessageBoxImage.Exclamation); // This process Process currentProcess = Process.GetCurrentProcess(); // Get all processes running on the local computer. Process[] localAll = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName); // ID of this process... int temp = currentProcess.Id; MessageBox.Show("This Process ID: " + temp.ToString()); for (int i = 0; i < localAll.Length; i++) { // Find the other process if (localAll[i].Id != currentProcess.Id) { MessageBox.Show("Original Process ID (Switching to): " + localAll[i].Id.ToString()); // Switch to it... SetForegroundWindow(localAll[i].MainWindowHandle); } } Application.Current.Shutdown(); }
This may have issues that I have not caught yet. If I run into any I'll update my answer.
Here is my 2 cents
static class Program { [STAThread] static void Main() { bool createdNew; using (new Mutex(true, "MyApp", out createdNew)) { if (createdNew) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); var mainClass = new SynGesturesLogic(); Application.ApplicationExit += mainClass.tray_exit; Application.Run(); } else { var current = Process.GetCurrentProcess(); foreach (var process in Process.GetProcessesByName(current.ProcessName).Where(process => process.Id != current.Id)) { NativeMethods.SetForegroundWindow(process.MainWindowHandle); break; } } } } }
I like a solution to allow multiple Instances, if the exe is called from an other path. I modified CharithJ solution Method 1:
static class Program { [DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow); [DllImport("User32.dll")] public static extern Int32 SetForegroundWindow(IntPtr hWnd); [STAThread] static void Main() { Process currentProcess = Process.GetCurrentProcess(); foreach (var process in Process.GetProcesses()) { try { if ((process.Id != currentProcess.Id) && (process.ProcessName == currentProcess.ProcessName) && (process.MainModule.FileName == currentProcess.MainModule.FileName)) { ShowWindow(process.MainWindowHandle, 5); // const int SW_SHOW = 5; //Activates the window and displays it in its current size and position. SetForegroundWindow(process.MainWindowHandle); return; } } catch (Exception ex) { //ignore Exception "Access denied " } } Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } }