C#預設的WinForm模板是不支援設定單例項的,也沒有隔壁大哥VB.NET那樣有個“生成單個例項應用程式”的勾選選項(VB某些時候要比C#更方便),實現單例項可以有多種方法:
- 檢測同名程序:Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName),如果集合的Length > 1那就表明已有同名程序了,如果有需要還可以進一步檢查該程序的路徑;
- 命名互斥鎖:Mutex,網上介紹的很多都是這種方法;
- 鎖定檔案:使用File.Create方法建立檔案並在程式退出時釋放,如果建立失敗則表明已經有例項在執行;
- VB.NET方法:WindowsFormsApplicationBase,個人認為該方法最完美,可以接收後續程序的啟動引數,還可以彈出前序程序的主窗體。
WindowsFormsApplicationBase是一個Microsoft.VisualBasic.ApplicationServices名稱空間下的類,是微軟為VB.NET實現應用程式啟動控制的類,其內部是以命名管道通訊來實現的。既然是同一個爹的東西,C#拿過來用毫無違和感。Microsoft.VisualBasic和Microsoft.CSharp一樣,都是.NET Framework中的一部分,不用擔心會缺少執行環境。
WindowsFormsApplicationBase類的一些常用屬性和方法:
- 屬性IsSingleInstance:設定當前程序是否為單例項程序,在構造方法中設定,如果是後續程序且為值true,構造方法結束後會給前序程序傳送啟動引數,然後就退出程序了,不會執行到下面的OnStartup;
- 方法OnStartup:首次啟動後執行,返回false就會退出程序,後續程序永遠不會執行到該方法;
- 方法OnStartupNextInstance:後續程序啟動後的重寫方法,前序程序會接收到後續程序的啟動引數,彈出主窗體等;
- 方法OnCreateMainForm:建立主窗體的重寫方法,必須指定主窗體。
建立一個單例項應用程式並響應後續程序引數的大概過程:
- 建立一個專案名稱為“SingleInstanceSample”的Windows窗體專案;
- 新增引用“Microsoft.VisualBasic”;
- 重新命名“Form1”為“MainForm”;
- 新增類“ApplicationBase.cs”,繼承自“WindowsFormsApplicationBase”;
- 修改“Program.cs”,從“ApplicationBase”啟動。
各個類的程式碼如下:
- Program.cs
1 using System; 2 using System.Windows.Forms; 3 4 namespace SingleInstanceSample 5 { 6 internal static class Program 7 { 8 [STAThread] 9 static void Main(string[] args) 10 { 11 Application.EnableVisualStyles(); 12 Application.SetCompatibleTextRenderingDefault(false); 13 14 var app = new ApplicationBase(); 15 app.Run(args); 16 } 17 } 18 }
- ApplicationBase.cs
1 using Microsoft.VisualBasic.ApplicationServices; 2 using System.IO; 3 4 namespace SingleInstanceSample 5 { 6 internal class ApplicationBase : WindowsFormsApplicationBase 7 { 8 public ApplicationBase() : base(AuthenticationMode.Windows) 9 { 10 //指示程序為單程序:IsSingleInstance 11 base.IsSingleInstance = true; 12 base.SaveMySettingsOnExit = true; 13 base.ShutdownStyle = ShutdownMode.AfterMainFormCloses; 14 } 15 16 /// <summary> 17 /// 首次啟動後的重寫方法,返回false就會退出程序, 18 /// 比如可以顯示登入窗體,登入失敗返回false就不會執行到OnCreateMainForm 19 /// </summary> 20 protected override bool OnStartup(StartupEventArgs eventArgs) 21 { 22 base.OnStartup(eventArgs); 23 24 //處理當前程序的啟動引數 25 26 return true; 27 } 28 29 /// <summary> 30 /// 後續程序啟動後的重寫方法 31 /// </summary> 32 protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) 33 { 34 base.OnStartupNextInstance(eventArgs); 35 36 //處理後續程序的啟動引數 37 } 38 39 /// <summary> 40 /// 指定主窗體, 41 /// 除非OnStartup返回false,否則必須指定主窗體 42 /// </summary> 43 protected override void OnCreateMainForm() 44 { 45 base.MainForm = new MainForm(); 46 } 47 } 48 }