所谓单实例应用程序就是只能开启一个进程的应用程序,通常未做处理的WPF程序可以多次点击exe程序,每次点击,系统都会分配一个进程。这样不仅造成了资源的浪费还会导致其他各种问题,例如,我们的程序里面寄宿了一个WCF接口,那多次启动会导致端口绑定错误。为了让大家对此有个更加深刻的印象,下面做个简单的演示。
1、创建一个简单的WPF应用程序,没做任何处理。如下图所示:
2、不采用调试模式,打开项目根目录下的bin/Debug,直接点击WPF.SimpleApp.exe运行程序,可以看到程序正常运行,那么现在试试点击多次,然后打开任务管理器,看看。如下图:
结果就是,我打开了三个WPF.SimpleApp.exe,同时存在三个WPF.SimpleApp.exe进程。
好了,现在要做的就是做个限制,无论用户点击多少次,始终运行一个exe,同时只能存在一个exe进程。废话不多说,下面进入正题。
在这之前,因为本人还是比较喜欢winform的启动方式,因此我把创建项目时自动生成的App.xaml删除,新增了个Program.cs文件,代码如下:
using System; using System.Windows; namespace WPF.SimpleApp { class Program { [STAThread] static void Main(string[] args) { Application app = new Application(); MainWindow win = new MainWindow(); app.Run(win); } } }
说明:WPF的启动方式不止这一种,感兴趣的可以自行百度。
下面进入正题
1、使用System.Threading.Mutex,Mutex是一个同步基元,也可用于进程间同步。代码如下:
using System; using System.Windows; namespace WPF.SimpleApp { class Program { const string GlobalMutexName = "WPF.SimpleApp.Mutex"; [STAThread] static void Main(string[] args) { System.Threading.Mutex mutex = null; bool isExists = System.Threading.Mutex.TryOpenExisting(GlobalMutexName,out mutex); if(isExists && null != mutex) { //表示互斥体已经存在,即已经打开了一个程序,这里提示用户 MessageBox.Show("程序已经在运行"); return; } else { //否则创建新的互斥体 mutex = new System.Threading.Mutex(true, GlobalMutexName); } Application app = new Application(); MainWindow win = new MainWindow(); app.Run(win); //程序关闭,记得释放所占用资源 if (null != mutex) { mutex.Dispose(); } } } }
运行效果:
可以看到,当打开一个应用程序之后,再次点击exe,会提示“程序已经在运行”。关闭程序之后,再次打开(第一次正常,之后提示一样)。
2、使用Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase包装。
首先添加对程序集:Microsoft.VisualBasic 的引用,如下图:
然后添加一个SingleWarpInstanceApp类,并继承Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase类,然后重新方法OnStartup和OnStartupNextInstance。
实现如下:
public class SingleWarpInstanceApp : Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase { public SingleWarpInstanceApp() { this.IsSingleInstance = true; } protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs eventArgs) { Application app = new Application(); MainWindow win = new MainWindow(); app.Run(win); bool tag = base.OnStartup(eventArgs); return tag; } protected override void OnStartupNextInstance(Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs eventArgs) { MessageBox.Show("程序已经在运行"); } }
在Program启动方法里面加上如下代码:
SingleWarpInstanceApp app = new SingleWarpInstanceApp(); app.Run(args);
运行效果一样。
最后贴上Program.cs的代码:
using System; using System.Windows; namespace WPF.SimpleApp { class Program { const string GlobalMutexName = "WPF.SimpleApp.Mutex"; [STAThread] static void Main(string[] args) { #region 第一种方法 //System.Threading.Mutex mutex = null; //bool isExists = System.Threading.Mutex.TryOpenExisting(GlobalMutexName, out mutex); //if (isExists && null != mutex) //{ // //表示互斥体已经存在,即已经打开了一个程序,这里提示用户 // MessageBox.Show("程序已经在运行"); // return; //} //else //{ // //否则创建新的互斥体 // mutex = new System.Threading.Mutex(true, GlobalMutexName); //} //Application app = new Application(); //MainWindow win = new MainWindow(); //app.Run(win); ////程序关闭,记得释放所占用资源 //if (null != mutex) //{ // mutex.Dispose(); //} #endregion #region 第二种方法 SingleWarpInstanceApp app = new SingleWarpInstanceApp(); app.Run(args); #endregion } } public class SingleWarpInstanceApp : Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase { public SingleWarpInstanceApp() { this.IsSingleInstance = true; } protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs eventArgs) { Application app = new Application(); MainWindow win = new MainWindow(); app.Run(win); bool tag = base.OnStartup(eventArgs); return tag; } protected override void OnStartupNextInstance(Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs eventArgs) { MessageBox.Show("程序已经在运行"); } } }
至此,完毕。