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

作者:郑佐
时间: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异常。
根据测试结果可见三种实现方式适用范围不同,理想的实现是结合他们的优点进行多点判断。
 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值