如何使.NET程序只运行单一实例
有时你会想只运行一个程序首次运行时的实例,有些时候则可能只需要运行最新的那个实例。以下是这两种实现这两种方法的例子。
你如何才能确保只有一个.NET的程序运行在你的机器上呢?多任务操作系统在很多方面都很有用,但是有时你只需要在某一时间内运行一个实例,例如,如果程序需要使用很多的资源或者需要排它地存取某一个资源。在这种情况下,你可能想确认当另一个实例启动时,它会检查是否有另一个实例正在运行。如果是,则将自身关闭。本文中,我会告诉大家如何去实现它,还有在相关的情况下如何只允许最新的程序实例运行。请在以下地址下载程序源码ftp://ftp.wdj.com/pub/webzip/newsletters/20030815dnn.zip
using System;
using System.Windows.Forms;
using System.Threading;
class App : Form
{
Mutex mutex;
App()
{
Text = "Single Instance!";
mutex = new Mutex(false,"SINGLE_INSTANCE_MUTEX");
if (!mutex.WaitOne(0,false))
{
mutex.Close();
mutex = null;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
mutex.ReleaseMutex();
base.Dispose(disposing);
}
static void Main()
{
App app = new App();
if (app.mutex != null) Application.Run(app);
else MessageBox.Show("Instance already running");
}
}
在以上代码中,方法Dispose()并不严格需要,这是因为当程序结束时,垃圾回收器将会dispose并且release mutex对象。但是我仍然添加了它,这是因为Form需要一段很长的时间来释放(dispose),并且另一个窗体(Form)的实例将会启动。
一种实现的方法是为每一个实例去存取一个命名的事件核心对象(named event kernel object),如果事件对象没有被触发(nonsignaled),那么此实例就继续运行;如果事件被触发则程序实例会结束。应用程序可以周期性地测试事件去看是否它已经被触发。当一个新的实例启动,它就会设置事件(去关闭其它任何实例)然后重设事件以使它可以继续运行。这种方案除了一个小问题外运行良好:.NET Framework不会允许你命名一个核心事件(kernel event)。以下是一个实现的类
public class NamedEventHelper
{
[DllImport("kernel32")]
static extern uint CreateEvent(
uint sec,bool manualReset,bool initialState,string name);
static IntPtr CreateEvent(bool manualReset,string name)
{
return new IntPtr(CreateEvent(0,manualReset,initialState,name));
}
[DllImport("kernel32")]
static extern bool CloseHandle(IntPtr handle);
public static ManualResetEvent CreateNamedEvent(
bool initialState,string name)
{
ManualResetEvent mre = new ManualResetEvent(false);
CloseHandle(mre.Handle);
mre.Handle = CreateEvent(true,name);
return mre;
}
}
以上的代码中,静态(static)方法CreateNamedEvent()创建了一个ManualResetEvent对象,并释放了当前的(underlying)Win32句柄(handle)。然后再创建一个命名事件(named event)并且使用此新事件的句柄初始化了ManualResetEvent对象。此事件对象就能被用于两个应用程序间的通信。
这种方案的弱点是一个应用程序一定要看它是否已经结束。一种解决方法是运行一个后台线程去管理事件
ManualResetEvent mre;
mre = NamedEventHelper.CreateNamedEvent(false,"LAST_INSTANCE_ONLY");
// Stop the other instances
mre.Set();
// Reset the event so that we can run
mre.Reset();
// Create a monitor thread
Thread t = new Thread(new ThreadStart(Monitor));
// Make sure that this thread cannot keep the app alive
t.IsBackground = true;
t.Start();
//The Monitor() method looks like this:
void Monitor()
{
mre.WaitOne();
Application.Exit();
}
如果程序有一个窗体,那么另一种方法就是告诉其它窗口去关闭这个新的程序实例。如果这是一个Win32应用程序,那么此程序可以简单地通过调用FindWindowsEx(),并传入一个特定的窗口类参数,然后发送WM_CLOSE消息。但是你不能对Windows Form这样做
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |