程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 基於.Net平台應用程序唯一運行實例C#代碼實現

基於.Net平台應用程序唯一運行實例C#代碼實現

編輯:關於C語言
概述
本文是針對《基於.Net平台應用程序唯一運行實例實現》的補充,文章給出功能實現代碼,其中SingleInstance類實現只允許一個實例運行,Program為測試主程序入口。在代碼中標識說明文字。完整代碼下載。
主要代碼
SingleInstance.cs文件,
using System;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Reflection;
using System.Runtime.InteropServices;
/*------------------------------------------------
鄭佐 2006-07-01  http://blog.csdn.Net/zhzuo     
--------------------------------------------------*/
namespace Zhengzuo.CSharpCode
{
    /// <summary>
    /// 只啟動一個應用程序實例控制類
    /// </summary>
    public static class SingleInstance
    {
        private const int WS_SHOWNORMAL = 1;
        [DllImport("User32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
        [DllImport("User32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
        //標志文件名稱
        private static string runFlagFullname = null;
        //聲明同步基元
        private static Mutex mutex = null; 
 
        /// <summary>
        /// static Constructor
        /// </summary>
        static SingleInstance()
        {
        } 
        #region api實現     
        /// <summary>
        /// 獲取應用程序進程實例,如果沒有匹配進程,返回Null
        /// </summary>
        /// <returns>返回當前Process實例</returns>
        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;
        } 
        /// <summary>
        /// 獲取應用程序句柄,設置應用程序前台運行,並返回bool值
        /// </summary>
        public static bool HandleRunningInstance(Process instance)
        {
            //確保窗口沒有被最小化或最大化
            ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);
            //設置真實例程為foreground window
            return SetForegroundWindow(instance.MainWindowHandle);
        } 
        /// <summary>
        /// 獲取窗口句柄,設置應用程序前台運行,並返回bool值,重載方法
        /// </summary>
        /// <returns></returns>
        public static bool HandleRunningInstance()
        {
            Process p = GetRunningInstance();
            if (p != null)
            {
                HandleRunningInstance(p);
                return true;
            }
            return false;
        } 
        #endregion
        #region Mutex實現
        /// <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();
            }
        } 
        #endregion
        #region 設置標志實現
        /// <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;
                    //CommonApplicationData://"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;
            }
        }
        #endregion
    }
}
Program.cs文件,
using System;
using System.Windows.Forms;
using System.Diagnostics;
using Zhengzuo.CSharpCode;
/*------------------------------------------------
  鄭佐 2006-07-01  http://blog.csdn.Net/zhzuo
--------------------------------------------------*/
namespace Zhengzuo.Test.WinGui
{
    static class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            if (args.Length == 0) //沒有傳送參數
            {
                Process p = SingleInstance.GetRunningInstance();
                if (p != null) //已經有應用程序副本執行
                {
                    SingleInstance.HandleRunningInstance(p);
                }
                else //啟動第一個應用程序
                {
                    RunApplication();
                }
            }
            else //有多個參數
            {
                switch (args[0].ToLower())
                {
                    case "-api":
                        if (SingleInstance.HandleRunningInstance() == false)
                        {
                            RunApplication();
                        }
                        break;
                    case "-mutex":
                        if (args.Length >= 2) //參數中傳入互斥體名稱
                        {
                            if ( SingleInstance.CreateMutex(args[1]) )
                            {
                                RunApplication();
                                SingleInstance.ReleaseMutex();
                            }
                            else
                            {
                                //調用SingleInstance.HandleRunningInstance()方法顯示到前台。
                                MessageBox.Show("程序已經運行!");
                            }
                        }
                        else
                        {
                            if (SingleInstance.CreateMutex())
                            {
                                RunApplication();
                                SingleInstance.ReleaseMutex();
                            }
                            else
                            {
                                //調用SingleInstance.HandleRunningInstance()方法顯示到前台。
                                MessageBox.Show("程序已經運行!");
                            }
                        }
                        break;
                    case "-flag"://使用該方式需要在程序退出時調用
                        if (args.Length >= 2) //參數中傳入運行標志文件名稱
                        {
                            SingleInstance.RunFlag = args[1];                         
                        }
                        try
                        {
                            if (SingleInstance.InitRunFlag())
                            {
                                RunApplication();
                                SingleInstance.DisposeRunFlag();
                            }
                            else
                            {
                                //調用SingleInstance.HandleRunningInstance()方法顯示到前台。
                                MessageBox.Show("程序已經運行!");
                            }
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.ToString());
                        }
                        break;
                    default:
                        MessageBox.Show("應用程序參數設置失敗。");
                        break;
                }
            }
        } 
        //啟動應用程序
        static void RunApplication()
        {
            Application.EnableVisualStyles();
            Application.Run(new MainForm());
        }
    }
}
功能測試
功能測試類別包括下面五類,
1.本地系統同一應用程序目錄;
2.本地系統同一應用程序修改運行文件名稱使兩次運行名稱不同;
3.本地系統兩次運行程序目錄不同,不修改文件名稱;
4.本地系統不同會話用戶登錄啟動應用程序;
5.遠程計算機程序訪問啟動應用程序(一個程序在遠程另一個在本地)。
運行CMD命令行,
第一種調用方式:
WindowsApplication1.exe
或 WindowsApplication1.exe –api
第二種調用方式:
WindowsApplication1.exe –mutex
或WindowsApplication1.exe –mutex {F140AE26-626C-42f8-BD49-45025742205E}
第三種調用方式:
WindowsApplication1.exe –flag
或WindowsApplication1.exe –flag c:\blog.csdn.Net.zhzuo
測試結果,
匹配/互斥/標志 1同一目錄 2修改名稱 3不同目錄 4不同用戶 5遠程訪問 1同一目錄 O/O/O         2修改名稱   X/O/O       3不同目錄     X/O/O     4不同用戶       #/X/O   5遠程訪問         X/O/O備注:O - 表示成功,X – 表示失敗,# - 程序第二個運行沒有反應 針對遠程訪問的測試,需要在系統管理工具的.Net Framework 2.0 Configuration中進行設置授權該局域網路徑允許訪問,否則會拋出System.Security.SecurityException異常。
根據測試結果可見三種實現方式適用范圍不同,理想的實現是結合他們的優點進行多點判斷。
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved