VC++实现程序只运行一个实例

原文地址:http://www.cctry.com/thread-8229-1-1.html

                  http://www.vckbase.com/index.php/wv/302

方法一:

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

   一、 实现方法

  对于具有窗口的应用程序,可以用静态函数CWnd::FindWindow()查找固定窗口,来判断程序是否已经运行。函数原型为:

CWnd* PASCAL FindWindow( LPCTSTR lpszClassName, LPCTSTR lpszWindowName );


这个函数有两个参数,第一个是要找的窗口的类,第二个是要找的窗口的标题。在搜索的时候不一定两者都知道,但至少要知道其中的一个。有的窗口的标题是比较容易得到的,如"计算器",所以搜索时应使用标题进行搜索。但有的软件的标题不是固定的,如"记事本",如果打开的文件不同,窗口标题也不同,这时使用窗口类搜索就比较方便。如果找到了满足条件的窗口,这个函数返回该窗口的指针,否则返回值为NULL。

  考虑到程序的健壮性,我们还需要判断窗口是否处于最小化状态、是否有弹出式子窗口,这就需要使用CWnd:: GetLastActivePopup()、CWnd::IsIconic()函数,它们的原型分别为:

CWnd* GetLastActivePopup( ) 

 

该函数返回一个指定父窗口中最近激活过的弹出式窗口的指针。如果窗口本身是刚刚激活的,或窗口不包含任何弹出窗口,那么该函数返回指向父窗口自身的指针。

BOOL IsIconic( )


该函数用来判断当前窗口是否处于最小化状态,如果窗口处于最小化状态,函数返回值为True,否则返回Flase。

  对于处于最小化状态的窗口,可以调用CWnd::ShowWindow( int nCmdShow )恢复窗口的正常状态,该函数的原型为:

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、 添加代码,编译运行程序;

三、 程序代码

/
// CInstanceApp initialization
BOOL CInstanceApp::InitInstance()
{
  if (!FirstInstance()) 
   return FALSE; 
  AfxEnableControlContainer(); 
  #ifdef _AFXDLL 
   Enable3dControls(); // Call this when using MFC in a shared DLL 
  #else 
   Enable3dControlsStatic(); // Call this when linking to MFC statically 
  #endif 
  CInstanceDlg dlg; 
  m_pMainWnd = &dlg;
  int nResponse = dlg.DoModal(); 
  if (nResponse == IDOK) 
  { 
   // TODO: Place code here to handle when the dialog is 
   // dismissed with OK 
  } 
  else if (nResponse == IDCANCEL) 
  { 
   // TODO: Place code here to handle when the dialog is 
   // dismissed with Cancel 
  } 
  // Since the dialog has been closed, return FALSE so that we exit the 
  // application, rather than start the application's message pump. 
  return FALSE; 
}

BOOL CInstanceApp::FirstInstance()
{
  CWnd *pWndPrev, *pWndChild; 

  // Determine if another window with our class name and Window title exists... 
  // The title "Instance " is set up latter, in the InitDialog function.
  if (pWndPrev = CWnd::FindWindow(NULL, "Instance "))
  { 
   pWndChild = pWndPrev- >GetLastActivePopup();
   // if so, does it have any popups? 
   if (pWndPrev- >IsIconic()) 
    pWndPrev- >ShowWindow(SW_RESTORE); 
    // If iconic, restore the main window 
    pWndChild- >SetForegroundWindow(); 
    // Bring the window to the foreground 
   return FALSE; 
  } 
  else 
   return TRUE; // First instance. Proceed as normal. 
}


四、 小结

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

方法二:

要使应用程序只运行一个实例,一个简单的方法是在应用程序类中使用互斥量,这可以用VC下的GUIDGEN.EXE程序产生.GUIDGEN.EXE位于VC安装目录CommonTools目录下

实例

1: 新建一基于对话框的工程ex1,采用默认设置

2: 用GUIDGEN.EXE产生一个全局标志,#define one "产生的全局标志"

本例中产生的语句如下:#define one "0xbe8e2ce1, 0xdab6, 0x11d6, 0xad, 0xd0, 0x0, 0xe0, 0x4c, 0x53, 0xf6, 0xe6"

3: 在应用程序类CEx1App::InitInstance()中,用CreateMutex函数创建一个互斥量,后调用函数GetLastError()

如果结果等于ERROR_ALREADY_EXISTS说明已经有一个实例在运行了这时返回FALSE.

BOOL CEx1App::InitInstance() 
02.{    
03.    
handle=::CreateMutex(NULL,FALSE,one);//handle为声明的HANDLE类型的全局变量 
04.    
if(GetLastError()==ERROR_ALREADY_EXISTS)     
05.    
{    
06.        
AfxMessageBox("应用程序已经在运行"); 
07.        
return FALSE;    
08.    
} 
09.}


 

4:在CEx1App::ExitInstance()中,删除这个互斥量

int CEx1App::ExitInstance() 
2.{  
3.    
CloseHandle(handle);     
4.    
return CWinApp::ExitInstance(); 
5.}


 



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值