在编写windows桌面应用程序时,如果我们没有特别处理,我们是可以打开多个应用程序实例的。例如,我们在同一台机器上挂打开多个QQ程序,也可以打开多个浏览器窗口。但有些应用程序,却只运行单个实例运行,如Outlook,MSN等。那么如何实现单实例应用程序呢?下面介绍三种方法。
这是最容易想到的方法,实现起来也比较简单。扫描进程的代码如下,假设应用程序名称为MySingleInstance.exe。
Process[] processes = Process.GetProcessesByName("MySingleInstance"); // no ".exe"
if (processes.Length > 1) {
MessageBox.Show("Another instance is running.");
return;
}
简单几行代码就可以实现单例应用程序了,只是稍微有些不够友好,因为当试图打开第二个实例时会弹出一个不够友好的对话框“Another instance is running.”,但如果我们把这行代码去掉后,又缺少了用户的交互。因此我们可以安装MSN或OUTLOOK的方式--激活正在运行的实例。
这需要调用WINDOWS API,如下代码:
Process[] processes = Process.GetProcessesByName("MySingleInstance");
if (processes.Length > 1) {
IntPtr hwnd = processes[0].MainWindowHandle;
// NOTE: ensure the first intance handle selected
if (Process.GetCurrentProcess().MainWindowHandle == hwnd) {
hwnd = processes[1].MainWindowHandle;
}
long style = GetWindowLong(hwnd, GWL_STYLE);
if ((style & WS_MINIMIZE) == WS_MINIMIZE) {
ShowWindow(hwnd, SW_SHOWNOACTIVATE);
}
SetForegroundWindow(hwnd);
return;
}
使用的WINDOWS API的声明,如下:
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hwnd);
[DllImport("user32.dll")]
private static extern long GetWindowLong(IntPtr hwnd, int nIndex);
private const int SW_SHOWNOACTIVATE = 4;
const int GWL_STYLE = -16;
const long WS_MINIMIZE = 0x20000000L;
完整的代码键附近中Program1.cs
如果你觉得扫描进程比较“笨拙”的话,那么有一个稍微专业一点的做法,使用互斥量Mutex。如果有多线程开发经验的,都应该使用过Mutex,该类比较可以实现线程的同步,而且是可以对其命名,并且是跨进程的。Mutex的构造函数签名:Mutex(bool initiallyOwned, string name, out bool createdNew),其中createdNew表示十分已经存在相同名称的Mutex,如果存在createdNew为false,没有则为true。利用该值可以判断应用程序的实例是否已经被创建。但在createdNew为false的情况时,还是需要方法一,来激活已创建的实例窗口。其实是有Mutex没有减少创建单实例的复杂度,反而更复杂了,而且创建的Mutex对象也不再使用,创建该对象也比较耗资源,该方法一般不会采用。
当然我们有更加简单,更加专业的方法--使用Microsoft提供的接口--WindowsFormsApplicationBase。Ms提供了Application基类,并且提供了IsSingleInstance的属性,该类位于命名空间Microsoft.VisualBasic.ApplicationServices下,必须添加Microsoft.VisualBasic.dll的引用。我们要做的就是实现该类,并且设置属性IsSingleInstance=True。实现代码:
internal sealed class MySingleInstanceApplication : WindowsFormsApplicationBase {
public MySingleInstanceApplication() {
base.IsSingleInstance = true;
base.EnableVisualStyles = true;
}
protected override void OnCreateMainForm() {
this.MainForm = new Form1();
}
}
该类的使用,同Application类基本相同,并且看上去更加简洁。
[STAThread]
static void Main(string[] args) {
MySingleInstanceApplication app = new MySingleInstanceApplication();
app.Run(args);
}
运行效果同方法一,二相同,关键是代码更简洁,面向对象。完整代码见Program3.cs