方法一: 有时候在开发应用程序时,希望控制程序运行唯一的实例。例如,最常用的mp3播放软件Winamp,由于它需要独占计算机中的音频设备,因此该程序只允许自身运行唯一的一个例程。在Visual C++的开发实践中,对于16位的Windows系统,应用程序的hPrevInstance句柄保存了应用程序上一个运行的实例,可以用该值来检查是否有实例运行;然而在32位Windows系统下,这个值总是NULL,所以无法利用该值来实现程序运行唯一实例。本实例给出了解决这个问题的简单办法,只要将程序中稍微改动一下就可以了。 一、 实现方法 对于具有窗口的应用程序,可以用静态函数CWnd::FindWindow()查找固定窗口,来判断程序是否已经运行。函数原型为:
考虑到程序的健壮性,我们还需要判断窗口是否处于最小化状态、是否有弹出式子窗口,这就需要使用CWnd:: GetLastActivePopup()、CWnd::IsIconic()函数,它们的原型分别为:
对于处于最小化状态的窗口,可以调用CWnd::ShowWindow( int 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、 添加代码,编译运行程序; 三、 程序代码
上述方法虽然实现起来很简单,但是它对于无窗口的应用程序却无能为力。为了解决这个问题,可以通过动态连接库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; } |