程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> 用VC++實現控制程序運行唯一實例

用VC++實現控制程序運行唯一實例

編輯:vc教程

  有時候在開發應用程序時,希望控制程序運行唯一的實例。例如,最常用的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變量的值來判斷是否程序已經運行了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved