在開發一些應用系統的時候,由於程式內在的一些特徵,系統的某些組成子程式只允許執行乙個應用程式例項,以保證業務和資料處理安全。本文將從實際應用角度來分析其實現原理,對三種實現方式進行測試比較,從而確定一種合適的實現方法。文章的例子使用c#語言進行描述。
程序匹配
對於每乙個應用程式執行例項都會包含該例項的乙個或多個程序,而且在程式執行過程中可能會動態的建立或銷毀程序,或者訪問其他現有程序進行通訊。不難發現,在程式最先初始化的那一刻只有乙個程序執行,而且應用程式程序生命週期最大程序名稱集合是不變的。因此,在應用程式初始化的時候,可以根據程序關鍵資訊檢查系統程序列表是否存在同當前初始化程序匹配的程序來確定是否已經執行程序例項。
邏輯處理步驟如下,
1.初始化應用程式,啟動程式初始化程序;
2.訪問系統程序列表,根據初始化程序關鍵資訊進行匹配查詢;
3.沒有找到匹配程序(這一步是不會發生的,因為當前初始化程序也在列表中,不過還要看獲取程序列表的實現**怎麼寫),繼續初始化程序,程式初始化完成執行。
4.找到第乙個匹配程序,判斷找到的程序id是否同初始化程序id相同;
5.如果第乙個匹配程序id同初始化程序id相同,則為當前初始化程序,繼續查詢;
6.沒有找到第二個匹配程序,表明當前執行的是首個例項,繼續初始化程序,程式初始化完成執行。
7.找到第二個,表明已有乙個例項在執行,停止當前程式初始化,提示已有應用程式執行。
8.如果找到第乙個匹配程序id不同,表明已有乙個例項在執行,停止當前程式初始化,提示已有應用程式執行。
可見上面的邏輯實現中用於程序匹配的資訊是關鍵,選擇不當功能就無法實現。在這個例項中筆者使用了應用程式完全檔名稱作為關鍵資訊。
在**中首先需要引用下面命名空間,以呼叫winapi函式。
using system.runtime.interopservices;
把實現唯一執行例項功能的類名取為singleinstance,在類前面加static關鍵字為c# 2.0新增的語言特徵。
public static class singleinstance {}
使用getrunninginstance靜態方法獲取應用程式程序例項,如果沒有匹配程序,返回null值,
public static process getrunninginstance()
}
return null;
}
接下來呼叫兩個winapi,其功能將在包裝方法中描述,
[dllimport("user32.dll")]
private static extern bool showwindowasync(intptr hwnd, int cmdshow);
[dllimport("user32.dll")]
private static extern bool setforegroundwindow(intptr hwnd);
定義類成員輔助變數,
private const int ws_shownormal = 1;
以上的方法宣告為私有,對其進一步包裝,handlerunninginstance靜態方法為獲取應用程式控制代碼,設定應用程式為前台執行,並返回bool值。
public static bool handlerunninginstance(process instance)
對上面的方法建立乙個過載版本,使呼叫**更加簡潔,
public static bool handlerunninginstance()
return false;
}
上面的方法實現獲取已經執行的程序例項的控制代碼,並獲取其焦點顯示到前台,這個很有用,在其他實現方式中也可以用到。
在main函式中呼叫下面**實現單一應用程式例項,
process p = singleinstance.getrunninginstance();
if (p != null) //已經有應用程式副本執行
else //啟動第乙個應用程式
簡潔的呼叫為,
if (singleinstance.handlerunninginstance()== false)
可見,在上面的實現過程中,由於關鍵資訊採用應用程式的完整檔名,因此在檔名稱或路徑名稱修改後,以上實現就會失效。
程序互斥
在這個實現方式中需要定義乙個程序同步基元,可以理解為臨界資源,該資源只允許乙個程序使用。根據這一點實現應用程式唯一執行例項就比較簡單了。
實現步驟如下,
1.應用程式初始化訪問該同步基元;
2.可以訪問,說明該同步基元未被使用,也就是說沒有應用程式例項執行,使用同步基元,可以繼續初始化成為第乙個執行例項。
3.不可以訪問,說明該同步基元已被使用,也就是說已有應用程式例項執行,停止當前程式初始化,提示已有應用程式執行。
4.應用程式例項退出釋放同步基元占用。
在**中筆者使用system.threading.mutex類實現同步基元,實現應用程式例項之間互斥功能。mutex預設名字取assembly.getentryassembly().fullname。
在類成員中宣告同步基元,
private static mutex mutex = null;
createmutex靜態方法建立應用程式程序mutex,返回建立結果為true表示建立成功,false失敗。
public static bool createmutex()
實現其過載方法,讓使用者可以自定義mutex名字,
public static bool createmutex(string name)
對應的釋放mutex資源方法為,
public static void releasemutex()
}
在main函式中呼叫下面**實現單一應用程式例項,
if (singleinstance.createmutex())
else
可見,在上面的實現過程中,mutex名字是同步基元的唯一標識,如果剛好有不同的應用程式使用了相同名稱的mutex,那不同的應用程式例項也會出現互斥現象。
執行標誌
使用應用程式執行標誌簡單來講就是在程式初始化的時候設定乙個標誌表示程式已執行,在程式執行結束的時候刪除該標誌。
基本步驟如下,
1.應用程式初始化檢查執行標誌是否已經設定;
2.發現已經設定,說明已有應用程式例項執行,停止當前程式初始化,提示已有應用程式執行。 3.發現沒有設定,說明沒有應用程式例項執行,繼續當前程式初始化。
4.退出應用程式時刪除該執行標誌。
宣告類成員標誌檔名稱變數,
private static string runflagfullname = null;
初始化程式執行標誌,如果設定成功,返回true,已經設定返回false,設定失敗將丟擲異常,
public static bool initrunflag()
using (filestream fs = new filestream(runflag, filemode.create))
return true;
}
釋放初始化程式執行標誌,如果釋放失敗將丟擲異常,
public static void disposerunflag()
}
獲取或設定程式執行標誌,必須符合windows檔案命名規範,
public static string runflag
return runflagfullname;
}
set
}
在main函式中呼叫下面**實現單一應用程式例項,
if (singleinstance.initrunflag())
else
可見,在上面的實現過程中,需要訪問檔案io,因此有可能會出現異常,對異常需要進行具體處理。如果不同應用程式使用了相同的執行標誌,也會出現程序互斥實現中存在的問題。由於執行標誌存在外部載體中,如果筆者把啟動的應用程式程序例項直接在windows管理器程序列表中結束或使其產生異常,那設定的執行標誌就不會銷毀,應用程式就沒法再次執行。
從乙個應用程式挑到另乙個應用程式
背景 假如有a,b兩個程式 當然都得是你自己寫的 想在a程式中判斷b程式是否存在本機上,存在就啟動他,啟動的時候彈出乙個對話方塊,對話方塊的內容是a程式帶過去的。背景到此結束,下面是實現流程。實現 plain view plain copy 這個方法明白人一看就懂,你要是不懂還是先去看基礎教程吧!這...
保證應用程式只有乙個例項在執行
要實現這樣的功能,方法灰常多,利用命名的事件物件,命名的互斥物件都可以實現,下面寫出這兩種方法的實現 1.命名的互斥物件 void main handle hthread1 handle hthread2 建立互斥物件 hmutex createmutex null,true,tickets if ...
只充許執行乙個應用程式例項
using system using system.collections.generic using system.windows.forms using system.reflection using system.threading using system.diagnostics using...