欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
基于.Net平臺應用程序唯一運行實(shí)例實(shí)現
基于.Net平臺應用程序唯一運行實(shí)例實(shí)現

發(fā)布日期: 2006-06-30 | 更新日期: 2006-07-04
作者:鄭佐
適用于: Windows 操作系統
.NET Framework 1.x,2.0運行時(shí)環(huán)境
.NET Windows開(kāi)發(fā)

摘要:本文闡述了在基于.NET平臺的應用程序開(kāi)發(fā)中如何實(shí)現唯一應用程序運行實(shí)例,對幾種實(shí)現方式進(jìn)行分析測試比較,從而尋找一種合適的處理方式。單擊此處才查看本文的示例代碼。

內容索引
概述
進(jìn)程匹配
進(jìn)程互斥
運行標志
功能測試
更多資源

概述
在開(kāi)發(fā)一些應用系統的時(shí)候,由于程序內在的一些特征,系統的某些組成子程序只允許運行一個(gè)應用程序實(shí)例,以保證業(yè)務(wù)和數據處理安全。本文將從實(shí)際應用角度來(lái)分析其實(shí)現原理,對三種實(shí)現方式進(jìn)行測試比較,從而確定一種合適的實(shí)現方法。文章的例子使用C#語(yǔ)言進(jìn)行描述。

進(jìn)程匹配
對于每一個(gè)應用程序運行實(shí)例都會(huì )包含該實(shí)例的一個(gè)或多個(gè)進(jìn)程,而且在程序運行過(guò)程中可能會(huì )動(dòng)態(tài)的創(chuàng )建或銷(xiāo)毀進(jìn)程,或者訪(fǎng)問(wèn)其他現有進(jìn)程進(jìn)行通信。不難發(fā)現,在程序最先初始化的那一刻只有一個(gè)進(jìn)程運行,而且應用程序進(jìn)程生命周期最大進(jìn)程名稱(chēng)集合是不變的。因此,在應用程序初始化的時(shí)候,可以根據進(jìn)程關(guān)鍵信息檢查系統進(jìn)程列表是否存在同當前初始化進(jìn)程匹配的進(jìn)程來(lái)確定是否已經(jīng)運行進(jìn)程實(shí)例。
邏輯處理步驟如下,
1.初始化應用程序,啟動(dòng)程序初始化進(jìn)程;
2.訪(fǎng)問(wèn)系統進(jìn)程列表,根據初始化進(jìn)程關(guān)鍵信息進(jìn)行匹配查找;
3.沒(méi)有找到匹配進(jìn)程(這一步是不會(huì )發(fā)生的,因為當前初始化進(jìn)程也在列表中,不過(guò)還要看獲取進(jìn)程列表的實(shí)現代碼怎么寫(xiě)),繼續初始化進(jìn)程,程序初始化完成運行。
4.找到第一個(gè)匹配進(jìn)程,判斷找到的進(jìn)程ID是否同初始化進(jìn)程ID相同;
5.如果第一個(gè)匹配進(jìn)程ID同初始化進(jìn)程ID相同,則為當前初始化進(jìn)程,繼續查找;
6.沒(méi)有找到第二個(gè)匹配進(jìn)程,表明當前運行的是首個(gè)實(shí)例,繼續初始化進(jìn)程,程序初始化完成運行。
7.找到第二個(gè),表明已有一個(gè)實(shí)例在運行,停止當前程序初始化,提示已有應用程序運行。
8.如果找到第一個(gè)匹配進(jìn)程ID不同,表明已有一個(gè)實(shí)例在運行,停止當前程序初始化,提示已有應用程序運行。

可見(jiàn)上面的邏輯實(shí)現中用于進(jìn)程匹配的信息是關(guān)鍵,選擇不當功能就無(wú)法實(shí)現。在這個(gè)實(shí)例中筆者使用了應用程序完全文件名稱(chēng)作為關(guān)鍵信息。
在代碼中首先需要引用下面命名空間,以調用WinAPI函數。
using System.Runtime.InteropServices;
把實(shí)現唯一運行實(shí)例功能的類(lèi)名取為SingleInstance,在類(lèi)前面加static關(guān)鍵字為C# 2.0新增的語(yǔ)言特征。
public static class SingleInstance {}
使用GetRunningInstance靜態(tài)方法獲取應用程序進(jìn)程實(shí)例,如果沒(méi)有匹配進(jìn)程,返回Null值,
public static Process GetRunningInstance()
{
        Process currentProcess = Process.GetCurrentProcess(); //獲取當前進(jìn)程
        //獲取當前運行程序完全限定名 
        string currentFileName = currentProcess.MainModule.FileName; 
        //獲取進(jìn)程名為ProcessName的Process數組。 
        Process[] processes = Process.GetProcessesByName(currentProcess.ProcessName); 
        //遍歷有相同進(jìn)程名稱(chēng)正在運行的進(jìn)程 
        foreach (Process process in processes) 
       
                if (process.MainModule.FileName == currentFileName) 
               
                        if (process.Id != currentProcess.Id) //根據進(jìn)程ID排除當前進(jìn)程 
                                return process;//返回已運行的進(jìn)程實(shí)例 
               
       
        return null;
}

