本節内容
- 1、使用核心對象
- 2、使用共享資料段
- 3、使用信号量(Semaphore)
- 4、使用事件Event
- 後記
1、使用核心對象
因為核心對象是可以跨程序存在的,是以我們可以通過建立一個命名互斥體(Mutex)核心對象來判斷,當用同一個名字的來建立Mutex時,CreateMutex會傳回一個指向該互斥體的句柄,但是GetLastError會得到ERROR_ALREADY_EXISTS的返值。是以我們就可以判斷程式已有一個執行個體在運作。
m_hmutex = ::CreateMutex( NULL,FALSE,appID);
if(m_hmutex == NULL) return FALSE;
if( ::GetLastError() == ERROR_ALREADY_EXISTS )
{
return FALSE;
}
else
{
return TRUE;
}
HANDLE RunOneByMutex(const char* appString)
{
::SetLastError(NO_ERROR);
HANDLE hMutex = ::CreateMutex(NULL, FALSE, appString);
if (::GetLastError() == ERROR_ALREADY_EXISTS) {
return NULL;
}
return hMutex;
}
2、使用共享資料段
背景知識:EXE和DLL檔案映像由許多區組成如代碼在.text段中,初始化資料在.data段中,未初始化資料在.bss段中。系統在加載EXE和DLL時,實際上是使用了記憶體映射,為了減少加載時間,同一EXE檔案多個執行個體實際在系統中隻有一份。但一般地如果其中某個執行個體對某個資料區進行寫時,系統會使用Copy-On-Write機制将這個資料區在虛拟記憶體中複制一份出來,并映射到該執行個體原先的位址空間,也就實作了程序資料的唯一性,而不會幹擾其它程序。但是我們可以通過設定讓系統關閉掉這個機制。哪麼如何做呢?
在Visual Studio中你可以程式中加上以下幾行:
#pragmacomment(linker,"/SECTION:Share,RWS") //訓示編譯器Share是可讀寫和共享的,當然你也可以通過設定連結器選項直接加上 /SECTION:Share,RWS,不過我更喜歡這個,是以其他朋友就不必自已去設定這個選項了。
// 開始自已的資料段
#pragmadata_seg("Share")
//必需初始化,否則不會将編譯器不會将其放入Share這個區
int g_AppInit =0;
#pragmadata_seg()
還有一種将某個變量置于特别資料段的方式
__declspec(allocate("Share")) int g_AppInit =0;
這種方式的好處是無論你初不初始化這個變量都将置于該Share段内
哪麼如何判斷呢是否啟動了執行個體呢,很簡單,看以下代碼
g_AppInit ++ ;
if(g_AppInit >1)
{
AfxMessageBox("A instance are runed!");
return FALSE;
}
相關的問題:如何通知前一個執行個體
解決了重複啟動的問題,為了獲得更佳的使用者體驗,往往我們要使前一個執行個體激活,如何做呢?使用消息是一個不錯的方法。首先你需要在啟動程式時登記一個全局消息。
WM_APPACTIVE = ::RegisterWindowMessage(appID);
相同的appID字元串會給出相同的消息值,并且總是在0xC000- 0xFFFF區間中,然後當你發現已啟動程式執行個體時通知前一個執行個體:
DWORD dectype = BSM_APPLICATIONS; //僅向應用程式發送
BroadcastSystemMessage(BSF_POSTMESSAGE,&dectype, WM_APPACTIVE, 0,0);
3、使用信号量(Semaphore)
bool RunOneBySemaphore(const char* appString)
{
::SetLastError(NO_ERROR);
HANDLE hSem = CreateSemaphore(NULL, 1, 1, appString);
if(hSem)
{
if(ERROR_ALREADY_EXISTS == GetLastError())
{
CloseHandle(hSem);
hSem = NULL;
//AfxMessageBox(_T("已有一個執行個體在運作!"));
return false;
}
}
else
{
//AfxMessageBox(_T("建立唯一對象失敗,程式退出!"));
return false;
}
return hSem != NULL;
}
4、使用事件Event
#ifdef _AFX
// Makes sure only one instance of the application is running.
BOOL IsSingleInstance( const char* AppTitle /*= NULL */ )
{
HANDLE hEvent;
hEvent = ::CreateEvent(NULL,FALSE,FALSE, (AppTitle==NULL ? AfxGetAppName() : AppTitle ));
if( hEvent==NULL ) {
// Something REALLY went wrong
return FALSE;
};
if( ::GetLastError()==ERROR_ALREADY_EXISTS ) {
// Some other instance is running!
::CloseHandle( hEvent );
return FALSE;
};
// System closes handle automatically when process terminates
return TRUE;
}