您的位置:首页 > 编程语言

.Net平台应用程序单一运行实例代码实现

2008-09-26 09:17 901 查看
作者:郑佐
日期:2006-7-2

概述
本文是针对《基于.Net平台应用程序唯一运行实例实现》的补充,文章给出功能实现代码,其中SingleInstance类实现只允许一个实例运行,Program为测试主程序入口。在代码中标识说明文字。完整代码下载。

主要代码
SingleInstance.cs文件。

[align=left]using System;[/align]
[align=left]using System.IO;[/align]
[align=left]using System.Diagnostics;[/align]
[align=left]using System.Threading;[/align]
[align=left]using System.Reflection;[/align]
[align=left]using System.Runtime.InteropServices;[/align]
[align=left]/*------------------------------------------------[/align]
[align=left] Zhengzuo 2006-07-01 http://blog.csdn.net/zhzuo [/align]
[align=left]--------------------------------------------------*/[/align]
[align=left]namespace Zhengzuo.CSharpCode[/align]
[align=left]{[/align]
[align=left] ///<summary>[/align]
[align=left] ///只启动一个应用程序实例控制类[/align]
[align=left] ///</summary>[/align]
[align=left] public static class SingleInstance[/align]
[align=left] {[/align]
[align=left] private const int WS_SHOWNORMAL = 1;[/align]
[align=left] [DllImport("User32.dll")][/align]
[align=left] private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);[/align]
[align=left] [DllImport("User32.dll")][/align]
[align=left] private static extern bool SetForegroundWindow(IntPtr hWnd);[/align]
[align=left] //标志文件名称[/align]
[align=left] private static string runFlagFullname = null;[/align]
[align=left] //声明同步基元[/align]
[align=left] private static Mutex mutex = null;[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] /// static Constructor[/align]
[align=left] ///</summary>[/align]
[align=left] static SingleInstance() [/align]
[align=left] {[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] #region api实现[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] ///获取应用程序进程实例,如果没有匹配进程,返回Null[/align]
[align=left] ///</summary>[/align]
[align=left] ///<returns>返回当前Process实例</returns>[/align]
[align=left] public static Process GetRunningInstance()[/align]
[align=left] { [/align]
[align=left] Process currentProcess = Process.GetCurrentProcess();//获取当前进程[/align]
[align=left] //获取当前运行程序完全限定名[/align]
[align=left] string currentFileName = currentProcess.MainModule.FileName;[/align]
[align=left] //获取进程名为ProcessName的Process数组。[/align]
[align=left] Process[] processes = Process.GetProcessesByName(currentProcess.ProcessName);[/align]
[align=left] //遍历有相同进程名称正在运行的进程[/align]
[align=left] foreach (Process process in processes)[/align]
[align=left] {[/align]
[align=left] if (process.MainModule.FileName == currentFileName)[/align]
[align=left] {[/align]
[align=left] if (process.Id != currentProcess.Id)//根据进程ID排除当前进程[/align]
[align=left] return process;//返回已运行的进程实例[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] return null;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] ///获取应用程序句柄,设置应用程序前台运行,并返回bool值[/align]
[align=left] ///</summary>[/align]
[align=left] public static bool HandleRunningInstance(Process instance)[/align]
[align=left] {[/align]
[align=left] //确保窗口没有被最小化或最大化[/align]
[align=left] ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);[/align]
[align=left] //设置真实例程为foreground window[/align]
[align=left] return SetForegroundWindow(instance.MainWindowHandle);[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] ///获取窗口句柄,设置应用程序前台运行,并返回bool值,重载方法[/align]
[align=left] ///</summary>[/align]
[align=left] ///<returns></returns>[/align]
[align=left] public static bool HandleRunningInstance()[/align]
[align=left] {[/align]
[align=left] Process p = GetRunningInstance();[/align]
[align=left] if (p != null)[/align]
[align=left] {[/align]
[align=left] HandleRunningInstance(p);[/align]
[align=left] return true;[/align]
[align=left] }[/align]
[align=left] return false;[/align]
[align=left] }[/align]
[align=left] #endregion[/align]
[align=left] [/align]
[align=left] #region Mutex实现[/align]
[align=left] ///<summary>[/align]
[align=left] ///创建应用程序进程Mutex[/align]
[align=left] ///</summary>[/align]
[align=left] ///<returns>返回创建结果,true表示创建成功,false创建失败。</returns>[/align]
[align=left] public static bool CreateMutex() [/align]
[align=left] {[/align]
[align=left] return CreateMutex(Assembly.GetEntryAssembly().FullName);[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] ///创建应用程序进程Mutex[/align]
[align=left] ///</summary>[/align]
[align=left] ///<param name="name">Mutex名称</param>[/align]
[align=left] ///<returns>返回创建结果,true表示创建成功,false创建失败。</returns>[/align]
[align=left] public static bool CreateMutex(string name)[/align]
[align=left] { [/align]
[align=left] bool result = false;[/align]
[align=left] mutex = new Mutex(true, name, out result);[/align]
[align=left] return result;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] ///释放Mutex[/align]
[align=left] ///</summary>[/align]
[align=left] public static void ReleaseMutex() [/align]
[align=left] {[/align]
[align=left] if (mutex != null) [/align]
[align=left] {[/align]
[align=left] mutex.Close();[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] #endregion[/align]
[align=left] [/align]
[align=left] #region设置标志实现[/align]
[align=left] ///<summary>[/align]
[align=left] ///初始化程序运行标志,设置成功,返回true,已经设置返回false,设置失败将抛出异常[/align]
[align=left] ///</summary>[/align]
[align=left] ///<returns>返回设置结果</returns>[/align]
[align=left] public static bool InitRunFlag() [/align]
[align=left] {[/align]
[align=left] if (File.Exists(RunFlag)) [/align]
[align=left] {[/align]
[align=left] return false;[/align]
[align=left] }[/align]
[align=left] using (FileStream fs = new FileStream(RunFlag, FileMode.Create)) [/align]
[align=left] {[/align]
[align=left] }[/align]
[align=left] return true;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] ///释放初始化程序运行标志,如果释放失败将抛出异常[/align]
[align=left] ///</summary>[/align]
[align=left] public static void DisposeRunFlag()[/align]
[align=left] {[/align]
[align=left] if (File.Exists(RunFlag)) [/align]
[align=left] {[/align]
[align=left] File.Delete(RunFlag);[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] ///获取或设置程序运行标志,必须符合Windows文件命名规范[/align]
[align=left] ///实现生成临时文件为依据,如果修改成设置注册表,那就不需要符合文件命名规范。[/align]
[align=left] ///</summary>[/align]
[align=left] public static string RunFlag[/align]
[align=left] {[/align]
[align=left] get [/align]
[align=left] {[/align]
[align=left] if(runFlagFullname == null)[/align]
[align=left] {[/align]
[align=left] string assemblyFullName = Assembly.GetEntryAssembly().FullName;[/align]
[align=left] //CommonApplicationData:"C://Documents and Settings//All Users//Application Data"[/align]
[align=left] string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);[/align]
[align=left] //"C://Program Files//Common Files"[/align]
[align=left] //string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles);[/align]
[align=left] runFlagFullname = Path.Combine(path, assemblyFullName);[/align]
[align=left] } [/align]
[align=left] return runFlagFullname;[/align]
[align=left] }[/align]
[align=left] set [/align]
[align=left] {[/align]
[align=left] runFlagFullname = value;[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] #endregion[/align]
[align=left] [/align]
[align=left] }[/align]
[align=left]}[/align]

Program.cs文件。

[align=left]using System;[/align]
[align=left]using System.Windows.Forms;[/align]
[align=left]using System.Diagnostics;[/align]
[align=left]using Zhengzuo.CSharpCode;[/align]
[align=left] [/align]
[align=left]namespace Zhengzuo.Test.WinGui[/align]
[align=left]{[/align]
[align=left] static class Program[/align]
[align=left] {[/align]
[align=left] [STAThread][/align]
[align=left] static void Main(string[] args)[/align]
[align=left] {[/align]
[align=left] if (args.Length == 0) //没有传送参数[/align]
[align=left] {[/align]
[align=left] Process p = SingleInstance.GetRunningInstance();[/align]
[align=left] if (p != null) //已经有应用程序副本执行[/align]
[align=left] {[/align]
[align=left] SingleInstance.HandleRunningInstance(p);[/align]
[align=left] }[/align]
[align=left] else //启动第一个应用程序[/align]
[align=left] {[/align]
[align=left] RunApplication();[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] else //有多个参数[/align]
[align=left] {[/align]
[align=left] switch (args[0].ToLower()) [/align]
[align=left] {[/align]
[align=left] case "-api":[/align]
[align=left] if (SingleInstance.HandleRunningInstance() == false) [/align]
[align=left] {[/align]
[align=left] RunApplication();[/align]
[align=left] } [/align]
[align=left] break;[/align]
[align=left] case "-mutex":[/align]
[align=left] if (args.Length >= 2) //参数中传入互斥体名称[/align]
[align=left] {[/align]
[align=left] if ( SingleInstance.CreateMutex(args[1]) )[/align]
[align=left] {[/align]
[align=left] RunApplication();[/align]
[align=left] SingleInstance.ReleaseMutex();[/align]
[align=left] }[/align]
[align=left] else[/align]
[align=left] {[/align]
[align=left] //调用HandleRunningInstance()方法显示到前台。[/align]
[align=left] MessageBox.Show("程序已经运行!");[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] else [/align]
[align=left] {[/align]
[align=left] if (SingleInstance.CreateMutex())[/align]
[align=left] {[/align]
[align=left] RunApplication();[/align]
[align=left] SingleInstance.ReleaseMutex();[/align]
[align=left] }[/align]
[align=left] else[/align]
[align=left] {[/align]
[align=left] //调用HandleRunningInstance()方法显示到前台。[/align]
[align=left] MessageBox.Show("程序已经运行!");[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] break;[/align]
[align=left] case "-flag"://使用该方式需要在程序退出时调用[/align]
[align=left] if (args.Length >= 2) //参数中传入运行标志文件名称[/align]
[align=left] {[/align]
[align=left] SingleInstance.RunFlag = args[1]; [/align]
[align=left] }[/align]
[align=left] try[/align]
[align=left] {[/align]
[align=left] if (SingleInstance.InitRunFlag())[/align]
[align=left] {[/align]
[align=left] RunApplication();[/align]
[align=left] SingleInstance.DisposeRunFlag();[/align]
[align=left] }[/align]
[align=left] else[/align]
[align=left] {[/align]
[align=left] //调用HandleRunningInstance()方法显示到前台。[/align]
[align=left] MessageBox.Show("程序已经运行!");[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] catch (Exception ex)[/align]
[align=left] {[/align]
[align=left] MessageBox.Show(ex.ToString());[/align]
[align=left] }[/align]
[align=left] break;[/align]
[align=left] default:[/align]
[align=left] MessageBox.Show("应用程序参数设置失败。");[/align]
[align=left] break;[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] //启动应用程序[/align]
[align=left] static void RunApplication() [/align]
[align=left] {[/align]
[align=left] Application.EnableVisualStyles();[/align]
[align=left] Application.Run(new MainForm());[/align]
[align=left] }[/align]
[align=left] }[/align]
}

功能测试
功能测试类别包括下面五类,
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同一目录[align=center]O/O/O[/align][align=center] [/align][align=center] [/align][align=center] [/align][align=center] [/align]
2修改名称[align=center] [/align][align=center]X/O/O[/align][align=center] [/align][align=center] [/align][align=center] [/align]
3不同目录[align=center] [/align][align=center] [/align][align=center]X/O/O[/align][align=center] [/align][align=center] [/align]
4不同用户[align=center] [/align][align=center] [/align][align=center] [/align][align=center]#/X/O[/align][align=center] [/align]
5远程访问[align=center] [/align][align=center] [/align][align=center] [/align][align=center] [/align][align=center]X/O/O[/align]
备注:O - 表示成功,X – 表示失败,# - 程序第二个运行没有反应

针对远程访问的测试,需要在系统管理工具的.NET Framework 2.0 Configuration中进行设置授权该局域网路径允许访问,否则会抛出System.Security.SecurityException异常。
根据测试结果可见三种实现方式适用范围不同,理想的实现是结合他们的优点进行多点判断。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: