// 定義共享資料段
#pragma data_seg("Shared")
int volatile g_lAppInstance = 0;
#pragma data_seg()
// 告知連結器:可讀、可寫、共享
#pragma comment(linker, "/section:Shared,RWS")
原理:所有進程實例映射同一物理記憶體頁面。InitInstance 中遞增計數,大於 1 即退出。
if (++g_lAppInstance > 1) {
AfxMessageBox(_T("程式已在運行"));
return FALSE;
}
優點:無核心物件開銷;缺點:VC 編譯器專屬,跨編譯器不通用。
HANDLE hMutex = CreateMutex(NULL, FALSE, _T("Global\\MyUniqueAppName"));
if (GetLastError() == ERROR_ALREADY_EXISTS) {
CloseHandle(hMutex);
AfxMessageBox(_T("程式已在運行"));
return FALSE;
}
優點:Win32 標準 API,VB (需 API 呼叫)、Delphi、C++Builder、.NET 皆適用;支援跨工作階段 (加 Global\\ 前綴)。
Private Sub Form_Load()
If App.PrevInstance Then
MsgBox "程式已在運行!"
Unload Me
End If
End Sub
VB 執行期自動維護,最簡單但僅限 VB 應用。
// Delphi
var
hMutex: THandle;
begin
hMutex := CreateMutex(nil, False, 'MyUniqueAppName');
if GetLastError = ERROR_ALREADY_EXISTS then begin
CloseHandle(hMutex);
Application.Terminate;
end;
end;
C++Builder 同理呼叫 CreateMutex,無編譯器內建共享段機制。
| 方法 | 適用範圍 | 跨工作階段 | 核心物件 | 備註 |
|---|---|---|---|---|
| 共享資料段 | VC++ 專屬 | 否 | 無 | 效能最佳,但不可移植 |
| 具名互斥體 | 所有 Win32 語言 | 是 (Global\\) | Mutex | 標準推薦作法 |
| VB PrevInstance | VB 6.0 | 否 | 內建 | 最簡單,語言綁定 |
| FindWindow | 所有語言 | 視窗類別名唯一時 | 無 | 不穩定,易誤判 |
FindWindow 檢查視窗標題,極易因版本、語系差異失效