基于.Net平台应用程序唯一运行实例C#代码实现

    技术2022-05-11  51

    作者:郑佐时间:2006-7-2 概述 本文是针对《基于.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异常。根据测试结果可见三种实现方式适用范围不同,理想的实现是结合他们的优点进行多点判断。  

    最新回复(0)