28.VC(custom)-控制一个程序只能有一个进程(单例随手代码)
来源:互联网 发布:java基础教程 csdn 编辑:程序博客网 时间:2024/05/11 00:58
EnumWindows的使用
BOOL EnumWindows( WNDENUMPROClpEnumFunc, LPARAMlParam);该函数枚举所有屏幕上的顶层窗口,并将窗口句柄传送给应用程序定义的回调函数,其中lParam是传递给lpEnumFunc的参数。回调函数返回FALSE将停止枚举,否则EnumWindows函数继续到所有顶层窗口枚举完为止。例如获取所有的桌面窗口句柄,并将其值放到CListBox中:
进程统指应用程序的一个实例
两个问题:
1.在程序的第二个实例启动时,如何发现该程序已有 一个实例在运行
2.如何将第一个实例激活,而第二个实例退出
由于windows并没有给内核对象定义唯一的名字标准,而且不同的内核对象共用一个名字空间,可以借鉴定义一个有名字的内核对象来标识唯一(具体不做说明)
第二个问题的难点是获取第一个实例的主窗对象指针或句柄,然后便可用SetForegroundWindow来激活。虽然FindWindow函数能寻找正运行着的窗口,但该函数要求指明所寻找窗口的标题或窗口类名,不是实现通用方法的途径。我们可以用Win32 SDK函数SetProp来给应用程序主窗设置一个特有的标记。用GetDesktopWindow可以获取Windows系统主控窗口对象指针或句柄,所有应用程序 主窗都可看成该窗口的子窗口,即可用GetWindow函数来获得它们的对象指针或句 柄。用Win32 SDK函数GetProp查找每一应用程序主窗是否包含有我们设置的特定 标记便可确定它是否我们要寻找的第一个实例主窗。使第二个实例退出很简单,只要让其应用程序对InitInstance函数返回FALSE即可。此外,当主窗口退出时 ,应用RemoveProp函数删除我们为其设置的标记。
方法1:
1、在App的InitInstance()中枚举所有窗口,查找本程序实例
HWND oldHWnd = NULL;EnumWindows(EnumWndProc,(LPARAM)&oldHWnd); //枚举所有运行的窗口if(oldHWnd != NULL){AfxMessageBox("本程序已经在运行了");::ShowWindow(oldHWnd,SW_SHOWNORMAL); //激活找到的前一个程序::SetForegroundWindow(oldHWnd); //把它设为前景窗口return false; //退出本次运行}
2、添加EnumWndProc窗口过程函数:
//添加的标识只运行一次的属性名CString g_szPropName = "Your Prop Name"; //自己定义一个属性名HANDLE g_hValue = (HANDLE)1; //自己定义一个属性值BOOL CALLBACK EnumWndProc(HWND hwnd,LPARAM lParam){HANDLE h = GetProp(hwnd,g_szPropName);if( h == g_hValue){*(HWND*)lParam = hwnd;return false;}return true;}
3、在主窗口的 OnInitDialog()中添加属性
<span style="color:#000000;">//设置窗口属性SetProp(m_hWnd,g_szPropName,g_hValue);</span>
方法二:
BOOL CTestApp::InitInstance() { /********************************/ // 用应用程序名创建信号量 HANDLE hSem = CreateSemaphore(NULL, 1, 1, m_pszExeName); // 信号量已存在? // 信号量存在,则程序已有一个实例运行 if (GetLastError() == ERROR_ALREADY_EXISTS) { //关闭信号量句柄 CloseHandle(hSem); //寻找先前实例的主窗口 HWND hWndPrevious = ::GetWindow(::GetDesktopWindow(), GW_CHILD); while (::IsWindow(hWndPrevious)) { // 检查窗口是否有预设的标记? //有,则是我们寻找的主窗 if (::GetProp(hWndPrevious, m_pszExeName)) { // 主窗口已最小化,则恢复其大小 if (::IsIconic(hWndPrevious)) ::ShowWindow(hWndPrevious, SW_RESTORE); // 将主窗激活 ::SetForegroundWindow(hWndPrevious); // 将主窗的对话框激活 ::SetForegroundWindow(::GetLastActivePopup(hWndPrevious)); // 退出本实例 return FALSE; } // 继续寻找下一个窗口 hWndPrevious = ::GetWindow(hWndPrevious, GW_HWNDNEXT); } // 前一实例已存在,但找不到其主窗 // 可能出错了 // 退出本实例 return FALSE; } AfxEnableControlContainer(); //... ... } int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;//设置寻找标记 ljs ::SetProp(m_hWnd, AfxGetApp()->m_pszExeName,(HANDLE)1); m_GameLobbyDlg.Create(this); m_bInit = TRUE; return 0; }CMainFrame::~CMainFrame() { //删除寻找标记 ::RemoveProp(m_hWnd, AfxGetApp()->m_pszExeName); }
方法三:
::CreateMutex(NULL,TRUE,m_pszExeName); if(GetLastError()==ERROR_ALREADY_EXISTS) { // 寻找先前实例的主窗口 HWND hWndPrevious = ::GetWindow(::GetDesktopWindow(), GW_CHILD); while(::IsWindow(hWndPrevious)) { if (::GetProp(hWndPrevious,m_pszExeName)) { // 主窗口已最小化,则恢复其大小 if (::IsIconic(hWndPrevious)) ::ShowWindow(hWndPrevious, SW_RESTORE); // 将主窗激活 ::SetForegroundWindow(hWndPrevious); // 将主窗的对话框激活 ::SetForegroundWindow(::GetLastActivePopup(hWndPrevious)); // 退出本实例 return FALSE; } hWndPrevious = ::GetWindow(hWndPrevious, GW_HWNDNEXT); } return FALSE; }
方法四:
另建线程创建一个窗口,记录APP的m_hWnd,直接发线程消息,激活这个窗口.
- 28.VC(custom)-控制一个程序只能有一个进程(单例随手代码)
- 实现程序只能运行一个实例(单例)
- VC++ 一次只能运行一个程序设置
- c# 控制winform程序只能打开一个
- 单例模式(一个类只能创建一个实例)
- 限制程序只能有一个实例
- python的单例模式,就是一个类只能有一个实例的模式
- 38.VC(custom)-调用临时Fonts(随手代码)
- 43.VC(custom)-richedit实现超链接(随手代码)
- 44.VC(custom)-EDIT密码框切换(随手代码)
- C# 创建互斥进程(程序只能运行一个实例)
- 程序路径相同,只能运行一个进程(重复运行激活界面)
- 软件进程只能存在一个
- 软件进程只能存在一个
- 实现一个应用程序只能打开一个进程
- 一个控制声音的程序(代码如下:)
- vc++创建一个进程
- .NET程序只能启动一个
- Android 开发(如何动态设置EditText输入的文字为密码形式)
- lwip1.4 arp #ifdef __cplusplus 倒底是什么意思?
- 图像熵和信息量
- 创建网站集出错
- 粗略估算
- 28.VC(custom)-控制一个程序只能有一个进程(单例随手代码)
- sleep()和wait()的区别 (转)
- 关于这个android源码分析的博客
- 存储器分类
- javascript的事件(event)
- 37款开源jQuery表格插件
- Javascript的变量与作用域
- struts2文件上传和下载
- SharePoint 获取SPField 相关信息