大家都看过或者使用过类似只运行一个实例的程序,比如:QQ游戏、部分浏览器 等等!
让一个程序只运行一个实例的方法有多种,但是原理都类似,也就是在程序创建后,有窗口的程序在窗口创建前,
检查系统中是否已经设置了某些特定标志,是否创建了一些全局唯一的东西,或者让程序的多个实例都能看到的东西,
如果有则说明已经有一个实例在运行了,则当前程序通知用户如何如何,然后程序退出,当然方法有很多种,各有各的优缺点!
 
①、创建互斥体 Mutex 法:
但是单纯的使用互斥体的话不能取得已经创建的实例窗口局柄,因此无法激活已经启动的实例窗口;
HANDLE m_hMutex = ::CreateMutex(NULL, FALSE, _T("{6668BB0A-DE0C-499d-8520-79653FF9B2EB}"));
if ( GetLastError() == ERROR_ALREADY_EXISTS ){
 AfxMessageBox(_T("已经有一个实例正在运行中……"));
 CloseHandle(m_hMutex);
 m_hMutex = NULL;
 return FALSE;
}
//其他代码,比如对话框的创建及弹出等等
 
if (m_hMutex) {
 CloseHandle(m_hMutex);
 m_hMutex = NULL;
}
 
===================================================
②、通过 FindWindow 进行窗口的查找,若发现则说明已经运行过一个实例,并将其窗口激活:
HWND hWnd = ::FindWindow(_T("#32770"), _T("DlgTest"));
if (hWnd != NULL) {
 AfxMessageBox(_T("已经有一个实例正在运行中……"));
 ::ShowWindow(hWnd, SW_NORMAL);
 ::SetForegroundWindow(hWnd);
 return FALSE;
}
此种方法不是很好,如果窗口标题改变了或者每个窗口实例的标题不一样,就找不到了!
 
===================================================
③、设置窗口属性 SetProp + EnumWindows 法!
1、加入全局变量的定义及枚举窗口函数:
TCHAR g_szPropName[] = _T("{12AA5160-5215-435b-AE3C-60C9E65615CE}");
HANDLE g_hValue = (HANDLE)9527;
 
BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lParam)
{
 HANDLE hProp = GetProp(hwnd, g_szPropName);
 if(hProp == g_hValue) {
  *(HWND *)lParam = hwnd;
  return FALSE;
 }
 return TRUE;
}
 
2、窗口的枚举以及属性的添加:
//OnInitDialog() 中加入以下代码:
HWND hPreWnd = NULL;
::EnumWindows(EnumWndProc, (LPARAM)&hPreWnd);
if (hPreWnd != NULL) {
 AfxMessageBox(_T("已经有一个实例正在运行中……"));
 ::ShowWindow(hPreWnd, SW_NORMAL);
 ::SetForegroundWindow(hPreWnd);
 ExitProcess(0);
 return FALSE;
}
::SetProp(m_hWnd, g_szPropName, g_hValue);
 
3、窗口属性的删除:
OnDestroy() 函数中加入以下代码:
::RemoveProp(m_hWnd, g_szPropName);
 
===================================================
④、使用全局共享变量的共享节法实现单实例运行;
1、新建共享节:
#pragma data_seg("Shared")
HWND hPreWnd = NULL;
#pragma data_seg()
#pragma comment(linker, "/Section:Shared,RWS")
 
2、OnInitDialog() 函数中加入以下代码:
if (hPreWnd == NULL) {
 hPreWnd = m_hWnd;
} else {
 AfxMessageBox(_T("已经有一个实例正在运行中……"));
 ::ShowWindow(hPreWnd, SW_NORMAL);
 ::SetForegroundWindow(hPreWnd);
 ExitProcess(0);
 return FALSE;
}
 
===================================================
⑤、互斥体+自定义广播系统消息法;
1、系统消息的注册:
#define REG_MSG (_T("{7510EF00-BADA-48de-A6CE-5FBC817616DD}"))
UINT WM_ACTIVE_MSG = ::RegisterWindowMessage(REG_MSG);
 
2、发现实例后,进行消息的广播:
InitInstance() 函数中添加如下代码:
 
HANDLE m_hMutex = ::CreateMutex(NULL, FALSE, _T("{6668BB0A-DE0C-499d-8520-79653FF9B2EB}"));
if ( GetLastError() == ERROR_ALREADY_EXISTS ){
 AfxMessageBox(_T("已经有一个实例正在运行中……"));
 CloseHandle(m_hMutex);
 m_hMutex = NULL;
 
 DWORD dwRecipients = BSM_APPLICATIONS;
 ::BroadcastSystemMessage(BSF_NOHANG, &dwRecipients, WM_ACTIVE_MSG, 0, 0);
 
 return FALSE;
}
//其他窗口创建之类的代码
if (m_hMutex) {
 CloseHandle(m_hMutex);
 m_hMutex = NULL;
}
 
3、窗口类中全局变量的作用域扩展:
extern UINT WM_ACTIVE_MSG;
 
