Mutex 作為系統核心對象是可以跨進程的(臨界區就不行), 我們可以利用互斥對象禁止程序重復啟動.
工作思路:
先用 OpenMutex 嘗試打開一個自定義名稱的 Mutex 對象, 如果打開失敗說明之前沒有這個對象存在;
如果之前沒有這個對象, 馬上用 CreateMutex 建立一個, 此時的程序應該是第一次啟動;
再重復啟動時, 那個 OpenMutex 就有結果了, 然後強制退出.
最後在程序結束時用 CloseHandle 釋放 Mutex 對象.
function OpenMutex(
dwDesiredAccess: DWORD; {打開權限}
bInheritHandle: BOOL; {能否被當前程序創建的進程繼承}
pName: PWideChar {Mutex 對象的名稱}
): THandle; stdcall; {成功返回 Mutex 的句柄; 失敗返回 0}
注意, 這裡的 CreateMutex 函數應該有個名了, 因為 OpenMutex 要用到;
另外, CreateMutex 的第二個參數已經不重要了(也就是 True 和 False 都行), 因為這裡是用其名稱來判斷的.
程序可以這樣寫:unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
hMutex: THandle;
const
NameMutex = 'MyMutex';
procedure TForm1.FormCreate(Sender: TObject);
begin
if OpenMutex(MUTEX_ALL_ACCESS, False, NameMutex) <> 0 then
begin
ShowMessage('該程序已啟動');
Application.Terminate;
end;
hMutex := CreateMutex(nil, False, NameMutex);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
CloseHandle(hMutex);
end;
end.
這一般都是寫在 dpr 主程序裡, 省得讓後啟動的程序執行些無用的代碼:program Project1;
uses
Forms, Windows,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
var
hMutex: THandle;
const
NameMutex = 'MyMutex';
begin
{主線程入口}
if OpenMutex(MUTEX_ALL_ACCESS, False, NameMutex) <> 0 then
begin
MessageBox(0, '該程序已啟動', '提示', MB_OK);
Application.Terminate;
end;
hMutex := CreateMutex(nil, False, NameMutex);
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
CloseHandle(hMutex);
{主線程出口}
end.