大家都看过或者使用过类似只运行一个实例的程序,比如: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. Linux记录-配置sudoers无密登录和环境变量

    su root vim /etc/sudoers.d/sfapp sfapp ALL=(ALL) ALLsfapp ALL=(ALL) NOPASSWD: ALL Defaults !env_rese ...

  2. springMVC下载中文文件名乱码【原】

    重点就在于添加  "attachment;filename*=utf-8'zh_cn'" + fileName //遇到的现象是,下载含有中文文件名的文件时,能获取到文件,但是使用 ...

  3. Process和ProcessBuilder入门【原】

    ProcessBuilder优点 ProcessBuilder(XXX).start()和Runtime.exec(XXX)功能相同,主要优点在使用过程中感受有: 前者是jdk1.5后的新方式 配置环 ...

  4. 【leetcode-125】 验证回文串

    给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写. 说明:本题中,我们将空字符串定义为有效的回文串. 示例 1: 输入: "A man, a plan, a c ...

  5. python 有趣的库练习

    这里会将看到别人玩过有趣的实践并记录下来,会是一个长期更新的过程... 以下大部分均非原创变化自网络,只是觉得有趣便记录下来了,如有侵权,请告知删除... 自动化脚本... 20个必不可少的Pytho ...

  6. java操作数据库:增删改查

    不多bb了直接上. 工具:myeclipse 2016,mysql 5.7 目的:java操作数据库增删改查商品信息 test数据库的goods表 gid主键,自增 1.实体类Goods:封装数据库数 ...

  7. HanLP中人名识别分析

    HanLP中人名识别分析 在看源码之前,先看几遍论文<基于角色标注的中国人名自动识别研究> 关于命名识别的一些问题,可参考下列一些issue: 名字识别的问题 #387 机构名识别错误 关 ...

  8. T-SQL常见基础疑点问答总结

    --建立测试环境 IF object_id('tb') IS NOT NULL     DROP TABLE tb GO   ,),v )) GO INSERT tb SELECT 'a' UNION ...

  9. Python pipenv

    pipenv都包含什么? pipenv 是 Pipfile 主要倡导者.requests 作者 Kenneth Reitz 写的一个命令行工具,主要包含了Pipfile.pip.click.reque ...

  10. mysql 查询优化 ~ select count 知多少

    一 简介:今天咱们来聊聊mysql的查询总数 二 具体介绍 1 从引擎层面说 myisam  myisam的扫描总行数是非常快的,这是因为myisam会将表的总行数存储起来,定期维护,但是注意,一旦加 ...