使用互斥物件讓程式只執行一次 (轉)
使用互斥讓只執行一次
“怎麼讓我的程式在執行時不能重複開啟?”經常在論壇上看到有朋友問這方面的問題。本文將比較詳細的說明這一問題,並給出一個較為完善的解決方案。
儘管這已經不是一個新問題了,但這裡還是簡要的說明一下這種技術:這的確是一個相當有用的技術,可能你經常會注意到相當多的程式在執行之後當你再次點選執行時,它只是會回到原來的視窗,而不會執行兩個程式。就如同你在執行時,在外部點開另一個工程時,delphi只是會簡單的將你的當前工程置換而不是執行兩個delphi。這樣的好處是顯而易見的:你不必擔心你的程式在某些情況下被別的惡意執行多次而吃光造成當機。下面我們做進一部的說明:
熟悉的朋友(特別是多執行緒程式設計),相信對互斥物件已經相當熟悉了,它常被用做執行緒間同步的技術手段。這裡我們使用它來防止程式重複執行。我們只是簡要的提一下互斥物件,並不做深入研究:互斥物件把第一次建立它的程式作為主程式,這樣我們只用檢測互斥物件是否已經有主程式就判斷程式是否已經執行過,這裡需要涉及到一個:WaitForSingle該函式的第一個引數為用以檢測的互斥物件,第2個引數的表示函式返回結果前的滯留時間,如果改函式返回wait_TimeOut就表明互斥物件已經有了一個主程式。修改了的工程檔案程式碼如下:(注意:以下的程式碼都出現在工程檔案中,而不是單元檔案中,並且這裡都在最簡單的delphi預設建立的工程基礎上修改)
var:namespace prefix = o ns = "urn:schemas--com::office" />
myMutex:HWND;
begin
myMutex:=CreateMutex(nil,false,'hkOneCopy');// CreateMutex建立互斥物件,並且給互斥物件起一個唯一的名字。
if WaitForSingleObject(myMutex,0)<>wait_TimeOut then//程式沒有被執行過
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
End;
End;
下面的工作是來完善這個程式,我們不僅希望程式可以不被重複執行,而且我們也希望當再次點選程式可檔案時,已經執行的程式能夠做出一些響應。在這裡我們希望它能夠變為最上層的活動視窗以提醒使用者程式已經被執行。為了達到這個目的,我們必須先獲得已經執行程式的視窗控制程式碼,以便使用SetForeGroundWindow(handle)來使程式視窗最前並啟用。為了得到這個控制程式碼,我們必須使用列舉函式EnumWindows來遍歷windows的視窗列表,該函式可以使用一個回撥函式作為引數,並用這個回撥函式來對每一箇中的視窗進行直到最後一個視窗或回撥函式返回false為止,這個回撥函式規定有兩個引數(handle,Cardinal,只用注意第一個handle引數它表示由列舉函式當前遍歷到的視窗控制程式碼)。我們只要編寫這個函式並在其中不斷的比較當前遍歷到的視窗類名和我們的程式的主視窗類名,以及比較視窗可執行檔案的名稱和我們程式的名稱直到找到相同的為止,將這時的視窗控制程式碼儲存下來就可以了,下面的程式碼加上了適當的註釋:
function EnumWndProc(hwnd:Thandle;param:Cardinal):bool;stdcall;
//由於用於api回撥函式,請使用windows傳統的引數傳遞方式stdcall
var
ClassName,WinMoudleName:string;
WinInstance:THandle;
begin
result:=true;
SetLength(ClassName,100);
GetClassName(hwnd,pchar(ClassName),length(ClassName));//獲得當前遍歷視窗的類名
ClassName:=pchar(ClassName);//在字串後加結束符,確定字串結束
if ClassName=TForm1.ClassName then//比較
begin
WinInstance:=GetWindowLong(hwnd,GWL_HINSTANCE);//獲得當前遍歷視窗的例項
setlength(WinMoudleName,100);
GetModuleFileName(WinInstance,pchar(WinMoudleName),length(WinMoudleName));
//獲得當前遍歷視窗的程式檔名
WinMoudleName:=pchar(WinMoudleName);
if WinMoudleName=MoudleName then//MoudleName為工程全域性變數,自身程式的檔名
begin
FindHid:=hwnd;//FindHid為工程全域性變數儲存找到的句炳
result:=false;//找到以後就結束遍歷
end;
end;
end;
下面是全部的工程檔案:
var
hMutex,FindHid:HWND;
MoudleName:string;
begin
hMutex:=CreateMutex(nil,false,'hkOneCopy');
if WaitForSingleObject(hMutex,0)<>wait_TimeOut then
begin
……//略去的程式碼在前文
end
else
begin
SetLength(MoudleName,100);
GetModuleFileName(HInstance,pchar(MoudleName),length(MoudleName));
//獲得自己程式檔名
MoudleName:=pchar(MoudleName);
EnumWindows(@EnumWndProc,0);//呼叫列舉函式
if FindHid<>0 then
SetForegroundWindow(FindHid);
end;
end.
為了使我們的程式更完美,讓它能在重複執行的時候展現更多的特性(如delphi中的置換工程檔案為當前開啟的工程),你還可以向找到的視窗控制程式碼傳送使用者訊息,再在視窗的訊息處理函式中做相應的處理,你一定可以讓我們的程式更眩!
參考文獻:
《delphi開發者指南》
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-982084/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- VC++中實現程式互斥執行 (轉)C++
- 執行緒同步(windows平臺):互斥物件執行緒Windows物件
- 使用cookie讓彈窗只出現一次程式碼Cookie
- PHP通過lock控制程式只執行一次PHP
- C#多執行緒學習(六) 互斥物件C#執行緒物件
- C# 多執行緒學習(6) :互斥物件C#執行緒物件
- python多執行緒程式設計3: 使用互斥鎖同步執行緒Python執行緒程式設計
- 執行緒同步與互斥:互斥鎖執行緒
- linux程式多執行緒互斥鎖的簡單使用Linux執行緒
- 定時器setInterval,只執行一次/第一次延遲執行定時器
- 我命由我不由天!如何只讓程式執行指定時間?
- 多執行緒訪問—限制某個方法只執行一次執行緒
- 為什麼過濾器只執行一次?過濾器
- 執行緒的互斥鎖執行緒
- 讓我們重視程式執行效率 (轉)
- Linux多執行緒的使用一:互斥鎖Linux執行緒
- 執行緒安全佇列(使用互斥鎖進行實現)執行緒佇列
- 使用nohup讓程式永遠後臺執行
- Java static方法塊只獲取一次物件控制程式碼供全域性使用Java物件
- 只允許一個程式執行winformORM
- c++實現程式與執行緒的同步互斥C++執行緒
- 多執行緒(2)-執行緒同步互斥鎖Mutex執行緒Mutex
- 使用nohup命令讓linux程式後臺執行Linux
- Linux之執行緒互斥鎖Linux執行緒
- windows多執行緒同步--互斥量Windows執行緒
- Python 執行緒同步與互斥Python執行緒
- 使用執行緒執行框架的一次經歷執行緒框架
- 多個 py 檔案,放在一個指令碼中執行,使用 TestSuite,怎樣才能只執行一次 setUp ( 已經使用了 @classmethod ) ?指令碼UISSM
- windows多執行緒同步互斥--總結Windows執行緒
- Java多執行緒—執行緒同步(單訊號量互斥)Java執行緒
- winform只允許一個應用程式執行ORM
- 幾維安全,讓程式安全執行
- Nohup命令讓Linux下的程式在後臺執行 - 轉Linux
- java基礎:執行緒與程式;執行緒的分工,協作,互斥;volatile關鍵字Java執行緒
- 讓Pqmagic在Server版中執行 (轉)Server
- C++11多執行緒程式設計(二)——互斥鎖mutex用法C++執行緒程式設計Mutex
- Java並行流:一次搞定多執行緒程式設計難題,讓你的程式飛起來!Java並行執行緒程式設計
- 五、併發控制(1):執行緒的互斥執行緒