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

实现的方式可能有判断进程名字,使用特殊文件等等,但是最靠谱的方式还是使用系统提供的 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

程序单一实例实现 z的更多相关文章

  1. WPF:实现主应用程序单一实例运行方式总结

       本文介绍常见的实现主应用程序单一实例运行的几种方式. 方式一: public partial class App : Application { protected override void ...

  2. Qt实现应用程序单实例运行--LocalServer方式

    使Qt应用程序能够单实例运行的典型实现方法是使用共享内存实现.该方法实现简单,代码简洁. 但有一个致命缺陷:共享内存(QSharedMemory)实现的单程序运行,当运行环境是UNIX时,并且程序不幸 ...

  3. 微信小程序web-view实例

    微信小程序web-view实例 index.js //index.js //获取应用实例 const app = getApp() Page({ /** * 页面的初始数据 */ data: { }, ...

  4. asp.net mvc 学习笔记 - 单一实例设计模式

    学习之前,先喊一下口号:每天进步一点,生活更好一点 首先声明一点,我也是新新新手一枚,崭新的新哦.如果文章有不合理的地方,也请各位博友多多指点,不要乱喷哦 我的文采很低调,低调到语文老师对我的期望是你 ...

  5. 计算机必知必会:进程process与线程thread 进程定义为一个正在运行的程序的实例

    http://www.nowamagic.net/librarys/veda/detail/1741进程和线程这对概念的理解也是很难的,至今网络上可查的资料对其的理解出入都挺大,在不同的操作系统中,如 ...

  6. DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法

    原文:DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA ...

  7. windows应用程序单实例

    前言 这才第几天博客就跟不上了,看来一天一篇博客的目标还是有点大,写博客还是挺费时间的,写了不满意删,删完再写...直到自己没了耐心.今天先写个前言,实质性的内容明天再补吧.今天一天的收获还是挺多的, ...

  8. Android入门(十四)内容提供器-实现跨程序共享实例

    原文链接:http://www.orlion.ga/661/ 打开SQLite博文中创建的 DatabaseDemo项目,首先将 MyDatabaseHelper中使用 Toast弹出创建数据库成功的 ...

  9. c# 控制职能运行单一实例,再次运行显示已经运行的实例

    有这么个需求,软件只能运行一个实例,软件运行后可以让其隐藏运行 再次运行这个软件的时候就让正在运行的实例显示出来 ================================= 当软件隐藏后没办法 ...

随机推荐

  1. grunt 实例构建(四)

    相关插件的引用: grunt-usemin  对页面的操作 grunt-contrib-cssmin  压缩css load-grunt-tasks 瘦身gruntfile grunt-rev给md5 ...

  2. Android中判断service是否在运行

    /** * 判断服务是否开启 * * @return */ public static boolean isServiceRunning(Context context, String Service ...

  3. STM32的固件升级(RTT

    STM32 通用 Bootloader ,让 OTA 更加 Easy 目前支持F1/F4,在线制作bootloader,准备固件升级,是RTT的云设备管理平台 https://mp.weixin.qq ...

  4. Java基础27-单例设计模式

    /* 设计模式:针对此类问题最有效的解决方法 java23种设计模式 单例设计模式:解决一个类只在内存中存在一个对象 如何让一个类在内存中只存在一个对象? 1.禁止其他的应用程序,通过此类来创建对象 ...

  5. RESTful简单介绍

    1 什么是restful Restful就是一个资源定位及资源操作的风格.不是标准也不是协议,只是一种风格.基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制. 资源:互联网所有的事物都 ...

  6. web_01Java ee实现登陆注册功能

    Web Web_01版本: 实现功能 用户注册 用户登录 设计内容 数据库:mysql 服务器: tomact7 配置 : xml 页面 : jsp+html/css *重点: 数据库相关: 数据库操 ...

  7. java 配置在.properties文件中的常量

    不让用常量类,那就用.properties文件配置,放在根目录. import java.util.HashMap; import java.util.Iterator; import java.ut ...

  8. 获取用户Ip地址通用方法常见安全隐患(HTTP_X_FORWARDED_FOR)

    分析过程 这个来自一些项目中,获取用户Ip,进行用户操作行为的记录,是常见并且经常使用的. 一般朋友,都会看到如下通用获取IP地址方法. function getIP() { if (isset($_ ...

  9. mysql服务器运维简单命令介绍

    1.mysql>show processlist; 此处关注查询时间,关注谁锁住了表,谁最多: 2.查看开启的日志 mysql>show global variables like '%l ...

  10. [转]让ASP.NET Web API支持$format参数的方法

    本文转自:http://www.cnblogs.com/liuzhendong/p/4228592.html 在不使用OData的情况下,也可以让ASP.NET Web API支持$format参数, ...