二、C#只允许启动一个WinFrom进程

SingleInstance.cs文件
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());
        }
    }
}
Program.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
    }

}

  功能测试

功能测试类别包括下面五类,
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异常。
根据测试结果可见三种实现方式适用范围不同,理想的实现是结合他们的优点进行多点判断


你可能感兴趣的:(二、C#只允许启动一个WinFrom进程)