接下來(lái)調用兩個(gè)WinAPI,其功能將在包裝方法中描述,
[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

定義類(lèi)成員輔助變量,
private const int WS_SHOWNORMAL = 1;

以上的方法聲明為私有,對其進(jìn)一步包裝,HandleRunningInstance靜態(tài)方法為獲取應用程序句柄,設置應用程序為前臺運行,并返回bool值。
public static bool HandleRunningInstance(Process instance)

        //確保窗口沒(méi)有被最小化或最大化 
        ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL); 
        //設置為foreground window 
        return SetForegroundWindow(instance.MainWindowHandle);
}

對上面的方法創(chuàng )建一個(gè)重載版本,使調用代碼更加簡(jiǎn)潔,
public static bool HandleRunningInstance()

        Process p = GetRunningInstance(); 
        if (p != null
       
                HandleRunningInstance(p); 
                return true
       
        return false;
}

上面的方法實(shí)現獲取已經(jīng)運行的進(jìn)程實(shí)例的句柄,并獲取其焦點(diǎn)顯示到前臺,這個(gè)很有用,在其他實(shí)現方式中也可以用到。

在Main函數中調用下面代碼實(shí)現單一應用程序實(shí)例,
Process p = SingleInstance.GetRunningInstance();
if (p != null) //已經(jīng)有應用程序副本執行

        SingleInstance.HandleRunningInstance(p);
}
else //啟動(dòng)第一個(gè)應用程序

        Application.Run(new MainForm());
}

簡(jiǎn)潔的調用為,
if (SingleInstance.HandleRunningInstance()== false)

        Application.Run(new MainForm());
}

可見(jiàn),在上面的實(shí)現過(guò)程中,由于關(guān)鍵信息采用應用程序的完整文件名,因此在文件名稱(chēng)或路徑名稱(chēng)修改后,以上實(shí)現就會(huì )失效。

進(jìn)程互斥
在這個(gè)實(shí)現方式中需要定義一個(gè)進(jìn)程同步基元,可以理解為臨界資源,該資源只允許一個(gè)進(jìn)程使用。根據這一點(diǎn)實(shí)現應用程序唯一運行實(shí)例就比較簡(jiǎn)單了。
實(shí)現步驟如下,
1.應用程序初始化訪(fǎng)問(wèn)該同步基元;
2.可以訪(fǎng)問(wèn),說(shuō)明該同步基元未被使用,也就是說(shuō)沒(méi)有應用程序實(shí)例運行,使用同步基元,可以繼續初始化成為第一個(gè)運行實(shí)例。
3.不可以訪(fǎng)問(wèn),說(shuō)明該同步基元已被使用,也就是說(shuō)已有應用程序實(shí)例運行,停止當前程序初始化,提示已有應用程序運行。
4.應用程序實(shí)例退出釋放同步基元占用。

在代碼中筆者使用System.Threading.Mutex類(lèi)實(shí)現同步基元,實(shí)現應用程序實(shí)例之間互斥功能。Mutex默認名字取Assembly.GetEntryAssembly().FullName。
在類(lèi)成員中聲明同步基元,
private static Mutex mutex = null;

CreateMutex靜態(tài)方法創(chuàng )建應用程序進(jìn)程Mutex,返回創(chuàng )建結果為true表示創(chuàng )建成功,false失敗。
public static bool CreateMutex()

        return CreateMutex(Assembly.GetEntryAssembly().FullName);
}

實(shí)現其重載方法,讓用戶(hù)可以自定義Mutex名字,
public static bool CreateMutex(string name)

        bool result = false
        mutex = new Mutex(true, name, out result); 
        return result;
}

對應的釋放Mutex資源方法為,
public static void ReleaseMutex()

        if (mutex != null
       
                mutex.Close(); 
        }
}

