在學習代碼的過程中,遇到了這樣一個問題:一個程式,在需求上只允許產生一個進程,即不可重複運行,於是就產生了如何保證系統中只有一個進程存在的問題。這個問題網上的代碼很多,不過都是一個解決辦法,就是當程式二次啟動並執行時候,如果發現系統中已經存在進程,則退出運行。不過我做的練習想實現另一種保持單例的方法,就是每次運行都殺掉那個老的進程,讓新進程產生,雖然這個做法似乎通用性不好,不過在一些特殊情況還是有用的,比如我這個練習 ^_^
還是先寫一下那比較常見的辦法,蠻簡單:
uses //uses這裡不知道是不是引用了多餘的東西,呵呵,沒檢查~
Windows, Messages, SysUtils, Dialogs;
var
FormHandle : THandle;
begin
FormHandle := windows.OpenMutex(MUTEX_ALL_ACCESS,false,'test'); //這裡的test似乎是可以隨便寫的
if FormHandle <> 0 then
begin
ShowMessage('程式已經運行');
end
else
begin
windows.CreateMutex(nil,false,'test'); ////這裡的test和上面那個要一致,這是對這程式的標識
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end;
end.
注意:這種處理方法的例子很多,寫法也有不少,我這個是最基本的方法,應該是不大嚴謹,不過倒是好用,嘻嘻
下面是我費了好大勁想出來的,殺掉舊進程的做法:
uses
Windows, Messages, SysUtils, Forms, Dialogs, tlhelp32;
var
FormHandle : THandle;
hand:thandle;
lppe:PROCESSENTRY32;
found:boolean;
begin
Hand:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); //這句,不懂,看來的,嘎嘎
if hand>0 then
lppe.dwSize:= sizeof(PROCESSENTRY32); //初始化,沒啥特別的
FormHandle := windows.OpenMutex(MUTEX_ALL_ACCESS,false,'test'); //這裡和上面一樣啦
if FormHandle <> 0 then
begin
found:=Process32First(Hand,lppe); //開始遍曆進程列表啦
while found do
begin
if strpas(lppe.szExeFile) = ExtractFileName(Application.ExeName) then //判斷是否是當前程式的進程
begin
//下面這句是終止這個進程
TerminateProcess(OpenProcess(PROCESS_ALL_ACCESS,FALSE,lppe.th32ProcessID),1);
break; //這句是必須的,因為新進程已經產生,所以同名進程有兩個,殺掉舊的就跳出迴圈了
//不然連新的一起殺掉了,所謂見好就收哇
end;
found:=Process32next(Hand,lppe);
end;
end
else
begin
windows.CreateMutex(nil,false,'test'); //這裡也是
end;
Application.Initialize; //這裡不同,是把它們拿到判斷語句外面了,因為殺掉舊進程,新進程要運行嘛
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
注意:這裡用到的思路是遍曆了進程列表,獲得舊進程,並殺掉。曾經擔心新進程會不會跑到進程列表前面去,不過在後來的測試中感覺進程列表應該是順序添加的,所以新進程應該是在列表的後面的,至少我目前是這個情況嘎。