C#編程中設(shè)置程序只可被運行一次的方法
防止程序運行多個實例的方法有多種,如:通過使用互斥量和進程名等.而我想要實現(xiàn)的是:在程序運行多個實例時激活的是第一個實例,使其獲得焦點,并在前端顯示.
主要用到兩個API 函數(shù):
ShowWindowAsync 該函數(shù)設(shè)置由不同線程產(chǎn)生的窗口的顯示狀態(tài)。
SetForegroundWindow 該函數(shù)將創(chuàng)建指定窗口的線程設(shè)置到前臺,并且激活該窗口。鍵盤輸入轉(zhuǎn)向該窗口,并為用戶改各種可視的記號。系統(tǒng)給創(chuàng)建前臺窗口的線程分配的權(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">指定窗口如何顯示。查看允許值列表,請查閱ShowWlndow函數(shù)的說明部分。</param>
/// <returns>如果函數(shù)原來可見,返回值為非零;如果函數(shù)原來被隱藏,返回值為零。</returns>
[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
/// <summary>
/// 該函數(shù)將創(chuàng)建指定窗口的線程設(shè)置到前臺,并且激活該窗口。鍵盤輸入轉(zhuǎn)向該窗口,并為用戶改各種可視的記號。系統(tǒng)給創(chuàng)建前臺窗口的線程分配的權(quán)限稍高于其他線程。
/// </summary>
/// <param name="hWnd">將被激活并被調(diào)入前臺的窗口句柄。</param>
/// <returns>如果窗口設(shè)入了前臺,返回值為非零;如果窗口未被設(shè)入前臺,返回值為零。</returns>
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
private const int WS_SHOWNORMAL = 1;
/// <summary>
/// 應用程序的主入口點。
/// </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>
/// 獲取正在運行的實例,沒有運行的實例返回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>
/// 顯示已運行的程序。
/// </summary>
public static void HandleRunningInstance(Process instance)
{
ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL); //顯示,可以注釋掉
SetForegroundWindow(instance.MainWindowHandle); //放到前端
}
}
實現(xiàn)讓程序只能打開一個實例(其他方法)
//=====創(chuàng)建互斥體法:=====
bool blnIsRunning;
Mutex mutexApp = new Mutex(false, Assembly.GetExecutingAssembly().FullName, out blnIsRunning);
if (!blnIsRunning)
{
MessageBox.Show("程序已經(jīng)運行!", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}
//保證同時只有一個客戶端在運行
System.Threading.Mutex mutexMyapplication = new System.Threading.Mutex(false, "OnePorcess.exe");
if (!mutexMyapplication.WaitOne(100, false))
{
MessageBox.Show("程序" + Application.ProductName + "已經(jīng)運行!", Application.ProductName,
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
//=====判斷進程法:(修改程序名字后依然能執(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)運行!", Application.ProductName,
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}
}
}
實現(xià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)自動寫的
instance.ReleaseMutex();
}
else
{
MessageBox.Show("已經(jīng)啟動了一個程序,請先退出!","系統(tǒng)提示",MessageBoxButtons.OK,MessageBoxIcon.Error);
Application.Exit();
}
用以上代碼實現(xiàn)了禁止多重啟動的功能。
同時程序關(guān)閉重啟是通過下面的代碼實現(xiàn)的:
Process.Start(Process.GetCurrentProcess().ProcessName + ".exe"); Application.Exit();
這時就出現(xiàn)一個問題,程序自動關(guān)閉重啟的時候就會提示已經(jīng)啟動了一個程序了。
請問應該怎么解決?
關(guān)閉之后過一會兒再啟動是沒問題的。
但是現(xiàn)在自動關(guān)閉,自動重啟有的時候能成功,有的時候就被禁止多重啟動的那個截住了。
那就必須手動重新啟動了。
比如,點【重新啟動】按鈕的時候執(zhí)行以下代碼:
Process.Start(Process.GetCurrentProcess().ProcessName + ".exe"); Application.Exit();
這時它是先啟動一個新的Process然后才退出當前程序。
這時就會在Program.cs里遇到禁止多重啟動的那段代碼。就不能自動啟動了。
解決方案:
解決方法一:
一般程序:
因為進程還沒有中止,還占在內(nèi)存中所以才會報錯.
出現(xiàn)這種原因的情況可能是:使用多線程,其中的線程沒有執(zhí)行結(jié)束,也沒有被置為后臺線程,所以雖然應用程序關(guān)閉,但進程仍駐留在內(nèi)存中.
可以使用Application.ExitThread();中止進程中的所有線程.
也可以在進程執(zhí)行中獲得進程的ID,然后通過Process.GetProcessById()獲得這個進程,然后將它Kill掉,再啟動新的進程.
解決方法二:
要不就在用戶點[重新啟動]時,把mutex先釋放掉?可能需要把那個mutex變量做成一個global,這樣你在兩個地方都能訪問到。然后在程序退出時(Application.Run下面那一句),檢查一下如果mutex已經(jīng)被釋放了,就不要再釋放了。
解決方法三:
或者就在點[重新啟動]時再設(shè)另外一個不同的信號量,當?shù)诙€程序重入時如果看到這個信號量說明是自動重啟的情況,就不報錯而直接正常往下走了。這個信號量可以在第一個程序[重新啟動]那里執(zhí)行完后再釋放,不過應該也可以在整個程序退出時檢查一下如果存在就釋放。
相關(guān)文章
在c#中把字符串轉(zhuǎn)為變量名并獲取變量值的小例子
這篇文章介紹了在c#中把字符串轉(zhuǎn)為變量名并獲取變量值的小例子,有需要的朋友可以參考一下2013-09-09
C#實現(xiàn)將HTML網(wǎng)頁或HTML字符串轉(zhuǎn)換為PDF
將HTML轉(zhuǎn)換為PDF可實現(xiàn)格式保留、可靠打印、文檔歸檔等多種用途,滿足不同領(lǐng)域和情境下的需求,所以本文就來介紹一下如何使用C#實現(xiàn)將HTML網(wǎng)頁或HTML字符串轉(zhuǎn)換為PDF,有需要的可以參考下2024-01-01
C#中Activator.CreateInstance()方法用法分析
這篇文章主要介紹了C#中Activator.CreateInstance()方法用法,實例分析了C#中Activator.CreateInstance()方法的功能、定義及使用技巧,需要的朋友可以參考下2015-03-03

