单实例(Single Instance)的VC应用

news/2025/1/7 19:56:17/文章来源:https://www.cnblogs.com/stronghorse/p/18655678

作者:马健
邮箱:stronghorse_mj@hotmail.com
主页:https://www.cnblogs.com/stronghorse
发布:2025.01.05

所谓单实例(Single Instance),是指在系统中同时只能有应用的一个实例在运行,即启动第二个实例的时候,如果发现已经有第一个实例在运行,则要么直接退出第二个实例,要么通知第一个实例退出,由第二个实例接棒。

在我发行的免费软件中,NoteIcon就是一个典型的单实例应用,因为如果同时有多个实例在运行,就会对NoteIcon.txt文件造成访问冲突,解决起来既麻烦,又没有必要,不如干脆限制成单实例。

最近想把TrayApp也改成单实例,所以对目前搜集的一些单实例技术进行了总结。

单实例最关键的技术,其实就是当第二个实例启动的时候,以什么特征判断第一个实例已经启动?这个特征判断要求既简单又可靠,我见过的技术包括:

一、以互斥量(Mutex)为特征

如果只需要简单判断是否已经有第一个实例在运行,发现已经在运行就直接退出第二个实例,两个实例之间不需要进行任何通讯,那么最简单的办法是使用互斥量(Mutex)。这种方法是我在一个开源小软件里看来的,名字叫NetworkIndicator,但忘记是从codeguru还是codeproject上下载的源代码了。这个小软件的功能就是模拟以前Win98的功能,在桌面右下角的系统托盘区(现在似乎叫系统通知区)显示一个小图标,展现当前网络的连接状态。这种托盘区的小软件一般都要做单实例判断,以免在系统托盘区中重复加入图标。

在NetworkIndicator中只用了三行做判断:

HANDLE hMutexOneInstance = ::CreateMutex( NULL, FALSE, _T("NetworkIndicator"));
DWORD dwLastErr = ::GetLastError();
BOOL bAlreadyRunning = (dwLastErr == ERROR_ALREADY_EXISTS || dwLastErr == ERROR_ACCESS_DENIED);

如果要更具有普适性,CreateMutex的第三个参数其实最好用GUID串。

二、以主窗口标题(Caption,或Title)为特征

如果需要在第一个实例与第二个实例之间进行通讯,比如说在第二个实例发现第一个实例后,自动激活第一个实例,然后自己再退出,则上面的Mutext方法就不够用。这种时候如果是有主窗口的应用,且主窗口的标题比较有特色,那么可以采用如下简单方法:

1、调用EnumWindows函数开始枚举窗口。
2、在回调函数中调用GetWindowText获取当前枚举到的窗口的标题,如果发现是自己的标题,那么就有了第一个实例主窗口的窗口句柄(HWND),不论是激活它,还是给它发消息,都是毛毛雨啦。

这种方法一般只适用于基于对话框的应用,不适用于文档-视(Document-View)结构的应用,因为不论是SDI还是MDI,一般MainFrame的标题都会随着当前所打开的文档而变化,不固定。

如果觉得仅凭主窗口标题还不是很保险,可以再加入通讯确认机制:第二个实例在枚举出第一个实例的主窗口后,调用SendMessageTimeout向第一个实例的主窗口发送一条约定好的自定义消息,如果没有超时,并且返回值也是双方约定好的值,则可以确认第一个实例主窗口的有效性和唯一性。

三、以主窗口类名(ClassName)为特征

对于文档-视(Document-View)结构的应用,既然主窗口的标题不固定,那么还可以在创建主窗口之前,调用AfxRegisterClass函数给主窗口注册一个够独特的类名(ClassName),然后用FindWindowEx函数找具有这个类名的窗口,找到了就可以给窗口激活、发消息。如果不保险,也可以和前面说的Mutex结合起来,先检查互斥量是否已经创建,发现已经被创建过再找窗口。

这个方法不仅适用于Document-View结构的应用,也适用于对话框为主窗口的应用,包括没有标题条的对话框。

这种方法的代码我最早是在codeguru上看到的一个开源项目,提供了现成的SingleInstanceApp.h、SingleInstanceApp.cpp,直接用就好。后来在codeproject上也看到类似的项目“Dialog based single instance applications improved”,技术上是一样的,但没有像codeguru上的封装成了一个类。

NoteIcon用的就是这种技术,所以如果用Spy++去看它主窗口的类名,就会看到长长一串字符串。

四、以进程ID(ProcessID)为特征

如果应用软件干脆就没有主窗口,那么不论是EnumWindows还是FindWindowEx,都将失去作用,只能用其他方法。

我在Windows 2003源代码中看到的一种方法是使用共享内存,即用CreateFileMapping创建一个具有约定名称(GUID)的共享内存,创建成功说明当前是第一个示例,可以把进程ID(Process ID)等写到共享内存里;创建不成功说明当前进程已经是第二个示例,可以从共享内存中读取出第一个示例的Process ID,然后进行进一步的操作。

在Windows 2003的原版代码中,取得第一个进程的Process ID后,是调用EnumWindows找窗口,找到后激活之。但如果应用软件没有主窗口,其实可以改成通过Mutex或Event通知第一个实例说“第二个实例已经上线”,然后双方通过共享内存进行双向通讯。