4、窗口类中自定义消息的响应:
afx_msg LRESULT OnActiveMsg(WPARAM wParam, LPARAM lParam);
ON_REGISTERED_MESSAGE(WM_ACTIVE_MSG, &CDlgTestDlg::OnActiveMsg)
LRESULT CDlgTestDlg::OnActiveMsg(WPARAM wParam, LPARAM lParam)
{
 ::ShowWindow(m_hWnd, SW_NORMAL);
 ::SetForegroundWindow(m_hWnd);
 return TRUE;
}
------------------------------------- End -------------------------------------------

vc++高级班之窗口篇[4]---让程序只运行一个实例的更多相关文章

  1. VC 实现程序只运行一个实例,并激活已运行的程序

    转载:http://blog.sina.com.cn/s/blog_4b44e1c00100bh69.html 进程的互斥运行:CreateMutex函数实现只运行一个程序实例 正常情况下,一个进程的 ...

  2. VC程序只运行一个实例,并在打开多个时激活原窗口

    (一)单文档应用程序   1.在应用程序类C~~App::InitInstance()函数中判断是否已有一个应用程序实例正在运行 BOOL C~~App::InitInstance() {     . ...

  3. [VC]在VC++中实现让程序只运行一个实例的方法且实现该实例

    方法一: 有时候在开发应用程序时,希望控制程序运行唯一的实例.例如,最常用的mp3播放软 件Winamp,由于它需要独占计算机中的音频设备,因此该程序只允许自身运行唯一的一个例程.在Visual C+ ...

  4. 让程序只运行一个实例(Delphi篇)(三种方法,其中使用全局原子的方法比较有意思)

    Windows 下一个典型的特征就是多任务,我们可以同时打开多个窗口进行操作,也可以同时运行程序的多个实例,比如可以打开许多个资源管理器进行文件的移动复制操作.但有时出于某种考虑(比如安全性),我们要 ...

  5. vc++高级班之多线程篇[6]---线程间的同步机制①

    ①.线程同步的必要性:   int g_Num = 0; UINT __cdecl ThreadProc(LPVOID lpParameter) {  for (int idx = 0; idx &l ...

  6. vc++高级班之多线程篇[7]---线程间的同步机制②

    //示例代码: CStringArray g_ArrString; UINT __cdecl ThreadProc(LPVOID lpParameter) {  int startIdx = (int ...

  7. VC只运行一个程序实例

    方法有很多,以下只是提供一种用的多的 一. 单文档程序 在程序App类的InitInstance中添加如下代码 BOOL CDDZApp::InitInstance() { /*只运行一个实例*/ / ...

  8. C#cmd执行命令隐藏窗口,并保持程序一直运行

    把要执行的cmd命令放入一个bat文件里,然后执行: //Process p = Process.Start(bPath); Process pro = new Process();pro.Start ...

  9. 深入浅出话VC++(1)——Windows程序内部运行机制

    一.引言 要想熟练掌握Windows应用程序的开发,首先需要理解Windows平台下程序运行的内部机制,然而在.NET平台下,创建一个Windows桌面程序,只需要简单地选择Windows窗体应用程序 ...

随机推荐

  1. python dom操作

    1.DOM介绍 (1)什么是DOM DOM:文档对象模型.DOM 为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构.目的其实就是为了能让js操作html元素而制定的一个规范. DOM就是由节 ...

  2. Linux下main函数启动过程【程序员自我修养笔记】【自用】

    1. 入口函数和程序初始化 1.1 程序从main开始吗? 当程序执行到main函数的第一行时,很多事情都已经完成了: [证1]如下是一段C语言代码: 代码中可以看到,在程序刚刚执行到main的时候, ...

  3. PHP7 网络编程(三)孤儿进程与僵尸进程

    基本概念 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程.子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 当一个 ...

  4. PHP7 学习笔记(十一)使用phpstudy快速配置一个虚拟主机

    说明:为了windows本地开发php方便,这里推荐使用PHP集成环境phpstudy. 目的:使用域名访问项目(tinywan.test) 1.官网:http://www.phpstudy.net ...

  5. Spark设计理念与基本架构

    1.基本概念 Spark中的一些概念: RDD(resillient distributed dataset):弹性分布式数据集. Partition:数据分区.即一个RDD的数据可以划分为多少个分区 ...

  6. windows配置Java环境变量

    打开电脑的高级系统设置-高级-环境变量 新建系统变量,如果已存在则添加到变量尾部,切勿覆盖 变量名:JAVA_HOME 变量值:C:\Program Files\Java\jdk1..0_102 变量 ...

  7. javaScript ES5常考面试题总结

    js的六种原始值 boolean null undefined number string symbol 坑1: 首先原始类型存储的都是值,是没有函数可以调用的,比如 undefined.toStri ...

  8. 常用Java数据库连接池

    概述 在这里所谓的数据库连接是指通过网络协议与数据库服务之间建立的TCP连接.通常,与数据库服务进行通信的网络协议无需由应用程序本身实现,原因有三: 实现复杂度大,需要充分理解和掌握相应的通信协议. ...

  9. js获取当前城市名

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  10. 关于"Linux下使用Windows应用程序的尝试"总结

    首推 Flatpak .Flatpak爽啊,命令行启动能不爽吗!? 其他的: 0. AppImage:AppImage试了下,唉,启动TIM时就没反应,其他的应用没试过 1. crossover:收费 ...