作者:郑佐时间: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异常。根据测试结果可见三种实现方式适用范围不同,理想的实现是结合他们的优点进行多点判断。
转载请注明原文地址: https://ibbs.8miu.com/read-25266.html