在 Windows 環境下,雙擊關聯檔案會啟動程式並傳遞路徑參數。多文檔介面(MDI)程式通常要求單一實例:若已運行,新啟動的實例應將參數傳遞給現有實例並自行退出。本文介紹四種防止多重啟動的核心技術。
szWindowName db "Hello World!",0
invoke FindWindow, NULL, offset szWindowName
.if eax != NULL
; 已有實例,傳遞參數並退出
invoke ExitProcess, 0
.endif
缺點:視窗標題極易重複,不可靠。
szClassName db "MY_UNIQUE_CLASS_NAME!",0
invoke FindWindow, offset szClassName, NULL
.if eax != NULL
invoke ExitProcess, 0
.endif
視窗類別名在進程內唯一,通常由 RegisterClassEx 註冊時指定。缺點:無標準視窗(如對話框為主視窗)的程式類別名固定為 #32768,無法區分實例。
.data
szMutex db "Global\\MyApp_Unique_Mutex_Name",0
hMutex dd ?
hInstance dd ?
.code
START:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke CreateMutex, NULL, TRUE, offset szMutex
mov hMutex, eax
invoke GetLastError
cmp eax, ERROR_ALREADY_EXISTS ; 互斥體已存在
jz @F ; 跳轉退出
; 首次運行:正常啟動
invoke WinMain, ...
invoke ReleaseMutex, hMutex ; 正常結束才釋放
@@:
invoke ExitProcess, 0
優點:
Global\\ 前綴)關鍵點:必須用 GetLastError 判斷 ERROR_ALREADY_EXISTS,而非單檢查傳回值(即使已存在也會傳回有效句柄)。
缺點:異常終止(崩潰、強制結束進程)會導致標記殘留,造成誤判;需額外清理機制,複雜度高。
| 方法 | 適用性 | 可靠度 | 推薦等級 |
|---|---|---|---|
| 視窗標題 | 僅限有標題視窗的 GUI | 低 | ⭐ |
| 視窗類別名 | 標準視窗 GUI | 中 | ⭐⭐⭐ |
| Mutex 互斥體 | 所有類型(GUI/控制台/服務) | 高 | ⭐⭐⭐⭐⭐ |
| 檔案/登錄標記 | 簡單場景 | 低(殘留風險) | ⭐⭐ |
下一篇將探討:檢測到已有實例後,如何將新實例的命令列參數傳遞給現有實例(進程間通訊:WM_COPYDATA、命名管道、共享記憶體等)。