開發無視窗(Console、Service 或背景工具)Windows 程式時,防止使用者重複啟動多個實例是基本需求。傳統做法使用 FindWindow 檢視窗標題/類別名,但無視窗程式無視窗句柄,且易受竄改影響。本文介紹使用核心物件 Mutex(互斥體) 實現優雅、可靠的單一實例保護。
在程式進入點(main、WinMain 或 MFC InitInstance)放入以下程式碼:
HANDLE hMutex = CreateMutex(
NULL, // 無安全性屬性
FALSE, // 初始不擁有
"RunOnlyOneInstance" // 命名 Mutex,全域可見
);
// 所有進程均可存取此命名 Mutex
if (hMutex == NULL || ERROR_ALREADY_EXISTS == ::GetLastError())
{
// 程式第二次或之後執行,取得 Mutex 已存在錯誤
return FALSE; // 直接結束
}
// ... 正常執行主邏輯 ...
// 程式結束前釋放(系統會自動回收,但建議顯式關閉)
CloseHandle(hMutex);
GetLastError() 為 0;後續呼叫返回現有句柄,GetLastError() 為 ERROR_ALREADY_EXISTS。若需允許最多 N 個實例同時執行(例如授權控制),請改用 Semaphore(信號量):
HANDLE hSem = CreateSemaphore(NULL, N, N, "MyAppInstanceLimit");
if (hSem == NULL || ERROR_ALREADY_EXISTS == ::GetLastError())
{
// 嘗試等待信號
if (WaitForSingleObject(hSem, 0) != WAIT_OBJECT_0)
return FALSE; // 已達上限
}
// ... 執行 ...
ReleaseSemaphore(hSem, 1, NULL); // 釋放一個名額
比起 FindWindow、建立暫存檔、註冊表旗標等方法,Mutex 具備:無視窗需求、核心級同步、自動生命週期管理、跨會話隔離(Global\ 前綴可跨 Terminal Services 會話) 等優勢,是 Windows 單一實例控制的標準解法。