傳統做法用 FindWindow 檢查視窗類別/標題,但無視窗程式(服務、Console、背景工具)無法適用。使用核心物件 Mutex (互斥體) 是通用、優雅、可靠的解決方案。
#include
HANDLE hMutex = CreateMutex(
NULL, // 預設安全性
FALSE, // 初始不擁有
_T("Global\\MyAppSingleInstanceMutex") // 命名 Mutex,跨 Session 可見
);
if (hMutex == NULL || GetLastError() == ERROR_ALREADY_EXISTS) {
// Mutex 已存在 = 另一實例正在執行
return FALSE; // 直接退出
}
// 正常執行主邏輯...
// 程式結束前釋放(系統自動回收,但建議顯式釋放)
ReleaseMutex(hMutex);
CloseHandle(hMutex);
Global\\ 前綴確保跨 Terminal Services Session 可見(服務/系統帳號下關鍵)。GetLastError() == ERROR_ALREADY_EXISTS。此即判斷重複執行的依據。使用 Semaphore (訊號量) 取代 Mutex:
HANDLE hSem = CreateSemaphore(NULL, N, N, _T("Global\\MyAppMaxNSemaphore"));
if (hSem == NULL || GetLastError() == ERROR_ALREADY_EXISTS) {
// 嘗試等待信號
if (WaitForSingleObject(hSem, 0) != WAIT_OBJECT_0)
return FALSE; // 已達上限
}
// 執行中...
ReleaseSemaphore(hSem, 1, NULL);
CloseHandle(hSem);
初始/最大計數均設為 N,WaitForSingleObject(hSem, 0) 非阻塞嘗試獲取信號,失敗即表示已達上限。
Global\\{Company.Product.Component.GUID}。main/WinMain/ServiceMain 最開頭執行檢查。FindWindow + PostMessage 通知)而非單純退出。