在开发应用程序时,经常需要确保同一时间只有一个实例在运行。这不仅可以防止资源的浪费,还可以避免数据的冲突和不一致。本文将介绍一种使用Mutex和Remoting技术来实现WinForm应用程序单实例运行的方法。
为什么需要另一种单实例实现方法?这是因为在尝试将Michael Potter的实现方法应用于一个最小化到资源管理器状态栏的应用程序时遇到了问题。这里提出的解决方案使用Mutex来检测已经运行的实例,并通过Remoting来通知新实例的启动。
要使用这个组件,首先需要将其添加到工具箱中。然后,可以将组件拖放到表单上,它会显示在组件托盘中。下图展示了SingleInstance组件的属性(事件)。
对于某些应用程序来说,安装一个InstanceActivate处理器可能是有用的。每次启动第二个实例时,都会调用该处理器。作为额外的好处,事件参数还包含传递给第二个实例的命令行参数。
private void singleInstance1_InstanceActivate(object sender, rr.Windows.Forms.SingleInstance.InstanceActivateEventArgs e)
{
foreach (string s in e.CommandLineArgs)
{
Debug.WriteLine(s);
}
}
组件在InstanceActivate事件后的默认行为是将第一个实例带到前台。要防止这种情况,必须将Cancel属性设置为true。
e.Cancel = true;
在XP上测试组件时,使用不同的用户帐户,当一个测试应用程序的实例已经在标准帐户下运行时,开始收到“通常只允许每个套接字地址(协议/网络地址/端口)使用一次”的错误。开始意识到使用固定端口号是行不通的,所以提供了0让通道获取一个空闲的端口号。
TcpChannel chan = new TcpChannel(0);
但现在的问题是客户端无法连接到服务器,因为它不知道服务器正在监听的端口号。在考虑了几种不同的方法后,最终决定使用HKEY_CURRENT_USER注册表项。
另一个让有点不安的实现细节是,使用了Process.GetCurrentProcess().Kill();在表单的InitializeComponent函数中间来终止第二个实例。需要在进程被杀死之前运行代码的实现可能会钩住InstanceShutdown事件。