在 Windows 上開發應用程式時,常需確保同一時間只有一個實例在執行。若使用者重複點擊捷徑,應直接啟動既有視窗而非開啟新視窗。MFC 專案中,最簡單且可靠的做法是在 CWinApp::InitInstance() 中建立具名 Mutex。
// 在 CMyApp::InitInstance() 最前面加入
HANDLE hMutexOneInstance = CreateMutex(NULL, TRUE, _T("Global\\MyApp_Unique_Mutex_Name"));
if (GetLastError() == ERROR_ALREADY_EXISTS) {
// 已有實例在執行
if (hMutexOneInstance) CloseHandle(hMutexOneInstance);
// 可選:將既有視窗帶到前景
CWnd* pWnd = CWnd::FindWindow(_T("MyAppMainWndClass"), NULL);
if (pWnd) {
pWnd->SetForegroundWindow();
if (pWnd->IsIconic()) pWnd->ShowWindow(SW_RESTORE);
}
return FALSE; // 結束新實例
}
// 正常初始化流程...
// 程式結束前記得釋放 Mutex(或由系統自動回收)
Global\\ 前綴(需管理員權限)或 Local\\ 確保跨 Session 可見性;名稱應包含 GUID 或公司/產品前綴避免衝突。GetLastError() 回傳 ERROR_ALREADY_EXISTS。ReleaseMutex 並 CloseHandle;異常終止時系統會自動釋放。FindWindow + SetForegroundWindow 讓使用者感覺「沒有重複開啟」。InitInstance 之後才檢查 Mutex,導致資源已分配完畢才發現重複。CreateMutex 回傳值,導致函數結束時 Handle 遺失,無法正確釋放。若需跨不同登入使用者仍只能有一個實例(如系統服務),需在 Mutex 名稱加上 Global\\ 並確保建立處理序具備 SE_CREATE_GLOBAL_NAME 權限;一般桌面應用僅需 Local\\ 即可。
使用具名 Mutex 是實現單一實例最標準、最穩健的 Windows API 做法,幾行程式碼即可解決重複啟動問題,並可延伸至跨 Session、帶前景視窗等進階需求。