背景
在編寫windows桌面應用程序時,如果我們沒有特別處理,我們是可以打開多個應用程序實例的。例如,我們在同一台機器上掛打開多個QQ程序,也可以打開多個浏覽器窗口。但有些應用程序,卻只運行單個實例運行,如Outlook,MSN等。那麼如何實現單實例應用程序呢?下面介紹三種方法。
方法一,掃描進程
這是最容易想到的方法,實現起來也比較簡單。掃描進程的代碼如下,假設應用程序名稱為MySingleInstance.exe。 www.2cto.com
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的構造函數簽名:Mutex(bool initiallyOwned, string name, out bool createdNew),其中createdNew表示十分已經存在相同名稱的Mutex,如果存在createdNew為false,沒有則為true。利用該值可以判斷應用程序的實例是否已經被創建。但在createdNew為false的情況時,還是需要方法一,來激活已創建的實例窗口。其實是有Mutex沒有減少創建單實例的復雜度,反而更復雜了,而且創建的Mutex對象也不再使用,創建該對象也比較耗資源,該方法一般不會采用。
方法三,Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
當然我們有更加簡單,更加專業的方法--使用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