防止程序啓動兩次的方法CreateMutex()

在工程文件中, WinMain函數里加上以下代碼
HANDLE hMutex = CreateMutex(NULL, false, "Process");
         if (GetLastError() == ERROR_ALREADY_EXISTS)
         {
            CloseHandle(hMutex);
            MessageBox(Application->Handle, "程序已經在運行中,不能重複啓動!", "提示", MB_OK +MB_ICONWARNING);
            Application->Terminate();
            return 0;
         }
         Application->CreateForm(__classid(TForm1), &Form1);
主要使用到CreateMutex()函數和GetLastError()以及一個常量ERROR_ALREADY_EXISTS.

當然, 你的程序有窗體的話, 還可以使用FindWindow(). 
void *handle = FindWindow(NULL, WindowName.c_str()); 
if (handle!=NULL)
    return 0; 

進程的互斥運行

  正常情況下,一個進程的運行一般是不會影響到其他正在運行的進程的。但是對於某些有特殊要求的如以獨佔方式使用串行口等硬件設備的程序就要求在其進程運行期間不允許其他試圖使用此端口設備的程序運行的,而且此類程序通常也不允許運行同一個程序的多個實例。這就引出了進程互斥的問題。

  實現進程互斥的核心思想比較簡單:進程在啓動時首先檢查當前系統是否已經存在有此進程的實例,如果沒有,進程將成功創建並設置標識實例已經存在的標記。此後再創建進程時將會通過該標記而知曉其實例已經存在,從而保證進程在系統中只能存在一個實例。具體可以採取內存映射文件、有名事件量、有名互斥量以及全局共享變量等多種方法來實現。下面就分別對其中具有代表性的有名互斥量和全局共享變量這兩種方法進行介紹:

// 創建互斥量
HANDLE m_hMutex = CreateMutex(NULL, FALSE, "Sample07");
// 檢查錯誤代碼
if (GetLastError() == ERROR_ALREADY_EXISTS) {
 // 如果已有互斥量存在則釋放句柄並復位互斥量
 CloseHandle(m_hMutex);
 m_hMutex = NULL;
 // 程序退出
 return FALSE;
}

上面這段代碼演示了有名互斥量在進程互斥中的用法。代碼的核心是CreateMutex()對有名互斥量的創建。CreateMutex()函數可用來創建一個有名或無名的互斥量對象,其函數原型爲:
HANDLE CreateMutex(
 LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全屬性的指針
 BOOL bInitialOwner, // 初始化互斥對象的所有者
 LPCTSTR lpName // 指向互斥對象名的指針
);


如果函數成功執行,將返回一個互斥量對象的句柄。如果在CreateMutex()執行前已經存在有相同名字的互斥量,函數將返回這個已經存在互斥量的句柄,並且可以通過GetLastError()得到錯誤代碼ERROR_ALREADY_EXIST。可見,通過對錯誤代碼ERROR_ALREADY_EXIST的檢測可以實現CreateMutex()對進程的互斥。

        建立互斥體,用來同步。如果一個線程獲取了互斥體,則要獲取該互斥體的第二個線程將被掛起,直到第一個線程釋放該互斥體。

參數 
lpMutexAttributes 
指向一個SECURITY_ATTRIBUTES結構的指針,這個結構決定互斥體句柄是否被子進程繼承。     
bInitialOwner 
布爾類型,決定互斥體的創建者是否爲擁有者 
lpName 
指向互斥體名字字符串的指針。互斥體可以有名字。 
互斥體的好處是可以在進程間共享

心得體會:
    CreateMutex() 用於有獨佔要求的程序 (在其進程運行期間不允許其他使用此端口設備的程序運行,或不允許同名程序運行)。如有同名程序運行,則通過 GetLastError()得到錯誤代碼 ERROR_ALREADY_EXIST。

剛纔又執行了下得出的結果(程序名samp)
       一般情況下:一進入調試階段,進程管理器中就出現了samp進程,執行到CreateMutex時返回進程句柄,執行到if(GetLastError() == ERROR_ALREADY_EXISTS ) 進行判斷時,跳過不執行if中的內容,所以表示沒有互斥。
       調試之前先運行debug中的samp.exe再調試:一進入調試階段,進程管理器中就出現了兩個samp進程,執行到CreateMutex時返回進程句柄,執行到if(GetLastError() == ERROR_ALREADY_EXISTS ) 進行判斷時,執行if中的內容,表示有互斥


我們公司的使用方法爲

HANDLE NetIq::CreateMutexNetIq()
{
	HANDLE nMutex = NULL;
	std::string strDeployRole = NetClient::Instance().m_strDeployRole;
	std::string strMutexId = Utils::String::Format("%s%s", NetIQ::Configure::Instance().m_strGuid.c_str(), strDeployRole.c_str());
	nMutex = ::CreateMutex(NULL, FALSE, strMutexId.c_str());
	if( NULL != nMutex )
	{
		DWORD dwErrorCode = ::GetLastError();
		if( ERROR_ALREADY_EXISTS == dwErrorCode )
		{
			__ULOG_INFO(__ULOG_FMT("App", "Mutex (%s) exists"), strMutexId.c_str());
			std::string strTitle;
			if( !RegisterKey::Instance().Read("", "Title", strTitle) )//讀取註冊表中的項目窗口名,,以便在以下將其顯示。國。
			{
				return NULL;
			}

			// instance exist
			HWND hAppWindow = ::FindWindow(NULL, strTitle.c_str());
			if( NULL != hAppWindow )
			{
				::ShowWindow(hAppWindow, SW_SHOWNORMAL);
				::SetWindowPos(hAppWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
				::SetWindowPos(hAppWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
			}

			return NULL;
		}
	}

	return nMutex;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章