在Main函數中調用下面代碼實(shí)現單一應用程序實(shí)例,
if (SingleInstance.CreateMutex())

        Application.Run(new MainForm()); 
        SingleInstance.ReleaseMutex();
}
else

        MessageBox.Show("程序已經(jīng)運行!");
}

可見(jiàn),在上面的實(shí)現過(guò)程中,Mutex名字是同步基元的唯一標識,如果剛好有不同的應用程序使用了相同名稱(chēng)的Mutex,那不同的應用程序實(shí)例也會(huì )出現互斥現象。

運行標志
使用應用程序運行標志簡(jiǎn)單來(lái)講就是在程序初始化的時(shí)候設置一個(gè)標志表示程序已運行,在程序運行結束的時(shí)候刪除該標志。
基本步驟如下,
1.應用程序初始化檢查運行標志是否已經(jīng)設置;
2.發(fā)現已經(jīng)設置,說(shuō)明已有應用程序實(shí)例運行,停止當前程序初始化,提示已有應用程序運行。 3.發(fā)現沒(méi)有設置,說(shuō)明沒(méi)有應用程序實(shí)例運行,繼續當前程序初始化。
4.退出應用程序時(shí)刪除該運行標志。

對于標志存儲載體可以使用注冊表、數據庫或外部文件等,這里的代碼使用外部文件實(shí)現。對存放標志的文件目錄選擇C:\Documents and Settings\All Users\Application Data,也可以是C:\Program Files\Common Files。
聲明類(lèi)成員標志文件名稱(chēng)變量,
private static string runFlagFullname = null;

初始化程序運行標志,如果設置成功,返回true,已經(jīng)設置返回false,設置失敗將拋出異常,
public static bool InitRunFlag()

        if (File.Exists(RunFlag)) 
       
                return false
       
        using (FileStream fs = new FileStream(RunFlag, FileMode.Create)) 
       
        }
        return true;
}

釋放初始化程序運行標志,如果釋放失敗將拋出異常,
public static void DisposeRunFlag()

        if (File.Exists(RunFlag)) 
       
                File.Delete(RunFlag); 
        }
}

獲取或設置程序運行標志,必須符合Windows文件命名規范,
public static string RunFlag

        get 
       
                if(runFlagFullname == null
               
                        string assemblyFullName = Assembly.GetEntryAssembly().FullName; 
                        string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); 
                        runFlagFullname = Path.Combine(path, assemblyFullName); 
               
                return runFlagFullname; 
       
        set 
       
                runFlagFullname = value
        }
}

在Main函數中調用下面代碼實(shí)現單一應用程序實(shí)例,
if (SingleInstance.InitRunFlag())

        Application.Run(new MainForm()); 
        SingleInstance.DisposeRunFlag();
}
else

        MessageBox.Show("程序已經(jīng)運行!");
}

可見(jiàn),在上面的實(shí)現過(guò)程中,需要訪(fǎng)問(wèn)文件IO,因此有可能會(huì )出現異常,對異常需要進(jìn)行具體處理。如果不同應用程序使用了相同的運行標志,也會(huì )出現進(jìn)程互斥實(shí)現中存在的問(wèn)題。由于運行標志存在外部載體中,如果筆者把啟動(dòng)的應用程序進(jìn)程實(shí)例直接在Windows管理器進(jìn)程列表中結束或使其產(chǎn)生異常,那設置的運行標志就不會(huì )銷(xiāo)毀,應用程序就沒(méi)法再次運行。

功能測試
這一節對上面的三個(gè)功能進(jìn)行測試,以分析之間的區別。功能測試類(lèi)別包括下面五類(lèi),
1.本地系統同一應用程序目錄;
2.本地系統同一應用程序修改運行文件名稱(chēng)使兩次運行名稱(chēng)不同;
3.本地系統兩次運行程序目錄不同,不修改文件名稱(chēng);
4.本地系統不同會(huì )話(huà)用戶(hù)登錄啟動(dòng)應用程序;
5.遠程計算機程序訪(fǎng)問(wèn)啟動(dòng)應用程序(一個(gè)程序在遠程另一個(gè)在本地)。

