C#編程中設(shè)置程序只可被運(yùn)行一次的方法
防止程序運(yùn)行多個(gè)實(shí)例的方法有多種,如:通過(guò)使用互斥量和進(jìn)程名等.而我想要實(shí)現(xiàn)的是:在程序運(yùn)行多個(gè)實(shí)例時(shí)激活的是第一個(gè)實(shí)例,使其獲得焦點(diǎn),并在前端顯示.
主要用到兩個(gè)API 函數(shù):
ShowWindowAsync 該函數(shù)設(shè)置由不同線程產(chǎn)生的窗口的顯示狀態(tài)。
SetForegroundWindow 該函數(shù)將創(chuàng)建指定窗口的線程設(shè)置到前臺(tái),并且激活該窗口。鍵盤(pán)輸入轉(zhuǎn)向該窗口,并為用戶改各種可視的記號(hào)。系統(tǒng)給創(chuàng)建前臺(tái)窗口的線程分配的權(quán)限稍高于其他線程。
代碼如下:
引用以下命名空間:
using System.Runtime.InteropServices; using System.Diagnostics; using System.Reflection; //***************************************************** static class Program { /// <summary> /// 該函數(shù)設(shè)置由不同線程產(chǎn)生的窗口的顯示狀態(tài)。 /// </summary> /// <param name="hWnd">窗口句柄</param> /// <param name="cmdShow">指定窗口如何顯示。查看允許值列表,請(qǐng)查閱ShowWlndow函數(shù)的說(shuō)明部分。</param> /// <returns>如果函數(shù)原來(lái)可見(jiàn),返回值為非零;如果函數(shù)原來(lái)被隱藏,返回值為零。</returns> [DllImport("User32.dll")] private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow); /// <summary> /// 該函數(shù)將創(chuàng)建指定窗口的線程設(shè)置到前臺(tái),并且激活該窗口。鍵盤(pán)輸入轉(zhuǎn)向該窗口,并為用戶改各種可視的記號(hào)。系統(tǒng)給創(chuàng)建前臺(tái)窗口的線程分配的權(quán)限稍高于其他線程。 /// </summary> /// <param name="hWnd">將被激活并被調(diào)入前臺(tái)的窗口句柄。</param> /// <returns>如果窗口設(shè)入了前臺(tái),返回值為非零;如果窗口未被設(shè)入前臺(tái),返回值為零。</returns> [DllImport("User32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd); private const int WS_SHOWNORMAL = 1; /// <summary> /// 應(yīng)用程序的主入口點(diǎn)。 /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Process instance = RunningInstance(); if (instance == null) { Form1 frm = new Form1(); Application.Run(new Form1()); } else { HandleRunningInstance(instance); } } /// <summary> /// 獲取正在運(yùn)行的實(shí)例,沒(méi)有運(yùn)行的實(shí)例返回null; /// </summary> public static Process RunningInstance() { Process current = Process.GetCurrentProcess(); Process[] processes = Process.GetProcessesByName(current.ProcessName); foreach (Process process in processes) { if (process.Id != current.Id) { if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName) { return process; } } } return null; } /// <summary> /// 顯示已運(yùn)行的程序。 /// </summary> public static void HandleRunningInstance(Process instance) { ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL); //顯示,可以注釋掉 SetForegroundWindow(instance.MainWindowHandle); //放到前端 } }
實(shí)現(xiàn)讓程序只能打開(kāi)一個(gè)實(shí)例(其他方法)
//=====創(chuàng)建互斥體法:===== bool blnIsRunning; Mutex mutexApp = new Mutex(false, Assembly.GetExecutingAssembly().FullName, out blnIsRunning); if (!blnIsRunning) { MessageBox.Show("程序已經(jīng)運(yùn)行!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } //保證同時(shí)只有一個(gè)客戶端在運(yùn)行 System.Threading.Mutex mutexMyapplication = new System.Threading.Mutex(false, "OnePorcess.exe"); if (!mutexMyapplication.WaitOne(100, false)) { MessageBox.Show("程序" + Application.ProductName + "已經(jīng)運(yùn)行!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } //=====判斷進(jìn)程法:(修改程序名字后依然能執(zhí)行)===== Process current = Process.GetCurrentProcess(); Process[] processes = Process.GetProcessesByName(current.ProcessName); foreach (Process process in processes) { if (process.Id != current.Id) { if (process.MainModule.FileName == current.MainModule.FileName) { MessageBox.Show("程序已經(jīng)運(yùn)行!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } } }
實(shí)現(xiàn)程序自重啟
程序運(yùn)行過(guò)程中,不能有多個(gè)實(shí)例運(yùn)行,并且需要程序自己可以重啟(重新運(yùn)行),所以代碼如果下代碼:
static void Main() { bool createNew; using (System.Threading.Mutex m = new System.Threading.Mutex(true, Application.ProductName, out createNew)) { if (createNew) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } else { MessageBox.Show("Only one instance of this application is allowed!"); } } } Boolean createdNew; //返回是否賦予了使用線程的互斥體初始所屬權(quán) System.Threading.Mutex instance = new System.Threading.Mutex(true, "MutexName", out createdNew); //同步基元變量 if (createdNew) //賦予了線程初始所屬權(quán),也就是首次使用互斥體 { Application.Run(new Form1()); /s/這句是系統(tǒng)自動(dòng)寫(xiě)的 instance.ReleaseMutex(); } else { MessageBox.Show("已經(jīng)啟動(dòng)了一個(gè)程序,請(qǐng)先退出!","系統(tǒng)提示",MessageBoxButtons.OK,MessageBoxIcon.Error); Application.Exit(); }
用以上代碼實(shí)現(xiàn)了禁止多重啟動(dòng)的功能。
同時(shí)程序關(guān)閉重啟是通過(guò)下面的代碼實(shí)現(xiàn)的:
Process.Start(Process.GetCurrentProcess().ProcessName + ".exe"); Application.Exit();
這時(shí)就出現(xiàn)一個(gè)問(wèn)題,程序自動(dòng)關(guān)閉重啟的時(shí)候就會(huì)提示已經(jīng)啟動(dòng)了一個(gè)程序了。
請(qǐng)問(wèn)應(yīng)該怎么解決?
關(guān)閉之后過(guò)一會(huì)兒再啟動(dòng)是沒(méi)問(wèn)題的。
但是現(xiàn)在自動(dòng)關(guān)閉,自動(dòng)重啟有的時(shí)候能成功,有的時(shí)候就被禁止多重啟動(dòng)的那個(gè)截住了。
那就必須手動(dòng)重新啟動(dòng)了。
比如,點(diǎn)【重新啟動(dòng)】按鈕的時(shí)候執(zhí)行以下代碼:
Process.Start(Process.GetCurrentProcess().ProcessName + ".exe"); Application.Exit();
這時(shí)它是先啟動(dòng)一個(gè)新的Process然后才退出當(dāng)前程序。
這時(shí)就會(huì)在Program.cs里遇到禁止多重啟動(dòng)的那段代碼。就不能自動(dòng)啟動(dòng)了。
解決方案:
解決方法一:
一般程序:
因?yàn)檫M(jìn)程還沒(méi)有中止,還占在內(nèi)存中所以才會(huì)報(bào)錯(cuò).
出現(xiàn)這種原因的情況可能是:使用多線程,其中的線程沒(méi)有執(zhí)行結(jié)束,也沒(méi)有被置為后臺(tái)線程,所以雖然應(yīng)用程序關(guān)閉,但進(jìn)程仍駐留在內(nèi)存中.
可以使用Application.ExitThread();中止進(jìn)程中的所有線程.
也可以在進(jìn)程執(zhí)行中獲得進(jìn)程的ID,然后通過(guò)Process.GetProcessById()獲得這個(gè)進(jìn)程,然后將它Kill掉,再啟動(dòng)新的進(jìn)程.
解決方法二:
要不就在用戶點(diǎn)[重新啟動(dòng)]時(shí),把mutex先釋放掉?可能需要把那個(gè)mutex變量做成一個(gè)global,這樣你在兩個(gè)地方都能訪問(wèn)到。然后在程序退出時(shí)(Application.Run下面那一句),檢查一下如果mutex已經(jīng)被釋放了,就不要再釋放了。
解決方法三:
或者就在點(diǎn)[重新啟動(dòng)]時(shí)再設(shè)另外一個(gè)不同的信號(hào)量,當(dāng)?shù)诙€(gè)程序重入時(shí)如果看到這個(gè)信號(hào)量說(shuō)明是自動(dòng)重啟的情況,就不報(bào)錯(cuò)而直接正常往下走了。這個(gè)信號(hào)量可以在第一個(gè)程序[重新啟動(dòng)]那里執(zhí)行完后再釋放,不過(guò)應(yīng)該也可以在整個(gè)程序退出時(shí)檢查一下如果存在就釋放。
- C#實(shí)現(xiàn)程序開(kāi)機(jī)啟動(dòng)的方法
- C#實(shí)現(xiàn)將應(yīng)用程序設(shè)置為開(kāi)機(jī)啟動(dòng)的方法
- C#實(shí)現(xiàn)開(kāi)機(jī)自動(dòng)啟動(dòng)設(shè)置代碼分享
- C#設(shè)置開(kāi)機(jī)啟動(dòng)項(xiàng)、取消開(kāi)機(jī)啟動(dòng)項(xiàng)
- C#代碼設(shè)置開(kāi)機(jī)啟動(dòng)示例
- c# 開(kāi)機(jī)啟動(dòng)項(xiàng)的小例子
- C#如何防止程序多次運(yùn)行的技巧
- 在Linux上運(yùn)行C#的方法
- C#操作注冊(cè)表的方法詳解
- c#讀寫(xiě)注冊(cè)表示例分享
- C# 注冊(cè)表 操作實(shí)現(xiàn)代碼
- C#操作注冊(cè)表的方法
- C#設(shè)置軟件開(kāi)機(jī)自動(dòng)運(yùn)行的方法(修改注冊(cè)表)
相關(guān)文章
在c#中把字符串轉(zhuǎn)為變量名并獲取變量值的小例子
這篇文章介紹了在c#中把字符串轉(zhuǎn)為變量名并獲取變量值的小例子,有需要的朋友可以參考一下2013-09-09C#設(shè)計(jì)模式之裝飾器模式實(shí)例詳解
本文詳細(xì)講解了C#設(shè)計(jì)模式之裝飾器模式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10C#實(shí)現(xiàn)將HTML網(wǎng)頁(yè)或HTML字符串轉(zhuǎn)換為PDF
將HTML轉(zhuǎn)換為PDF可實(shí)現(xiàn)格式保留、可靠打印、文檔歸檔等多種用途,滿足不同領(lǐng)域和情境下的需求,所以本文就來(lái)介紹一下如何使用C#實(shí)現(xiàn)將HTML網(wǎng)頁(yè)或HTML字符串轉(zhuǎn)換為PDF,有需要的可以參考下2024-01-01C#中Activator.CreateInstance()方法用法分析
這篇文章主要介紹了C#中Activator.CreateInstance()方法用法,實(shí)例分析了C#中Activator.CreateInstance()方法的功能、定義及使用技巧,需要的朋友可以參考下2015-03-03