zoukankan      html  css  js  c++  java
  • 只允许n个实例进行

    方法一:

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

       一、 实现方法

      对于具有窗口的应用程序,可以用静态函数CWnd::FindWindow()查找固定窗口,来判断程序是否已经运行。函数原型为:
    1. CWnd* PASCAL FindWindow( LPCTSTR lpszClassName, LPCTSTR lpszWindowName );
    复制代码
    这个函数有两个参数,第一个是要找的窗口的类,第二个是要找的窗口的标题。在搜索的时候不一定两者都知道,但至少要知道其中的一个。有的窗口的标题是比较容易得到的,如"计算器",所以搜索时应使用标题进行搜索。但有的软件的标题不是固定的,如"记事本",如果打开的文件不同,窗口标题也不同,这时使用窗口类搜索就比较方便。如果找到了满足条件的窗口,这个函数返回该窗口的指针,否则返回值为NULL。

      考虑到程序的健壮性,我们还需要判断窗口是否处于最小化状态、是否有弹出式子窗口,这就需要使用CWnd:: GetLastActivePopup()、CWnd::IsIconic()函数,它们的原型分别为:
    1. CWnd* GetLastActivePopup( )
    复制代码
    该函数返回一个指定父窗口中最近激活过的弹出式窗口的指针。如果窗口本身是刚刚激活的,或窗口不包含任何弹出窗口,那么该函数返回指向父窗口自身的指针。
    1. BOOL IsIconic( )
    复制代码
    该函数用来判断当前窗口是否处于最小化状态,如果窗口处于最小化状态,函数返回值为True,否则返回Flase。

      对于处于最小化状态的窗口,可以调用CWnd::ShowWindow( int nCmdShow )恢复窗口的正常状态,该函数的原型为:
    1. BOOL ShowWindow( int nCmdShow )
    复制代码
    如窗口之前是可见的,函数调用后返回True,否则返回False。参数nCmdShow的值可以为以下任意个常数:

       SW_HIDE:隐藏窗口,活动状态给令一个窗口;

       SW_MINIMIZE:最小化窗口,活动状态给另一个窗口;

       SW_RESTORE:用原来的大小和位置显示一个窗口,同时令其进入活动状态;

       SW_SHOW:用当前的大小和位置显示一个窗口,同时令其进入活动状态;

       SW_SHOWMAXIMIZED:最大化窗口,并将其激活;

       SW_SHOWMINIMIZED:最小化窗口,并将其激活;

       SW_SHOWMINNOACTIVE:最小化一个窗口,同时不改变活动窗口;

       SW_SHOWNA:用当前的大小和位置显示一个窗口,不改变活动窗口;

       SW_SHOWNOACTIVATE:用最近的大小和位置显示一个窗口,不改变活动窗口;

       SW_SHOWNORMAL:与SW_RESTORE相同;

      最后不要忘记了用CWnd:: SetForegroundWindow()函数将弹出窗口设置为桌面的最前端。

      有了上面的知识,我们就可以修改程序中应用程序类的InitInstance()函数,如果程序已经运行,也即是可以发现相应的程序窗口,那么就显示该窗口,InitInstance()函数就返回False,程序提前退出,否则就正常运行。

    二、 编程步骤

    1、 启动Visual C++6.0,生成一个基于对话框的应用程序,程序命名为"Instance";

    2、 修改程序的InitInstance()函数;

    3、 添加代码,编译运行程序;

    三、 程序代码
    1. /////////////////////////////////////////////////////////////////////////////
    2. // CInstanceApp initialization
    3. BOOL CInstanceApp::InitInstance()
    4. {
    5.   if (!FirstInstance())
    6.    return FALSE;
    7.   AfxEnableControlContainer();
    8.   #ifdef _AFXDLL
    9.    Enable3dControls(); // Call this when using MFC in a shared DLL
    10.   #else
    11.    Enable3dControlsStatic(); // Call this when linking to MFC statically
    12.   #endif
    13.   CInstanceDlg dlg;
    14.   m_pMainWnd = &dlg;
    15.   int nResponse = dlg.DoModal();
    16.   if (nResponse == IDOK)
    17.   {
    18.    // TODO: Place code here to handle when the dialog is
    19.    // dismissed with OK
    20.   }
    21.   else if (nResponse == IDCANCEL)
    22.   {
    23.    // TODO: Place code here to handle when the dialog is
    24.    // dismissed with Cancel
    25.   }
    26.   // Since the dialog has been closed, return FALSE so that we exit the
    27.   // application, rather than start the application's message pump.
    28.   return FALSE;
    29. }

    30. BOOL CInstanceApp::FirstInstance()
    31. {
    32.   CWnd *pWndPrev, *pWndChild;

    33.   // Determine if another window with our class name and Window title exists...
    34.   // The title "Instance " is set up latter, in the InitDialog function.
    35.   if (pWndPrev = CWnd::FindWindow(NULL, "Instance "))
    36.   {
    37.    pWndChild = pWndPrev- >GetLastActivePopup();
    38.    // if so, does it have any popups?
    39.    if (pWndPrev- >IsIconic())
    40.     pWndPrev- >ShowWindow(SW_RESTORE);
    41.     // If iconic, restore the main window
    42.     pWndChild- >SetForegroundWindow();
    43.     // Bring the window to the foreground
    44.    return FALSE;
    45.   }
    46.   else
    47.    return TRUE; // First instance. Proceed as normal.
    48. }
    复制代码
    四、 小结

    上述方法虽然实现起来很简单,但是它对于无窗口的应用程序却无能为力。为了解决这个问题,可以通过动态连接库DLL实现更通用的控制程序运行的方法。在 DLL中使用#pragma data_seg指令实现共享数据段,在该数据段中定义一个变量long m_nRun,并设置其初始值为-1,同时还要在 DLL的入口点函数DllMain返回成功值的语句前添加语句m_nRun++,意思是在应用程序启动连接DLL成功时对已经运行的实例进行计数,然后在 DLL中导出一个函数来返回该变量的值。最后将应用程序的工程设置为依赖于该DLL的工程,在应用程序根据DLL中的m_nRun变量的值来判断是否程序已经运行了。  

    方法二:

    #define UNIQE_NAME "{1AB792D6-EAF2-3267-9A84-9135681127A4}"
    #define GIS_MSG "{D48CA993-4925-41cb-8F59-ABAAAFCEF797}"

    const UINT ID_GIS_INSTANCE = ::RegisterWindowMessage(GIS_MSG); //注册消息

    // 确保程序只有一个实例在运行
    m_hOneInstance = ::CreateMutex(NULL, FALSE, UNIQE_NAME);
    if (GetLastError() == ERROR_ALREADY_EXISTS )//如果存在前一个
    {
      //发送消息,激活实例
      DWORD dwRecipients = BSM_APPLICATIONS;
      ::BroadcastSystemMessage(BSF_NOHANG, &dwRecipients,
       ID_GIS_INSTANCE, // registered window message
       0, 0);    // user defined parameters

      return FALSE;
    }

    ON_REGISTERED_MESSAGE(ID_GIS_INSTANCE, OnGISInstance)
    LRESULT CMainFrame::OnGISInstance(WPARAM wParam, LPARAM lParam)
    {
    theApp.m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
    theApp.m_pMainWnd->SetForegroundWindow();

    ::AfxMessageBox("本程序已经有一个实例在运行了。");

    return 0;
    }
  • 相关阅读:
    CF809D Hitchhiking in the Baltic States
    CF1188D Make Equal
    CF1137 Train Car Selection
    LOJ3215「PA 2019」Muzyka pop
    洛谷4455 [CQOI2018]社交网络 (有向图矩阵树定理)(学习笔记)
    洛谷3571 POI2014 SUP-Supercomputer (斜率优化)
    洛谷2805 [NOI2009]植物大战僵尸 (拓扑排序+最小割)
    洛谷2120 [ZJOI2007]仓库建设(斜率优化dp)
    洛谷2494 [SDOI2011]保密 (分数规划+最小割)
    洛谷3648 [APIO2014]序列分割(斜率优化+dp)
  • 原文地址:https://www.cnblogs.com/kevinzhwl/p/3878857.html
Copyright © 2011-2022 走看看