在软件开发中,有时需要确保同一时间只有一个应用程序实例在运行。这可以通过实现单实例应用程序来实现。本文将介绍如何使用命名互斥体、线程休眠、内存映射文件等技术来实现单实例应用程序。
单实例应用程序的一个关键特点是,它将新的命令行参数传递给现有的应用程序实例。这种方法不需要寻找或定位窗口,并且实例之间的CPU开销几乎为零。要查看这个示例的实际效果,只需使用不同的命令行参数运行多个实例,应该能看到命令行参数被传递给初始实例。
在同事询问如何实现单实例应用程序后编写了这个示例。第一反应是使用“命名互斥体”。花了一些时间查看代码项目和以下文章:
这两篇文章都很好,值得称赞,但它们都没有解决传递命令行参数的问题。目标是展示以下内容:
使用CSingleInstance类非常简单,只需将其作为CWinApp类的第二个父类添加即可。
// singleton.h
class CSingletonApp : public CWinApp, public CSingleInstance {
...
};
接下来,在CWinApp::InitInstance内部的第一个语句调用CSingleInstance::Create,创建参数必须提供一个唯一的字符串。可以提供"MyCompany_MyApplication",但这样做总是有别人使用相同字符串的风险,所以更喜欢使用GUID。
可以通过在命令提示符下运行"guidgen"来生成GUID;它是MSVC的一部分,使用注册表格式。可以使用Microsoft定义的任何前缀,"Global\"或"Local\",必须了解应用程序的目标环境,因为"命名对象"在XP、NT等系统下的行为不同。
有关更多信息,建议阅读以下内容:
// singleton.cpp
BOOL CSingletonApp::InitInstance() {
// 在这里使用GUID,以确保字符串是100%唯一的
if (CSingleInstance::Create(_T("E435FC13-82C1-4f80-97C5-006FF4A4Exxx")) == FALSE)
return FALSE;
...
}
以下是可选的,允许处理唤醒或激活消息,应该通过派生一个类从CSingleInstance,然后添加一个虚拟方法WakeUp来实现。
// singleton.h
class CSingletonApp : public CWinApp, public CSingleInstance {
public:
virtual void WakeUp(LPCTSTR aCommandLine) const;
};
// singleton.cpp
void CSingletonApp::WakeUp(LPCTSTR aCommandLine) const {
// 调用父类来处理基本功能(设置前景)
CSingleInstance::WakeUp(aCommandLine);
// 处理命令行,对于这个示例,将新命令行发送到对话框
CSingletonDlg* lSingletonDlg = (CSingletonDlg*) m_pMainWnd;
if (lSingletonDlg) {
lSingletonDlg->SetCommandLine(aCommandLine);
}
}