在项目开发中,经常要求系统在同一时刻在同一台机器上只能运行一个实例,可以通过这种方式实现
在InitInstance()函数中添加如下代码(可以函数最前边添加,也可以放后边点,不过最好放最前边):
Sample Code
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->HANDLEm_hMutex=::CreateMutex(NULL,TRUE,m_pszName);// m_pszName为互斥体 名 如"132"或者"my"
if(GetLastError()==ERROR_ALREADY_EXISTS)
{
AfxMessageBox("您已经运行了本软件!");//弹出对话框确认不能运行第二个实例。
returnFALSE;
}
1: 新建一基于对话框的工程ex1,采用默认设置
2: 用GUIDGEN.EXE产生一个全局标志,#define one "产生的全局标志"
本例中产生的语句如下:#define one "0xbe8e2ce1, 0xdab6, 0x11d6, 0xad, 0xd0, 0x0,
0xe0, 0x4c, 0x53, 0xf6, 0xe6"
3: 在应用程序类CEx1App::InitInstance()中,用CreateMutex函数创建一个互斥量,后调用函数GetLastError()
如果结果等于ERROR_ALREADY_EXISTS说明已经有一个实例在运行了这时返回FALSE.
BOOL CEx1App::InitInstance()
{
handle=::CreateMutex(NULL,FALSE,one);//handle为声明的HANDLE类型的全局变量 ,前边是个局部变量 故不用第4步
if(GetLastError()==ERROR_ALREADY_EXISTS)
{
AfxMessageBox("应用程序已经在运行");
return FALSE;
}
}
4:在CEx1App::ExitInstance()中,删除这个互斥量
int CEx1App::ExitInstance()
{
CloseHandle(handle);
return CWinApp::ExitInstance();
}
------------------------------一----------------------------------------------------------------
方法一:
我用得做多的方法是创建互斥体Mutex,使用Mutex代码比较简洁,但是此时不能取得已经启动的实例窗口局柄,因此无法激活已经启动的实例窗口,代码如下:
// -------------------------------------------------------------------------
// 函数 : CreateSendingWNDList
// 功能 : 创建互斥量,用于保证只启动一个进程
// 返回值 : int
// 成功 0
// 失败 -1
// 存在进程实例 1
// 附注 :
// -------------------------------------------------------------------------
int CreateSendingWNDList(const TCHAR *pstrKSCoreAppName)
{
//-------防止多次起动----------
HANDLE hMutex = ::CreateMutex(0, true, pstrKSCoreAppName);
int nRet = 0;
if (hMutex)
{
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
nRet = 1;
}
else
{
nRet = 0;
}
}
else
{
nRet = -1;
}
return nRet;
}
// 在创建窗口前调用下面代码
switch(CreateSendingWNDList(g_strKSCoreAppName))
{
case 0:
// 正常启动
// TODO……
break;
case 1:
// 已存在进程,退出
{
::MessageBox(NULL, TEXT("已经有一个实例在运行了。"), TEXT("注意"), MB_OK);
}
case -1:// 无法创建,退出
default:
return FALSE;
}
方法二:
一般来说,使程序只运行一个实例的最简单的方法当然是使用FindWindow()查找主窗口,如果主窗口已经存在了,当然说明已经有一个实例运行了。代码如下:
// 这种方法有缺陷,窗口名字改变之后就再也找不到了,FindWindow()的参数ClassName和Caption比较难取得。
HWND hWnd = FindWindow(NULL, TEXT("SingleInstanceFW"));
if(IsWindow(hWnd))
{
::MessageBox(NULL, TEXT("已经有一个实例在运行了。"), TEXT("注意"), MB_OK);
::ShowWindow(hWnd, SW_NORMAL); // 显示
::SetForegroundWindow(hWnd); // 激活
return FALSE;
}
方法三:
这种方法相比上面两种方法,避免上面两种方法的缺点,通过SetProp()为程序主窗口设置一个特殊的Property,然后在启动时遍历所有的窗口,找出包含着个Property的窗口局柄
。【这个附加的窗口属性在窗口销毁时也应该销毁】这个方法的缺点就是代码比较多一点,如下:
// 声明全局的 属性 名和 属性值
TCHAR g_strKSCoreAppName[] = _T("AFX_KSInstall_CPP__12036F8B_8301_46e2_ADC5_A14A44A85877__");
HANDLE g_hValue = (HANDLE)1022;
// 定义枚举窗口回调函数
BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lParam)
{
//TCHAR str[200] = {0};
//::GetWindowText(hwnd, str, 200);
HANDLE h = GetProp(hwnd, g_strKSCoreAppName);
if(h == g_hValue)
{
*(HWND*)lParam = hwnd;
return FALSE;
}
return TRUE;
}
// 主窗口创建前判断
HWND oldHWnd = NULL;
::EnumWindows(EnumWndProc,(LPARAM)&oldHWnd); //枚举所有运行的窗口
if (oldHWnd != NULL)
{
::MessageBox(NULL, TEXT("已经有一个实例在运行了。"), TEXT("注意"), MB_OK);
::ShowWindow(oldHWnd, SW_NORMAL); // 显示
::SetForegroundWindow(oldHWnd); // 激活
return FALSE;
}
// 主窗口创建后设置,为窗口附加一个属性
::SetProp(m_hWnd, g_strKSCoreAppName, g_hValue);
// 主窗口退出时移除该附加属性
::RemoveProp(m_hWnd, g_strKSCoreAppName);
方法四:
上面的方法二和方法三都有一个弊病,不知道大家发现没,那就是依赖于窗口的存在,没有窗口的程序怎么办了,用方法一是可以的,不过方法一不太适合即时修改状态,譬如我想提供选项给用户,可以即时修改是否允许多实例,像KMP就提供了即时修改是否允许多实例,使用全局变量是一个比较好的解决方案,使用全局共享变量的方法则主要是在VC框架程序中通过编译器来实现的。通过#pragma data_seg预编译指令创建一个新节,在此节中可用volatile关键字定义一个变量,而且必须对其进行初始化。Volatile关键字指定了变量可以为外部进程访问。最后,为了使该变量能够在进程互斥过程中发挥作用,还要将其设置为共享变量,同时允许具有读、写访问权限。这可以通过#pragma comment预编译指令来通知编译器。下面给出使用了全局变量的进程互斥代码清单:
#pragma data_seg("Shared")
int volatile g_lAppInstance = 0;
#pragma data_seg()
#pragma comment(linker,"/section:Shared,RWS")
if (0 == g_lAppInstance)
{
g_lAppInstance = 1;
}
else if (1 == g_lAppInstance)
{
::MessageBox(NULL, TEXT("已经有一个实例在运行了。"), TEXT("注意"), MB_OK);
return FALSE;
}
else
{
// 直接启动
}
【注意,代码应该放在程序的入口处】
其实上面的方法可以两种进行组合来实现一些比较特殊的需求,具体怎样就自己去想了。
分享到:
相关推荐
保证应用程序只有一个实例运行! 很值得下载看看!资源免费,大家分享!!
可以使用互斥体Mutex类型完成此功能。见如下代码: [STAThread]c_让应用程序只有一个实例运行
c++ vs2008 应用程序只有一个实例 简单的demo 启动程序
使用共享内存和信号量实现QT应用程序单实例的方法,并且支持根据需要弹出已经运行的程序窗口,解决了同类软件存在的问题,而且程序非常简单。
保证应用程序只有一个实例运行.txt 编辑字段中的word文件.txt 编码标准.txt 播放声音.txt 捕捉DataGrid的双击事件(C#版本).txt 不显示窗口后台运行程序.txt 储存过程.txt 处理“进程性能计数器被禁用”的...
保证应用程序只有一个实例运行.txt 编辑字段中的word文件.txt 编码标准.txt 播放声音.txt 捕捉DataGrid的双击事件(C#版本).txt 不显示窗口后台运行程序.txt 储存过程.txt 处理“进程性能计数器被禁用”的...
51单片机C语言应用程序设计实例精讲教材1及CD光盘【全部 完整程序和相应原理图】.zip 上次本人上传给大家一个不完整的版本,在此表示抱歉,现在将完整版本低分 分享给大家。 (经过本人初步验证过,其实戴佳此书的第...
C#电话本 控制台应用程序 软件项目课程设计 1.文件破坏处理, 若文件破坏则重新初始化 2.管理员账号保存,一个电话簿文件中内置管理员账号,一一对应。删除电话簿必须正确输入管理员账号。//管理员为第【0】条记录 ...
详细介绍Delphi 的集成开发环境,Delphi 的应用程序框架。介绍Object Pascal 的编程语法结构,:主要介绍了VCL 简单组件的编程技巧与主要属性、方法、事件的使用方法主要讲解Delphi 数据库开发工具基础知识,只有熟练...
每个应用程序只有一个实例。 您可以将小部件直接添加到根窗口,也可以添加到其他小部件。 一旦构建了UI(通过代码或从XML源加载UI),RootWindow的Run()方法就可以开始接受用户输入和处理事件。 当它处于活动...
VC++ 多线程与聊天室程序的创建 ...如何利用命名互斥对象保证应用程序只有一个实例运行。应用多线程编写网络聊天室程序。在接收线程函数中,遗忘了释放指针的操作,在随盘代码中已更正,特此说明。
内含课程内容和讲义PPT,本实例主要通过演示多线程的应用,多线程应用中容易出现的问题,互斥对象的讲解等,比如如何采用互斥对象来实现多线程的同步,如何利用命名互斥对象保证应用程序只有一个实例运行,并使用多...
实例006 设置Windows应用程序启动窗体 9 实例007 统一窗体中控件的字体设置 10 实例008 通过“格式”菜单布局窗体 10 1.3 快速开发项目必备 11 实例009 为项目添加DLL文件引用 11 实例010 为项目添加已有类 12 实例...
多实例队列管理器特征是MQV7.0.1版本之后引进的新特征,它是MQ产品的内置功能,丰富了 MQ 高可用...它可以锁定队列管理器数据,确保 队列管理器中只有一个活动实例。备用队列管理器实例定期查看活动实例是否正在运行。
多线程程序的编写,多线程应用中容易出现的问题。互斥对象的讲解,如何采用互斥对象来实现多线程的同步。如何利用命名互斥对象保证应用程序只有一个实例运行。应用多线程编写网络聊天室程序。
每个应用程序只有一个实例。 RootWindow可以只有一个子元素。 您可以使用诸如Grid或Stackpanel之类的控件将多个元素添加到窗口中。 就像您在WPF中所做的一样。 一旦创建了RootWindow,就需要在其上调用Run()方法。...
细节 ... 每个应用程序只有一个实例(单个进程);每个实例只有一个实例。 我还没有找到如何在更改QoS设置的方法,因此在两个应用程序中都使用了默认设置。 PostgreSQL 11(500个连接限制); Rab
使用socket-io 只需一个React钩子,即可访问应用程序的客户端Socket实例。安装使用npm : npm i --save use-socket-io 带yarn : yarn add use-socket-io用法import SocketProvider , { useSocket } from "use-...
线性结构的数据元素之间存在 一对一的关系,其特点是除了开头和最后一个节点外,其他的任意一个节点都只有一个 直接前驱节点后后继节点。线性结构主要包括有线性表、栈和队列。树、集合、图都是 非线性结构,其中树...
single-beat, 确保你的服务器上只有一个流程实例 单节拍单节拍是一个不错的小应用程序,它确保你的进程的一个实例在你的服务器上运行。比如 celerybeat ( 或者邮件发送者,孤儿档案清洁工等。) 只需要在一台服务器上...