用VC++實現程式運行唯一執行個體
方法一:
一、 實現方法
對於具有視窗的應用程式,可以用靜態函數CWnd::FindWindow()尋找固定視窗,來判斷程式是否已經運行。函數原型為:
| CWnd* PASCAL FindWindow( LPCTSTR lpszClassName, LPCTSTR lpszWindowName ); |
這個函數有兩個參數,第一個是要找的視窗的類,第二個是要找的視窗的標題。在搜尋的時候不一定兩者都知道,但至少要知道其中的一個。有的視窗的標題是比較容易得到的,如"計算機",所以搜尋時應使用標題進行搜尋。但有的軟體的標題不是固定的,如"記事本",如果開啟的檔案不同,視窗標題也不同,這時使用視窗類別搜尋就比較方便。如果找到了滿足條件的視窗,這個函數返回該視窗的指標,否則傳回值為NULL。
考慮到程式的健壯性,我們還需要判斷視窗是否處於最小化狀態、是否有彈出式子視窗,這就需要使用CWnd:: GetLastActivePopup()、CWnd::IsIconic()函數,它們的原型分別為:
| CWnd* GetLastActivePopup( ) |
該函數返回一個指定父視窗中最近啟用過的彈出式視窗的指標。如果視窗本身是剛剛啟用的,或視窗不包含任何快顯視窗,那麼該函數返回指向父視窗自身的指標。
該函數用來判斷當前視窗是否處於最小化狀態,如果視窗處於最小化狀態,函數傳回值為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、 添加代碼,編譯運行程式;
代碼如下:
BOOL CTestApp::InitInstance()
{//------------添加--------------
if (!FirstInitInstance())
return false;
//--------------end--------------
AfxEnableControlContainer();
//SetDialogBkColor(RGB(160,180,220),RGB(0,0,0));//設定背景顏色
#ifdef _AFXDLL
Enable3dControls();
#else
Enable3dControlsStatic();
#endif
CTestrDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
}
else if (nResponse == IDCANCEL)
{
}
return FALSE;
}
//-----------添加的成員函數FirstInitInstance()---------------
BOOL CTestApp::FirstInitInstance()
{
CWnd *p;
if(p = CWnd::FindWindow(NULL, "ocr"))
{
p->GetLastActivePopup();
if (p->IsIconic())
{
p->ShowWindow(SW_RESTORE);
}
p->SetForegroundWindow();
return false;
}
else
return true;
}
//成員函數的型別宣告是:
public:
CTestApp();
//{{AFX_VIRTUAL(COcrApp)
public:
virtual BOOL InitInstance();
virtual BOOL FirstInitInstance();
//}}AFX_VIRTUAL
方法二:
1.聲明控制代碼HANDLE hApp
2.在InitInstance()函數中寫入以下代碼:
//只運行一個執行個體
hApp = CreateMutex(NULL,FALSE,"OnlyOneInstanceExample");
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
AfxMessageBox("Already Exist An Instance!");
return FALSE;
}
3. 在ExitInstance() 函數中寫入以下代碼:
{
CloseHandle(hApp);
return CWinApp::ExitInstance();
}
方法三:
通過動態串連庫DLL實現更通用的控製程式啟動並執行方法。在DLL中使用#pragma data_seg指令實現共用資料區段,在該資料區段中定義一個變數long m_nRun,並配置其初始值為-1,同時還要在DLL的進入點函數DllMain返回成功值的語句前添加語句m_nRun++,意思是在應用程式啟動串連DLL成功時對已啟動並執行執行個體進行計數,然後在DLL中匯出一個函數來返回該變數的值。最後將應用程式的工程配置為依賴於該DLL的工程,在應用程式根據DLL中的m_nRun變數的值來判斷是否程式已運行了。