如何使.NET程序只运行单一实例

原创 2003年09月17日 08:59:00

有时你会想只运行一个程序首次运行时的实例,有些时候则可能只需要运行最新的那个实例。以下是这两种实现这两种方法的例子。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

你如何才能确保只有一个.NET的程序运行在你的机器上呢?多任务操作系统在很多方面都很有用,但是有时你只需要在某一时间内运行一个实例,例如,如果程序需要使用很多的资源或者需要排它地存取某一个资源。在这种情况下,你可能想确认当另一个实例启动时,它会检查是否有另一个实例正在运行。如果是,则将自身关闭。本文中,我会告诉大家如何去实现它,还有在相关的情况下如何只允许最新的程序实例运行。请在以下地址下载程序源码ftp://ftp.wdj.com/pub/webzip/newsletters/20030815dnn.zip


最简单的方法是使用mutex对像。例如,在以下的代码中,Form的构造函数中创建了一个mutex对象,然后 试着去存取它。如果WaitOne()返回true,那么当前线程就已经拥有了mutex,如果返回falsemutex已经被另一个线程所拥有。

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)的实例将会启动。


这种方法只允许第一个进程实例运行。但如果你只想运行最新的那个实例时怎么办呢?就是说如果我启动了一个新的进程实例,而且之前已经有一个实例正在运行中,那么我们需要停止之前的那个线程。例如屏保的显示属性对话框。这个对话框显示一个小的预览窗口,当用用户点击预览按钮时,另一个屏保程序实例(instance)就会启动并全屏显示。当全屏实例停止时(例如你移动了鼠标),另一个屏保实例就会开始在小的预览窗口中开始运行。很明显,当全屏实例开始,这个预览的屏保窗口进程就要结束。

 

一种实现的方法是为每一个实例去存取一个命名的事件核心对象(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, bool initialState, 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, initialState, name);

              return mre;

         }

     }

 

以上的代码中,静态(static)方法CreateNamedEvent()创建了一个ManualResetEvent对象,并释放了当前的(underlyingWin32句柄(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这样做<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />CSDN_Dev_Image_2003-9-16208200.gif,因为大多数窗体(Forms)都有相同的类名,正如我在上一封newsletter是所说的。在下一个newsletter中,我会解释另一种方法去解决这类问题。


 

使Qt程序只运行一个实例

Normal 0 7.8 磅 0 2 false false false Microsof...
  • tingsking18
  • tingsking18
  • 2010年05月20日 08:48
  • 19029

让MFC程序只运行一个实例

以对话框程序Demo为例:1、在CDemoApp类中添加成员变量: HANDLE m_hMutex;2、重载CWinApp::InitInstance 和 CWinApp::ExitInstance...
  • hxmcnu
  • hxmcnu
  • 2014年03月17日 18:31
  • 1290

让MFC程序只运行单个实例 的简单示例

这里只是简单的建立一个MFC 程序来演示 只运行一个实例。 // 在头文件中添加类似如下代码 #define SCANSETTINGS_CLASSNAME _T("ScanSettingsWi...
  • W_SX12553
  • W_SX12553
  • 2014年12月17日 15:08
  • 1956

如何使程序只运行一个实例

       我们在开发程序时,经常需要程序只运行一个实例,以避免不同的进程同时控制同一个硬件,或读写相同的端口,造成系统的不稳定或崩溃。本文给出一种实现的方法。一。实现原理:在指定窗口的属性表中增加...
  • xvdongming
  • xvdongming
  • 2008年07月08日 19:12
  • 458

.NET限制程序一次只能运行一个实例

利用System.Threading命名空间下的Mutex类,可以限制应用程序,让它不能同时运行多个实例。 在WinForm程序中,可以将Mutex类嵌在Main()函数中,代码如下: stati...
  • highplayer
  • highplayer
  • 2011年12月18日 21:57
  • 2046

.Net平台下使应用程序只运行一个实例

摘要:   本文阐述了在基于.NET平台的应用程序开发中如何实现唯一应用程序运行实例,对几种实现方式进行分析测试比较,从而寻找一种合适的处理方式。单击此处才查看本文的示例代码。概述   在开发一些应用...
  • alpsboy
  • alpsboy
  • 2006年09月28日 18:14
  • 2436

程序只启动一个实例的几种方法

    有些时候,我们要求一个程序在系统中只能启动一个实例。比如,Windows自带的播放软件Windows Medea Player在Windows里就只能启动一个实例。原因很简单,如果同时启动几个...
  • starlee
  • starlee
  • 2007年03月20日 09:26
  • 11705

Qt程序只运行一个实例

#include QSharedMemory shared("name");//随便填个名字就行 if (shared.attach()) {         return 0; } shared....
  • caoshangpa
  • caoshangpa
  • 2016年04月01日 15:03
  • 2074

如何让Java程序只运行一个实例

Java没有提供这样的机制。从操作系统的观点来看,一个启动的Java Application仅仅是一 个JVM的运行实例。运行相同Application的两个实例,仅仅是运行两个无关的JVM。 只...
  • yaerfeng
  • yaerfeng
  • 2012年02月16日 15:20
  • 6749

VC++实现程序只运行一个实例 最简单办法

C++如何使应用程序只运行一个实例 最简单的方法:在应用程序类中使用互斥量是应用程序只运行一次(一个实例)的简单的方法。方法是通过VC下的GUIDGEN.EXE程序产生一个全局标志。在VC安装目录中...
  • i_likechard
  • i_likechard
  • 2017年07月11日 09:19
  • 404
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:如何使.NET程序只运行单一实例
举报原因:
原因补充:

(最多只允许输入30个字)