C#限制程序運行只有一個實例

来源:互联网 发布:2016伤感歌曲大全网络 编辑:程序博客网 时间:2024/06/07 05:43

C#限制程序運行只有一個實例

1.進程匹配
--示例1
  static void Main()
  { 

   Process  mobj_pro =Process.GetCurrentProcess();
   Process[]  mobj_proList=Process.GetProcessesByName(mobj_pro.ProcessName);
   if(mobj_proList.Length>1)
   {
    MessageBox.Show("當前的應用程序已被打開!", "系統提示", MessageBoxButtons.OK);
    return;
   }
   Application.Run(new fcmain());
  }
--示例2
public static Process GetRunningInstance()
{
        Process currentProcess = Process.GetCurrentProcess(); //获取当前进程
        //获取当前运行程序完全限定名
        string currentFileName = currentProcess.MainModule.FileName;
        //获取进程名为ProcessName的Process数组。
        Process[] processes = Process.GetProcessesByName(currentProcess.ProcessName);
        //遍历有相同进程名称正在运行的进程
        foreach (Process process in processes)
        {
                if (process.MainModule.FileName == currentFileName)
                {
                        if (process.Id != currentProcess.Id) //根据进程ID排除当前进程
                                return process;//返回已运行的进程实例
                }
        }
        return null;
}
 [STAThread]
        static void Main(string[] args)
        {
            if (args.Length == 0) //没有传送参数
            {
                Process p = GetRunningInstance();
                if (p != null) //已经有应用程序副本执行
                {
                    MessageBox.Show("當前應用程序已經運行");
                }
                else //启动第一个应用程序
                {
                    Application.EnableVisualStyles();
                 Application.Run(new MainForm());
                }
            }
 }


2.進程互斥

