[VC]在VC++中实现让程序只运行一个实例的方法且实现该实例
方法一:
有时候在开发应用程序时,希望控制程序运行唯一的实例。例如,最常用的mp3播放软 件Winamp,由于它需要独占计算机中的音频设备,因此该程序只允许自身运行唯一的一个例程。在Visual C++的开发实践中,对于16位的Windows系统,应用程序的hPrevInstance句柄保存了应用程序上一个运行的实例,可以用该值来检查是否 有实例运行;然而在32位Windows系统下,这个值总是NULL,所以无法利用该值来实现程序运行唯一实例。本实例给出了解决这个问题的简单办法,只 要将程序中稍微改动一下就可以了。
一、 实现方法
对于具有窗口的应用程序,可以用静态函数CWnd::FindWindow()查找固定窗口,来判断程序是否已经运行。函数原型为:
CWnd* PASCAL FindWindow( LPCTSTR lpszClassName, LPCTSTR lpszWindowName );
这个函数有两个参数,第一个是要找的窗口的类,第二个是要找的窗口的标题。在搜索的时候不一定两者都知道,但至少要知道其中的一个。有的窗口的标题是比
较容易得到的,如"计算器",所以搜索时应使用标题进行搜索。但有的软件的标题不是固定的,如"记事本",如果打开的文件不同,窗口标题也不同,这时使用
窗口类搜索就比较方便。如果找到了满足条件的窗口,这个函数返回该窗口的指针,否则返回值为NULL。
考虑到程序的健壮性,我们还需要判断窗口是否处于最小化状态、是否有弹出式子窗口,这就需要使用CWnd:: GetLastActivePopup()、CWnd::IsIconic()函数,它们的原型分别为:
CWnd* GetLastActivePopup( )
该函数返回一个指定父窗口中最近激活过的弹出式窗口的指针。如果窗口本身是刚刚激活的,或窗口不包含任何弹出窗口,那么该函数返回指向父窗口自身的指针。
BOOL IsIconic( )
该函数用来判断当前窗口是否处于最小化状态,如果窗口处于最小化状态,函数返回值为True,否则返回Flase。
对于处于最小化状态的窗口,可以调用CWnd::ShowWindow( int nCmdShow )恢复窗口的正常状态,该函数的原型为:
BOOL ShowWindow( int nCmdShow )
如窗口之前是可见的,函数调用后返回True,否则返回False。参数nCmdShow的值可以为以下任意个常数:
SW_HIDE:隐藏窗口,活动状态给令一个窗口;
SW_MINIMIZE:最小化窗口,活动状态给另一个窗口;
SW_RESTORE:用原来的大小和位置显示一个窗口,同时令其进入活动状态;
SW_SHOW:用当前的大小和位置显示一个窗口,同时令其进入活动状态;
SW_SHOWMAXIMIZED:最大化窗口,并将其激活;
SW_SHOWMINIMIZED:最小化窗口,并将其激活;
SW_SHOWMINNOACTIVE:最小化一个窗口,同时不改变活动窗口;
SW_SHOWNA:用当前的大小和位置显示一个窗口,不改变活动窗口;
SW_SHOWNOACTIVATE:用最近的大小和位置显示一个窗口,不改变活动窗口;
SW_SHOWNORMAL:与SW_RESTORE相同;
最后不要忘记了用CWnd:: SetForegroundWindow()函数将弹出窗口设置为桌面的最前端。
有了上面的知识,我们就可以修改程序中应用程序类的InitInstance()函数,如果程序已经运行,也即是可以发现相应的程序窗口,那么就显示该窗口,InitInstance()函数就返回False,程序提前退出,否则就正常运行。
二、 编程步骤
1、 启动Visual C++6.0,生成一个基于对话框的应用程序,程序命名为"Instance";
2、 修改程序的InitInstance()函数;
3、 添加代码,编译运行程序;
三、 程序代码
/////////////////////////////////////////////////////////////////////////////
// CInstanceApp initialization
BOOL CInstanceApp::InitInstance()
{
if (!FirstInstance())
return FALSE;
AfxEnableControlContainer();
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
CInstanceDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
BOOL CInstanceApp::FirstInstance()
{
CWnd *pWndPrev, *pWndChild;
// Determine if another window with our class name and Window title exists...
// The title "Instance " is set up latter, in the InitDialog function.
if (pWndPrev = CWnd::FindWindow(NULL, "Instance "))
{
pWndChild = pWndPrev- >GetLastActivePopup();
// if so, does it have any popups?
if (pWndPrev- >IsIconic())
pWndPrev- >ShowWindow(SW_RESTORE);
// If iconic, restore the main window
pWndChild- >SetForegroundWindow();
// Bring the window to the foreground
return FALSE;
}
else
return TRUE; // First instance. Proceed as normal.
}
四、 小结
上述方法虽然实现起来很简单,但是它对于无窗口的应用程序却无能为力。为了解决这个问题,可以通过动态连接库DLL实现更通用的控制程序运行的方法。在
DLL中使用#pragma data_seg指令实现共享数据段,在该数据段中定义一个变量long
m_nRun,并设置其初始值为-1,同时还要在DLL的入口点函数DllMain返回成功值的语句前添加语句m_nRun++,意思是在应用程序启动连
接DLL成功时对已经运行的实例进行计数,然后在DLL中导出一个函数来返回该变量的值。最后将应用程序的工程设置为依赖于该DLL的工程,在应用程序根
据DLL中的m_nRun变量的值来判断是否程序已经运行了。
方法二:
#define UNIQE_NAME "{1AB792D6-EAF2-3267-9A84-9135681127A4}"
#define GIS_MSG "{D48CA993-4925-41cb-8F59-ABAAAFCEF797}"
const UINT ID_GIS_INSTANCE = ::RegisterWindowMessage(GIS_MSG); //注册消息
// 确保程序只有一个实例在运行
m_hOneInstance = ::CreateMutex(NULL, FALSE, UNIQE_NAME);
if (GetLastError() == ERROR_ALREADY_EXISTS )//如果存在前一个
{
//发送消息,激活实例
DWORD dwRecipients = BSM_APPLICATIONS;
::BroadcastSystemMessage(BSF_NOHANG, &dwRecipients,
ID_GIS_INSTANCE, // registered window message
0, 0); // user defined parameters
return FALSE;
}
ON_REGISTERED_MESSAGE(ID_GIS_INSTANCE, OnGISInstance)
LRESULT CMainFrame::OnGISInstance(WPARAM wParam, LPARAM lParam)
{
theApp.m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
theApp.m_pMainWnd->SetForegroundWindow();
::AfxMessageBox("本程序已经有一个实例在运行了。");
return 0;
}
[VC]在VC++中实现让程序只运行一个实例的方法且实现该实例的更多相关文章
- [转]Delphi中,让程序只运行一次的方法
program onlyRunOne; uses Forms,Windows,SysUtils, Dialogs, Unit1 in 'Unit1.pas' {Form1}; {$R *.res} v ...
- vc++高级班之窗口篇[4]---让程序只运行一个实例
大家都看过或者使用过类似只运行一个实例的程序,比如:QQ游戏.部分浏览器 等等! 让一个程序只运行一个实例的方法有多种,但是原理都类似,也就是在程序创建后,有窗口的程序在窗口创建前, 检查系统中是 ...
- VC 实现程序只运行一个实例,并激活已运行的程序
转载:http://blog.sina.com.cn/s/blog_4b44e1c00100bh69.html 进程的互斥运行:CreateMutex函数实现只运行一个程序实例 正常情况下,一个进程的 ...
- 如何让Windows程序只运行一个程序实例?
要实现VC++或者MFC只运行一个程序实例,一般采用互斥量来实现,即首先用互斥量封装一个只运行一个程序实例的函数接口: HANDLE hMutex = NULL; void MainDlg::RunS ...
- C#让应用程序只运行一个实例的几种方法
一 判断是否有相同的实例已经运行 1 根据“Mutex”判断是否有相同的实例在运行 /// <returns>已有实例运行返回true,否则为false</returns>pu ...
- VC程序只运行一个实例,并在打开多个时激活原窗口
(一)单文档应用程序 1.在应用程序类C~~App::InitInstance()函数中判断是否已有一个应用程序实例正在运行 BOOL C~~App::InitInstance() { . ...
- Winform(C#)限制程序只运行一个实例
C#控制只运行开启一个程序 在这个例子中不需要调用ReleaseMutex,mutex会在程序结束时自动释放.为了防止mutex过早释放,在程序的最后调用下GC.KeepAlive (mutex). ...
- 让程序只运行一个实例(Delphi篇)(三种方法,其中使用全局原子的方法比较有意思)
Windows 下一个典型的特征就是多任务,我们可以同时打开多个窗口进行操作,也可以同时运行程序的多个实例,比如可以打开许多个资源管理器进行文件的移动复制操作.但有时出于某种考虑(比如安全性),我们要 ...
- Java程序只运行一个实例[转]
如果希望你的Java程序只能存在一个实例,可以参考下面的用法. 原文链接:http://blog.csdn.net/yaerfeng/article/details/7264729 Java没有提供这 ...
随机推荐
- 微信小程序运行机制
对于扫描接口B生成的带参小程序码的问题: (1)线上版本 扫描不同带参的小程序码会重新执行小程序的整个注册程序生命周期(详细生命周期函数见官方文档), (2)扫描相同的二维码的时候,目前微信官方给出的 ...
- Thinkpad 拆光驱更换光驱硬盘支架、拆光驱面板 T400 T440
拆光驱.硬盘装支架的环节就不多说了.主要说下拆光驱面板. 先拿细物(区别针.回形针),捅这个洞,就能把光驱仓打开弹出来后,反过来,这里有个卡扣放大看,按住这卡扣,然后往外掰,把面板掰出来 掰出来的面板 ...
- js用"."和"[]"获取属性的区别
在JavaScript中通常使用”."运算符来存取对象的属性的值.或者使用[]作为一个关联数组来存取对象的属性. 对象的属性和方法统称为对象的成员. 访问对象的属性 在JavaScript中 ...
- PHP中error_reporting()函数的用法(修改PHP屏蔽错误)
一般在默认的普通PHP文件中输出一个未定义声明的变量是不会报错误的,但在codeigniter框架下却要报错误,这对于想集成 添加 和 修改 页面于一体的”懒人”很不方便,由于是初学者开始还想怎么在代 ...
- opengl学习资料
opengl新手指引 https://www.codeproject.com/articles/771225/learning-modern-opengl Learning Modern 3D Gra ...
- DNS(域名系统)服务器
DNS(Domain Name System),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的Ip数串.通过主机名,最终得到该主机 ...
- Elasticsearch内存分配设置详解(转)
Elasticsearch默认安装后设置的内存是1GB,对于任何一个现实业务来说,这个设置都太小了.如果你正在使用这个默认堆内存配置,你的集群配置可能会很快发生问题.这里有两种方式修改Elastics ...
- PAT甲级——1104 Sum of Number Segments (数学规律、自动转型)
本文同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/90486252 1104 Sum of Number Segmen ...
- BZOJ 1047: [HAOI2007]理想的正方形 单调队列瞎搞
题意很简明吧? 枚举的矩形下边界和右端点即右下角,来确定矩形位置: 每一个纵列开一个单调队列,记录从 i-n+1 行到 i 行每列的最大值和最小值,矩形下边界向下推移的时候维护一下: 然后在记录的每一 ...
- H.天神的密码
链接:https://ac.nowcoder.com/acm/contest/903/H 题意: 2018年,icebound打开了神殿.而在2019年,icebound正在试图破解天神的密码,以期获 ...