Windows 2003的相关代码封装在单独一个文件singleinst.h中,不论是使用还是修改都很方便。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/865002.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PhpStorm 2024.3.1.1 安装激活教程(激活至2026,实际上永久,亲测!)以及常见问题处理

申明:本教程 PhpStorm 补丁、激活码均收集于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除。若条件允许,希望大家购买正版 !卸载老版本 PhpStorm 首先,如果小伙伴的电脑上有安装老版本的 PhpStorm , 需要将其彻底卸载掉,如下所示(没有安装则不用管,直…

以太网物理层IOP测试设备TESTBASE-EIOP

OPEN联盟(OPEN Alliance)是一个由OEM、Tier1和Tier2共同组建的非盈利开放性的行业联盟,旨在将以太网技术在汽车环境中应用及推广,TESTBASE-EIOP是经纬恒润自主研发的车载以太网物理层IOP(交互性)自动化测试设备,可完整覆盖OPEN TC8 IOP测试标准。背景OPEN联盟(OPEN All…

Linux命令行连接蓝牙设备

Linux命令行连接蓝牙设备 查看Bluetooth设备: hciconfig启动一个Bluetooth设备,例如:hci0: hciconfig hci0 up相关指令查看特定的Bluetooth设备(例如,设备名为hci0): hciconfig hci0关闭一个Bluetooth设备(例如,设备名为hci0): hciconfig hci0 down修改一个Bluetoot…

华为云专家说:开源的商业化之路与开发者技术服务

开源在大量在云技术以及业务中应用,从开源与云的增长模式看,开源与云具有相当程度的相似性。本文来源:《华为云DTSE》第五期开源专刊,作者:华为云开发者支持首席布道师汪盛 开源、云的增长模式与 Product Led Growth具有较大相似性,两者增长立足于产品质量与使用的开发者…

JAVA-Day 06:if语句的三种形式

if语句的三种形式if(表达式){语句体}如果小括号里的表达式结果为真,则执行大括号中的语句体,如下图例子所示:2.if(表达式){语句体}else{语句体} 如果小括号里的表达式为真,则执行else前的大括号中的语句体,如果小括号里的表达式为假,则执行else后的大括号中的语句体。如下图…

Redis可视化工具 Another Redis Desktop Manager工具使用详细教程(附下载链接)

Redis 可视化工具推荐:Another Redis Desktop Manager Redis 是一种高性能的键值数据库,广泛应用于缓存和消息队列等场景。对于开发者来说,命令行工具固然强大,但操作繁琐。而一款高效易用的可视化工具可以极大地提升使用效率。本篇将为大家推荐一款开源、跨平台且功能强大…

跟狂神学习第一天,了解Markdown语法

Markdown学习 一个#+空格+标题名字=大标题/一级标题 二级标题 两个#+空格+标题 = 二级标题 三个#+空格+标题 = 三级标题 .......(以此类推) 一直到六级标题 字体 hello! 粗体:文字两边同时加两个* hello! 斜体:文字两边同时加一个* hello! 斜体加粗:文字两边同时加三个…

Ubuntu换源自用备用

Ubuntu换源(本地) 作者 原文链接:https://blog.csdn.net/MacWx/article/details/137689898 查询系统版本 lsb_release -a系统版本是 Ubuntu 20.04.6 LTS,注意这个开发代号Codename,Ubuntu每一个版本都有一个代号,这个一定要跟国内源对应,否则会出问题。 阿里云Ubuntu镜像…

大规模高性能云网络技术思路

控制面基础架构采用微服务架构模型,服务独立可扩展,可以根据每个服务的规模来部署满足需求的实例。具体网络控制面技术方案如图本文分享自天翼云开发者社区《大规模高性能云网络技术思路》,作者:程****超 控制面基础架构采用微服务架构模型,服务独立可扩展,可以根据每个服…

Python开发环境部署教程

本教程将详细介绍如何在 Windows 系统上配置 Python 开发环境,包括安装 Python、配置虚拟环境以及使用 VS Code 进行开发,适合新手和需要精细配置的开发者。本教程将详细介绍如何在 Windows 系统上配置 Python 开发环境,包括安装 Python、配置虚拟环境以及使用 VS Code 进行…

基于云效 Windows 构建环境和 Nuget 制品仓库进行 .Net 应用开发

本文将基于云效 Flow 流水线 Windows 构建环境和云效 Packages Nuget 制品仓库手把手教你如何开发并部署一个 .NET 应用,从环境搭建到实战应用发布的详细教程,帮助你掌握 .NET 开发的核心技能。作者:陆冬澄、周静 在现代软件研发体系中,.NET 平台由于其强大的功能、灵活性和…

初创团队如何借助看板工具简化任务管理

在初创企业的构建过程中,团队管理和项目推进常常面临诸多挑战。由于资金、人员和时间的限制,如何高效地组织和管理项目成为了每个初创团队需要面对的重要课题。幸运的是,借助现代化的看板文档工具,初创团队可以大幅提升其工作效率和协作效果,确保在快速变化的市场环境中保…