`
qoz790qo
  • 浏览: 14979 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

使应用程序只能运行一个实例

 
阅读更多

使应用程序只能运行一个实例
2010年07月16日
  这里涉及两个基本的问题,一是在程序的第二个实例启动时,如何发现该程序已有     
  一个实例在运行,而是如何将第一个实例激活,而第二个实例退出。   
  方法一: 
  对于第一个问题,可以通过给应用程序设置信号量,实例启动时首先检测该信号量,     
  如已存在,则说明程序已运行一个实例。   
  第二个问题的难点是获取第一个实例的主窗对象指针或句柄,然后便可用     
  SetForegroundWindow来激活。虽然FindWindow函数能寻找正运行着的窗口,但该函     
  数要求指明所寻找窗口的标题或窗口类名,不是实现通用方法的途径。   
  我们可以用Win32   SDK函数SetProp来给应用程序主窗设置一个特有的标记。   
  用GetDesktopWindow   可以获取Windows系统主控窗口对象指针或句柄,所有应用程   
  序主窗都可看成该窗口的子窗口,即可用GetWindow函数来获得它们的对象指针或句   
  柄。用Win32   SDK函数GetProp查找每一应用程序主窗是否包含有我们设置的特定标   
  记便可确定它是否我们要寻找的第一个实例主窗。使第二个实例退出很简单,只要   
  让其应用程序对象的InitInstance函数返回FALSE即可。此外,当主窗口退出时,应   
  用RemoveProp函数删除我们为其设置的标记。   
  下面的InitInstance、OnCreate和OnDestroy函数代码将实现上述的操作:   
  BOOL   CEllipseWndApp::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_pszAppName))     
  {     
  //   主窗口已最小化,则恢复其大小 这里针对最小化的情况,如果不是最小化,则取消if判断   
  if   (::IsIconic(hWndPrevious))     
  ::ShowWindow(hWndPrevious,SW_RESTORE);     
  //   将主窗激活     
  ::SetForegroundWindow(hWndPrevious);     
  //   将主窗的对话框激活     
  ::SetForegroundWindow(     
  ::GetLastActivePopup(hWndPrevious));     
  //   退出本实例     
  return   FALSE;     
  }     
  //   继续寻找下一个窗口     
  hWndPrevious   =   ::GetWindow(hWndPrevious,GW_HWNDNEXT);   
  }     
  //   前一实例已存在,但找不到其主窗     
  //   可能出错了     
  //   退出本实例     
  return   FALSE;     
  }     
  AfxEnableControlContainer();     
  //   Standard   initialization     
  //   If   you   are   not   using   these   features   and   wish   to   reduce   the   size     
  //   of   your   final   executable,   you   should   remove   from   the   following     
  //   the   specific   initialization   routines   you   do   not   need.     
  #ifdef   _AFXDLL     
  Enable3dControls();   //   Call   this   when   using   MFC   in   a   shared   DLL     
  #else     
  Enable3dControlsStatic();//   Call   this   when   linking   to   MFC   statically     
  #endif     
  CEllipseWndDlg   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;     
  }     
  int   CEllipseWndDlg::OnCreate(LPCREATESTRUCT   lpCreateStruct)       
  {     
  if   (CDialog::OnCreate(lpCreateStruct)   ==   -1)     
  return   -1;     
  //   设置寻找标记     
  ::SetProp(m_hWnd,   AfxGetApp()->m_pszAppName,   (HANDLE)1);     
  return   0;     
  }     
  void   CEllipseWndDlg::OnDestroy()       
  {     
  CDialog::OnDestroy();     
  //   删除寻找标记     
  ::RemoveProp(m_hWnd,   AfxGetApp()->m_pszExeName);       
  }   
  方法二:
  使用互斥器CMutex
  缺点:
  当用户已TS的方式登陆的时候,他们是可以打开两个实例,即方法一和方法二无效。
  解决方案:
  方法三:锁定文件
  // 程序只能运行一次
  m_hLockFile = CreateFile(_T("lockfile.sys"), GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  if( INVALID_HANDLE_VALUE == m_hLockFile) 
  {
  AfxMessageBox(_T("程序不能重复打开!"));
  return FALSE;
  }
  方法四:巧用程序共享区域
  1.设定共享变量
  #pragma data_seg("share_data")
  int _app_count_ = 0;
  #pragma data_seg()
  #pragma comment(linker, "/section:share_data,RWS")
  2. 在Instance函数中写入如下代码
  if(_app_count_ > 0) return FAlSE;    // 已经有实例在运行
  else _app_count_++;
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics