C#创建单实例应用程序

先看原文,后面简单翻译一下:Creating a Single Instance Application in C#

Sometimes, it's desirable to ensure that there is only ever one instance of your application running at any given time. Take Windows Live Messenger for instance - if you try to launch it whilst it is already running, it will just bring itself to the foreground instead.

Unfortunately, a lot of people try to recreate this behavior by simply checking if a process with the same name is currently running. As K. Scott Allen explains, this is not a good idea. The correct way to implement a single instance application, is to use a named mutex.

The word mutex is short for mutual exclusion, and is a synchronisation object that can only be owned by a single thread at any given time. Specifying a name for the mutex is optional - an unnamed mutex is scoped to the current process, while a named one is associated with an operating system object and can thus be used for interprocess synchronisation. Quite simply then, we can launch our application like this:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> [STAThread]
static void Main()
{
bool createdNew = true ;
using (Mutexmutex = new Mutex( true , " MyApplicationName " , out createdNew))
{
if (createdNew)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(
false );
Application.Run(
new FrmMain());
}
}
}

That ensures that there's only a single instance of our application running. Now, the above code just 'does nothing' if the application is already running - it would be nice if it instead tried to give the main window focus. To do this, we need to find the process instance, and then pinvoke the SetForeGroundWindow method of the Win32 API. Our final Main method then looks like this:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> [DllImport( " user32.dll " )]
[
return :MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtrhWnd);

/// <summary>
/// Themainentrypointfortheapplication.
/// </summary>
[STAThread]
static void Main()
{
bool createdNew = true ;
using (Mutexmutex = new Mutex( true , " MyApplicationName " , out createdNew))
{
if (createdNew)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(
false );
Application.Run(
new FrmMain());
}
else
{
Processcurrent
= Process.GetCurrentProcess();
foreach (Processprocess in Process.GetProcessesByName(current.ProcessName))
{
if (process.Id != current.Id)
{
SetForegroundWindow(process.MainWindowHandle);
break ;
}
}
}
}
}

这篇文章说,很多人通过简单地检查正在运行的进程名(通过for循环,请自行搜索其他文章,已有很多例子)来判断自己的程序是否在运行,这不是一个好办法。正确的做法是使用Mutex类,Mutex就是互斥的意思。

作者首先给出了互斥的代码(没有必要使用Mutex.WaitOne()方法) ,作者使用了using来释放资源。最后作者引入了Win32 API来让窗体重新获得焦点。

这个例子没有完全达到我们所预期的功能,当运行一个实例并最小化,再次运行这个实例时,窗口仅获得焦点,并不会恢复,在SetForegroundWindow(process.MainWindowHandle);后加入一行代码就可以搞定了,需要使用Win32 API,最终代码如下:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;

namespace WinApp
{
static class Program
{
[DllImport(
" user32.dll " )]
[
return :MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtrhWnd);
[DllImport(
" user32.dll " )]
private static extern bool ShowWindowAsync(IntPtrhWnd, int nCmdShow);
private const int SW_HIDE = 0 ; // 隐藏窗口,活动状态给令一个窗口
private const int SW_SHOWNORMAL = 1 ; // 用原来的大小和位置显示一个窗口,同时令其进入活动状态
private const int SW_SHOWMINIMIZED = 2 ; // 最小化窗口,并将其激活
private const int SW_SHOWMAXIMIZED = 3 ; // 最大化窗口,并将其激活
private const int SW_SHOWNOACTIVATE = 4 ; // 用最近的大小和位置显示一个窗口,同时不改变活动窗口
private const int SW_RESTORE = 9 ; // 用原来的大小和位置显示一个窗口,同时令其进入活动状态
private const int SW_SHOWDEFAULT = 10 ; // 根据默认创建窗口时的样式来显示

/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
bool createdNew = true ;
using (Mutexmutex = new Mutex( true , " MyApplicationName " , out createdNew))
{
if (createdNew)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(
false );
Application.Run(
new FrmMain());
}
else
{
Processcurrent
= Process.GetCurrentProcess();
foreach (Processprocess in Process.GetProcessesByName(current.ProcessName))
{
if (process.Id != current.Id)
{
SetForegroundWindow(process.MainWindowHandle);
ShowWindowAsync(process.MainWindowHandle,SW_RESTORE);
break ;
}
}
}
}
}
}
}

你可能感兴趣的:(应用程序)