根據代碼實(shí)現細節不同,對測試的結果可能會(huì )有所不同,這里的測試結果以筆者上面幾節中實(shí)現的代碼為準。為了測試簡(jiǎn)單化,通過(guò)給應用程序傳入測試參數,決定使用哪種方式,入口函數調用代碼為,
[STAThread]
static void Main(string[] args)

        if (args.Length == 0) //沒(méi)有傳送參數 
       
                Process p = SingleInstance.GetRunningInstance(); 
                if (p != null) //已經(jīng)有應用程序副本執行 
                        SingleInstance.HandleRunningInstance(p); 
                else //啟動(dòng)第一個(gè)應用程序 
                        Application.Run(new MainForm()); 
       
        else //有多個(gè)參數 
       
                switch (args[0].ToLower()) 
               
                        case "-api"
                                if (SingleInstance.HandleRunningInstance() == false
                                        Application.Run(new MainForm()); 
                                break
                        case "-mutex"
                                if (args.Length >= 2) //參數中傳入互斥體名稱(chēng) 
                               
                                        if ( SingleInstance.CreateMutex(args[1]) ) 
                                       
                                                Application.Run(new MainForm()); 
                                                SingleInstance.ReleaseMutex(); 
                                       
                                        else 
                                                //調用SingleInstance.HandleRunningInstance()方法顯示到前臺。 
                                                MessageBox.Show("程序已經(jīng)運行!"); 
                               
                                else 
                               
                                        if (SingleInstance.CreateMutex()) 
                                       
                                                Application.Run(new MainForm()); 
                                                SingleInstance.ReleaseMutex(); 
                                       
                                        else 
                                                //調用SingleInstance.HandleRunningInstance()方法顯示到前臺。 
                                                MessageBox.Show("程序已經(jīng)運行!"); 
                               
                                break
                        case "-flag":
//使用該方式需要在程序退出時(shí)調用 
                                if (args.Length >= 2)
//參數中傳入運行標志文件名稱(chēng) 
                                        SingleInstance.RunFlag = args[1]; 
                                try 
                                {
                                        if (SingleInstance.InitRunFlag()) 
                                       
                                                Application.Run(new MainForm()); 
                                                SingleInstance.DisposeRunFlag(); 
                                       
                                        else 
                                                //調用SingleInstance.HandleRunningInstance()方法顯示到前臺。 
                                                MessageBox.Show("程序已經(jīng)運行!"); 
                               
                                catch (Exception ex) 
                               
                                        MessageBox.Show(ex.ToString()); 
                               
                                break
                        default
                                MessageBox.Show("應用程序參數設置失敗。"); 
                                break
               
        }
}

運行CMD命令行,
第一種調用方式:
 WindowsApplication1.exe –api 或 WindowsApplication1.exe
第二種調用方式:
 WindowsApplication1.exe –mutex 或WindowsApplication1.exe –mutex {F140AE26-626C-42f8-BD49-45025742205E}
第三種調用方式:
 WindowsApplication1.exe –flag 或WindowsApplication1.exe –flag c:\blog.csdn.net.zhzuo

測試結果:
匹配/互斥/標志 1同一目錄 2修改名稱(chēng) 3不同目錄 4不同用戶(hù) 5遠程訪(fǎng)問(wèn)
1同一目錄 O/O/O        
2修改名稱(chēng)   X/O/O      
3不同目錄     X/O/O    
4不同用戶(hù)       #/X/O  
5遠程訪(fǎng)問(wèn)         X/O/O

備注:O - 表示成功,X – 表示失敗,# - 程序第二個(gè)運行沒(méi)有反應

針對遠程訪(fǎng)問(wèn)的測試,需要在系統管理工具的.NET Framework 2.0 Configuration中進(jìn)行設置授權該局域網(wǎng)路徑允許訪(fǎng)問(wèn),否則會(huì )拋出System.Security.SecurityException異常。根據測試結果可見(jiàn)三種實(shí)現方式適用范圍不同,理想的實(shí)現是結合他們的優(yōu)點(diǎn)進(jìn)行多點(diǎn)判斷。

更多資源
關(guān)于.NET平臺應用的開(kāi)發(fā),更多的技術(shù)文章可以訪(fǎng)問(wèn)http://blog.csdn.net/zhzuo ,對于本文的建議或意見(jiàn)可在網(wǎng)站上留言。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
C#線(xiàn)程同步- 互斥量 Mutex
android開(kāi)發(fā)教程(十一)——android應用程序基礎
[C# 開(kāi)發(fā)技巧]如何防止程序多次運行
Windows線(xiàn)程同步與互斥技術(shù)總結
怎么讓C#程序同時(shí)只能運行一個(gè)實(shí)例
判斷程序實(shí)例是否已經(jīng)運行的N種方法
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久