不少应用程序有单一实例的需求,也就是同时只能开启一个实例(一般也就是一个进程)。

实现的方式可能有判断进程名字,使用特殊文件等等,但是最靠谱的方式还是使用系统提供的 Mutex 工具。

Mutex是互斥体,命名的互斥体可以跨进程使用,所以可以用以实现程序单一实例这个需求。相关的例子网上应该不少,不过很多给出的例子中并没有注意到一些细节,这里就完整总结下。

命名Permalink

Mutex 需要一个名字,这个名字需要唯一,一般的方式是使用一个固定的 GUID 作为名字。

对于 .NET 应用,可以通过 Assembly 上的GuidAttribute来获取。默认情况下建立工程的时候 VS 就会生成一个 GUID 给 Assembly,这样无需自己再生成一个 GUID 来使用。

另外,为了调试方面,最好给 GUID 加一个便于人识别的前缀,一般就是程序的名字。这样使用一些查看系统对象的工具时,可以方便找到这个 Mutex。

var guidAttr = (GuidAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(),
typeof(GuidAttribute));
var key = string.Format("MyApp-}", guidAttr.Value);
_mutex = new Mutex(true, key);

判断Permalink

一般在程序启动的代码中进行判断,判断的方式是使用 Mutex 上的WaitOne方法。但是有两点需要注意:

  1. 程序异常退出,WaitOne 会抛出AbandonedMutexException异常,需要处理。
  2. 如果程序使用了Application.Restart来重新启动,就需要 WaitOne 等待更长的时间。这是因为Application.Restart会在程序退出前启动新程序实例,需要等待原程序完全退出释放 Mutex。
try
{
return _mutex.WaitOne(TimeSpan.FromSeconds(1), true);
}
catch (AbandonedMutexException ex)
{
if (ex.Mutex != null)
ex.Mutex.ReleaseMutex();
return true;
}

返回true则可以正常启动,否则程序已在运行。

释放Permalink

在程序退出时需要释放 Mutex。

_mutex.ReleaseMutex();

通知Permalink

有些场景下,如果应用已在运行,用户再启动应用时,需要将已在运行的应用显示给用户。如果应用已经有自己的进程间通讯方式,那就可以直接利用,如果没有,则可以使用 Windows 系统的消息广播。

P/Invoke 定义:

public const int HWND_BROADCAST = 0xffff;

[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32")]
public static extern bool SendMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);

程序启动时注册消息:

_showMeMessage = RegisterWindowMessage(key);

判断程序已运行时广播消息:

PostMessage((IntPtr)NativeMethods.HWND_BROADCAST,
_showMeMessage,
IntPtr.Zero,
IntPtr.Zero);

处理消息循环,显示已运行的实例(WinForms 版本):

protected override void WndProc(ref Message m) {
if (m.Msg == _showMeMessage) {
if (form.WindowState == FormWindowState.Minimized)
form.WindowState = FormWindowState.Normal; if (!form.Visible)
form.Show(); var top = form.TopMost;
form.TopMost = true;
form.TopMost = top;
}
base.WndProc(ref m);
}

参考:http://sanity-free.org/143/csharp_dotnet_single_instance_application.html

最新文章

  1. winxp计算机管理中服务详解
  2. 【转载】MATLB绘图
  3. 本机搭建外网web服务器
  4. Scala中的match(模式匹配)
  5. (转)ASP.NET(C#) 读取EXCEL ——另加解决日期问题
  6. VirtualBox single usermode boot
  7. iOS NSString类中获取子字符串
  8. openjdk7之编译和debug
  9. Go之十大经典排序算法
  10. C语言之控制语言:分支和跳转
  11. vue怎么引入外网json文件
  12. PowerDesigner 16.5 使用VBScript脚本从Excel导入物理数据模型
  13. C-Lodop打印服务没启动怎么办
  14. docker 容器内启动 sshd 启动报错
  15. Dart编程语言入门
  16. java基础 (二)之HashMap,HashTable,ConcurrentHashMap区别
  17. 51nod 1437 迈克步(单调栈)
  18. 2007-10的PWX OracleCdc问题解答
  19. 泊松分布E(X^2)
  20. 桶排序与快速排序算法结合-python实现

热门文章

  1. 实验Complex
  2. APP的功能分类及打包与发布的分类方式
  3. 初探flow.js
  4. JavaSE_XMind总结
  5. condition实现原理
  6. cg教程
  7. 下面我将随机抽取一名幸运女生,XXXXX
  8. [转]Add Bootstrap Glyphicon to Input Box
  9. html空白文字宽度
  10. redis操作基本命令