首页 > 编程 > .NET > 正文

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

2024-07-10 13:07:20
字体:
来源:转载
供稿:网友
国内最大的酷站演示中心!
概述
本文是针对《基于.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异常。
根据测试结果可见三种实现方式适用范围不同,理想的实现是结合他们的优点进行多点判断。
 
更多资源
关于.net平台应用的开发,更多的技术文章可以访问http://blog.csdn.net/zhzuo,对于本文的建议或意见可在网站上留言。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表