vc++高级班之窗口篇[4]---让程序只运行一个实例

大家都看过或者使用过类似只运行一个实例的程序,比如: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 -------------------------------------------

时间: 2024-10-23 11:28:22

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

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

方法一: 有时候在开发应用程序时,希望控制程序运行唯一的实例.例如,最常用的mp3播放软 件Winamp,由于它需要独占计算机中的音频设备,因此该程序只允许自身运行唯一的一个例程.在Visual C++的开发实践中,对于16位的Windows系统,应用程序的hPrevInstance句柄保存了应用程序上一个运行的实例,可以用该值来检查是否 有实例运行:然而在32位Windows系统下,这个值总是NULL,所以无法利用该值来实现程序运行唯一实例.本实例给出了解决这个问题的简单办法,只 要将程序中稍

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

Windows 下一个典型的特征就是多任务,我们可以同时打开多个窗口进行操作,也可以同时运行程序的多个实例,比如可以打开许多个资源管理器进行文件的移动复制操作.但有时出于某种考虑(比如安全性),我们要做出一些限制,让程序只能够运行一个实例.在Delphi编程中,笔者总结出了以下几种方法: 一. 查找窗口法 这是最为简单的一种方法.在程序运行前用FindWindow函数查找具有相同窗口类名和标题的窗口,如果找到了,就说明已经存在一个实例.在项目源文件的初始化部分添加以下代码: [delphi] v

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

①.线程同步的必要性: int g_Num = 0; UINT __cdecl ThreadProc(LPVOID lpParameter) { for (int idx = 0; idx < 100; ++idx) { g_Num = g_Num+1; CString strNum; strNum.Format(_T("%d"), g_Num); g_Num = g_Num-1; } return 0; } void CThreadTestDlg::OnBnClickedBtn

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

//示例代码: CStringArray g_ArrString; UINT __cdecl ThreadProc(LPVOID lpParameter) { int startIdx = (int)lpParameter; for (int idx = startIdx; idx < startIdx+100; ++idx) { CString str; str.Format(_T("%d"), idx); g_ArrString.Add(str); } return 0; }

VC++环境下多文档模板应用程序开发(带源码)

我们以前见到的关于VC++环境下利用APP Wizard 自动生成的MDI的应用程序只支持打开同一文档类型的多个文件,但是不能够同时打开不同种类型的文档.网上的这种公开资料比较少,我在知网上查阅了相关的资料.下面我根据这些资料做一下总结(辛辛苦苦一个一个字码出来的). 下面设计一个能够处理两种文档类型的应用程序:第一种文档类型:TXT文档,第二种文档类型:Bub的文档类型. 第一种的文档类型TXT,是利用APP Wizard自动生成的,只不过是在设置的时候将文档类型设置为TXT类型,并且使生成的

高级班:影调与直方图

橄榄图课堂笔记: 高级班真的能点燃一个人. 处理照片前,先问自己要把照片处理成特殊的高调(白色占大部分)还是低调(黑色占大部分),还是正常调. 我们以正常调为主,特效是偶尔. 直方图反映明暗分布,可以判断曝光是否正常. ------------ 然而,不是用色阶去看,用色阶看是不太懂PS的. 用窗口--直方图: 并且记得把感叹号点掉,那才反映真实的像素. 记得这个分析仅仅针对正常影调.

VC实现A进程窗口嵌入到B进程窗口中显示的方法

这篇文章主要介绍了VC实现A进程窗口嵌入到B进程窗口中显示的方法,对于理解windows程序运行原理的进程问题有一定的帮助,需要的朋友可以参考下 本文通过一个Demo示例讲述把A应用程序嵌入到B应用程序中显示的方法. 主要代码如下: <span style="font-size:12px;font-weight: normal;">//在B应用启动时创建A进程 CreateProcess(_T("A.exe"),NULL,NULL,NULL,FALSE,

VC++获取屏幕大小第二篇 物理大小GetDeviceCaps 上

分享一下我老师大神的人工智能教程吧.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net 上一篇<VC++获取屏幕大小第一篇像素大小GetSystemMetrics>中介绍了使用GetSystemMetrics函数来获取屏幕的像素大小,本篇将介绍使用GetDeviceCaps函数来获取屏幕的物理大小.下面来看看GetDeviceCaps函数的用法: 函数功能:用于得到被定义的系统数据或者系统配置信息 函数原型:获取一些

iOS开发——高级技术精选OC篇&amp;Runtime之字典转模型实战

Runtime之字典转模型实战 如果您还不知道什么是runtime,那么请先看看这几篇文章: http://www.cnblogs.com/iCocos/p/4734687.html http://www.cnblogs.com/iCocos/p/4676679.html http://www.cnblogs.com/iCocos/p/4725527.html 关于runtime的详细介绍及其相关的小实例 好了,这里就不多废话了,直接开干! 先来看看怎么使用Runtime给模型类赋值 iOS开发