SingleInstance.cs文件
Program.cs文件
功能测试
功能测试类别包括下面五类,
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
测试结果
备注:O - 表示成功,X – 表示失败,# - 程序第二个运行没有反应
针对远程访问的测试,需要在系统管理工具的.NET Framework 2.0 Configuration中进行设置授权该局域网路径允许访问,否则会抛出System.Security.SecurityException异常。
根据测试结果可见三种实现方式适用范围不同,理想的实现是结合他们的优点进行多点判断。
using
System;
using System.Windows.Forms;
using System.Diagnostics;
using Zhengzuo.CSharpCode;
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());
}
}
}
using System.Windows.Forms;
using System.Diagnostics;
using Zhengzuo.CSharpCode;
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());
}
}
}
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
}
}
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
}
}
功能测试
功能测试类别包括下面五类,
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 |
针对远程访问的测试,需要在系统管理工具的.NET Framework 2.0 Configuration中进行设置授权该局域网路径允许访问,否则会抛出System.Security.SecurityException异常。
根据测试结果可见三种实现方式适用范围不同,理想的实现是结合他们的优点进行多点判断。