標 題:程式執行例項數量的控制——大全篇[原創]
發信人:bellkwong
時 間:2004-3-28 週日, 上午12:44
詳細資訊:
經常會碰到有人問如何保證程式只執行一個例項,原來我也零碎的給過兩三個方法,今天干脆來個大總結,希望對大家在做程式設計的時候有所幫助。
一個程式只執行一個例項(或限制例項數量)通常可以採用如下方法:
1)FindWindow 之<視窗標題>
透過查詢視窗標題來確定上一例項是否正在執行,不適合視窗標題動態變化的程式。
2)FindWindow 之<工作列按紐標題>
透過查詢工作列按紐標題來確定上一例項是否正在執行,不適合按紐標題動態變化的程式(如Winamp)。通常情況下,該方法還是優先考慮,因為按紐標題是一般是固定的。
3)Window Property
將某個資料(可以是字串或控制程式碼)透過SetProp加入到指定視窗的property list,程式執行時列舉視窗並檢查該資料是否存在來確定上一例項是否正在執行。
4)全域性Atom
將某個特定字串透過GlobalAddAtom加入全域性原子表(Global Atom Table),程式執行時檢查該串是否存在來確定上一例項是否正在執行。該方法有個侷限,就是程式終止前必須顯式呼叫GlobalDeleteAtom來釋放atom,否則該atom不會自動釋放,如果程式執行時意外終結了,那麼下一個例項就無法正常執行。早期版本的realplayer就存在這個現象,不知道是不是採用了該方法。
5)Mutex/Event/Semaphore
透過互斥物件/訊號量/事件等執行緒同步物件來確定例項是否存在,在NT下要注意許可權問題(SID)。
6)DLL全域性共享區域
VC下的DLL工程可以透過下面程式碼來建立一個程式間共享資料段:
#pragma data_seg(".share")
//shared for all processes that attach to the dll
DWORD dllgs_dwRunCount = 1; //一定要在這裡對變數進行初始化,否則工夫白做!
#pragma data_seg()
#pragma comment(linker,"/section:.share,rws")
匯出3個函式,分別為:
DWORD IncRunCount(void); //執行計數器加1,返回計數器結果
DWORD DecRunCount(void); //執行計數器減1,返回計數器結果
DWORD GetRunCount(void); //取當前執行計數器
由於DLL全域性共享段在對映到各個程式地址空間時僅會被初始化一次,並且是在首次被windows載入時,所以利用該共享段資料就能對程式例項進行可靠計數。
7)記憶體對映檔案(File Mapping)
透過把程式例項資訊(如視窗控制程式碼、計數器等等)放置到跨程式的記憶體對映檔案,同樣可以控制程式例項執行的數量,道理與DLL全域性共享區域類似。
8)其它
曾經見過有人透過登錄檔、磁碟檔案等途徑來處理例項控制問題,但由於這些參考物件均為非易失性資源,在碰到程式非正常結束且沒有清除例項標識時相當麻煩,真正使用起來具有很大的侷限性。
總結:前面三種方法適用於擁有窗體的程式,而後面幾種則沒有這個限制,但相對而言後者實現起來較複雜。不管採用哪種方法,參考物件均必須具有可共享、跨程式、易失性、重啟自復位等必要性質。