zoukankan      html  css  js  c++  java
  • 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 -------------------------------------------
  • 相关阅读:
    python
    car-travel project
    数据库
    kafka笔记
    cloudera笔记
    上课笔记
    structured streaming
    SparkSQL
    流数据
    spark厦门大学
  • 原文地址:https://www.cnblogs.com/liaocheng/p/4243383.html
Copyright © 2011-2022 走看看