--1.調用API實現
  public abstract class SingleInstance
  {

   [DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
   private static extern IntPtr OpenMutex(
    uint dwDesiredAccess,  // access
    int bInheritHandle,    // inheritance option
    string lpName          // object name
    );

   [DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
   private static extern IntPtr CreateMutex(
    IntPtr lpMutexAttributes,  // SD
    int bInitialOwner,                       // initial owner
    string lpName                            // object name
    );
   /// <summary>
   /// 用來判斷一個指定的程序是否正在運行
   /// </summary>
   /// <param name="appId">程序名稱,長一點比較好,防止有重復</param>
   /// <returns>如果程序是第一次運行返回True,否則返回False</returns>
   public static bool IsFirst(string appId)
   {
    bool ret=false;
    if(OpenMutex(0x1F0001,0,appId)==IntPtr.Zero)
    {
     CreateMutex(IntPtr.Zero,0,appId);
     ret=true;
    }
    return ret;
   }
  }

  [STAThread]
  static void Main()
  {
   if(!SingleInstance.IsFirst("MyClock"))//"MyClock"為主方案名
   {
    MessageBox.Show ("MyClock已經在運行中!!");
    return;
   }

   Application.Run(new MainForm());
  }
--2.利用.net框架中的類實現

public static class SingleInstance
{
  //声明同步基元
        private static Mutex mutex = null;

 ///<summary>
        ///创建应用程序进程Mutex
        ///</summary>
        ///<returns>返回创建结果,true表示创建成功,false创建失败。</returns>
        public static bool CreateMutex()
        {
            return CreateMutex(Assembly.GetEntryAssembly().FullName);
        }
        ///<summary>
        ///创建应用程序进程Mutex
        ///</summary>
        ///<param name="name">Mutex名称</param>
        ///<returns>返回创建结果,true表示创建成功,false创建失败。</returns>
        public static bool CreateMutex(string name)
        {
            bool result = false;
            mutex = new Mutex(true, name, out result);
            return result; 
        }
        ///<summary>
        ///释放Mutex
        ///</summary>
        public static void ReleaseMutex()
        {
            if (mutex != null)
            {
                mutex.Close();
            }
        }
}

  [STAThread]
  static void Main(string[] args)
  {
   if (args.Length >= 2) //参数中传入互斥体名称
                        {
                            if ( SingleInstance.CreateMutex(args[1]) )
                            {
    Application.EnableVisualStyles();
           Application.Run(new MainForm());
                                SingleInstance.ReleaseMutex();
                            }
                            else
                            {
                                //调用SingleInstance.HandleRunningInstance()方法显示到前台。
                                MessageBox.Show("程序已经运行!");
                            }
                        }
                        else
                        {
                            if (SingleInstance.CreateMutex())
                            {
    Application.EnableVisualStyles();
           Application.Run(new MainForm());
                                SingleInstance.ReleaseMutex();
                            }
                            else
                            {
                                //调用SingleInstance.HandleRunningInstance()方法显示到前台。
                                MessageBox.Show("程序已经运行!");
                            }
                        }
  }

3.運行標志
可以用臨時文件名或注冊表來做標識.這里使用文件名示例
public static class SingleInstance
{
  //标志文件名称
        private static string runFlagFullname = null;
 ///<summary>
        ///初始化程序运行标志,如果设置成功,返回true,已经设置返回false,设置失败将抛出异常
        ///</summary>
        ///<returns>返回设置结果</returns>
        public static bool InitRunFlag()
        {
            if (File.Exists(RunFlag))
            {
                return false;
            }
            using (FileStream fs = new FileStream(RunFlag, FileMode.Create))
            {
            }
            return true;
        }
        ///<summary>
        ///释放初始化程序运行标志,如果释放失败将抛出异常
        ///</summary>
        public static void DisposeRunFlag()
        {
            if (File.Exists(RunFlag))
            {
                File.Delete(RunFlag);
            }
        } 

        ///<summary>
        ///获取或设置程序运行标志,必须符合Windows文件命名规范
        ///这里实现生成临时文件为依据,如果修改成设置注册表,那就不需要符合文件命名规范。
        ///</summary>
        public static string RunFlag
        {
            get
            {
                if(runFlagFullname == null)
                {
                    string assemblyFullName = Assembly.GetEntryAssembly().FullName;
                    //"C://Documents and Settings//All Users//Application Data"
                    string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
                    //"C://Program Files//Common Files"
                    //string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles);
                    runFlagFullname = Path.Combine(path, assemblyFullName);
                }
                return runFlagFullname;
            }
            set
            {
                runFlagFullname = value;
            }
        }
}
  [STAThread]
  static void Main(string[] args)
  {
   if (args.Length >= 2) //参数中传入运行标志文件名称
                        {
                            SingleInstance.RunFlag = args[1];                         
                        }
                        try
                        {
                            if (SingleInstance.InitRunFlag())
                            {
                                Application.EnableVisualStyles();
           Application.Run(new MainForm());
                                SingleInstance.DisposeRunFlag();//释放程序运行标志
                            }
                            else
                            {
                                //调用SingleInstance.HandleRunningInstance()方法显示到前台。
                                MessageBox.Show("程序已经运行!");
                            }
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.ToString());
                        }
  }

4.綜合分析
第一种方法只能防止同一可執行文件執行多次.但如果用戶將文件改名或复制一個到別的地方,則此方法失效.
第二种方法效果較好,但對于多用戶操作,則無效.
第三种方法只考慮到了正常情況,但如果程式非正常退出沒有清除標識,則下次程式將可能無法啟動
所以,我認為如果只限制只運行一個實例,則將第二种方法与第三种方法結合來做比較好,而第一种方法沒什么用,如果限制程式最多只運行n個實例,則第二种方法不适用,具体方法我還沒想到.
以下是限制只能有一個實例的偽代法:
if(初始化標識成功)
{
 創建互斥進程;//這一步肯定會成功的,如果不成功則屬于异常
 運行程序;
 程序退出時释放程序运行标志
}
else//程序已運行或程序先前非法退出
{
 if(創建互斥進程成功)//先前程序非法退出
 {
 運行程序
 程序退出時释放程序运行标志
 }
 else//程序已運行
 {
 提示程序已運行或直接返回先前的進程
 }
}
對于有窗体的程式,我們可能還要顯示窗体.

 [DllImport("User32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
        [DllImport("User32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

     private const int WS_SHOWNORMAL = 1;
 ///<summary>
        ///获取应用程序句柄,设置应用程序前台运行,并返回bool值
        ///</summary>
        public static bool HandleRunningInstance(Process instance)
        {
            //确保窗口没有被最小化或最大化
            ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);
            //设置真实例程为foreground window
            return SetForegroundWindow(instance.MainWindowHandle);
        }

注:以上代碼在vs2003/vs2005中都應該可以使用,但我都沒有經過測試,現在沒時間,下次用到時再做測試并完善.

參考文獻:1. http://blog.csdn.net/zhzuo/archive/2006/06/30/857405.aspx
2. http://blog.csdn.net/vfp_system/archive/2007/02/14/1510107.aspx

 


原创粉丝点击