C#创建单实例应用程序

先看原文,后面简单翻译一下:Creating a Single Instance Application in C#

Sometimes, it's desirable to ensure that there is only ever one instance of your application running at any given time. Take Windows Live Messenger for instance - if you try to launch it whilst it is already running, it will just bring itself to the foreground instead.

Unfortunately, a lot of people try to recreate this behavior by simply checking if a process with the same name is currently running. As K. Scott Allen explains, this is not a good idea. The correct way to implement a single instance application, is to use a named mutex.

The word mutex is short for mutual exclusion, and is a synchronisation object that can only be owned by a single thread at any given time. Specifying a name for the mutex is optional - an unnamed mutex is scoped to the current process, while a named one is associated with an operating system object and can thus be used for interprocess synchronisation. Quite simply then, we can launch our application like this: 

[STAThread]
static   void  Main()
{
    
bool  createdNew  =   true ;
    
using  (Mutex mutex  =   new  Mutex( true " MyApplicationName " out  createdNew))
    {
        
if  (createdNew)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(
false );
            Application.Run(
new  FrmMain());
        }
    }
}

That ensures that there's only a single instance of our application running. Now, the above code just 'does nothing' if the application is already running - it would be nice if it instead tried to give the main window focus. To do this, we need to find the process instance, and then pinvoke the SetForeGroundWindow method of the Win32 API. Our final Main method then looks like this:

[DllImport( " user32.dll " )]
[
return : MarshalAs(UnmanagedType.Bool)]
private   static   extern   bool  SetForegroundWindow(IntPtr hWnd);

///   <summary>
///  The main entry point for the application.
///   </summary>
[STAThread]
static   void  Main()
{
    
bool  createdNew  =   true ;
    
using  (Mutex mutex  =   new  Mutex( true " MyApplicationName " out  createdNew))
    {
        
if  (createdNew)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(
false );
            Application.Run(
new  FrmMain());
        }
        
else
        {
            Process current 
=  Process.GetCurrentProcess();
            
foreach  (Process process  in  Process.GetProcessesByName(current.ProcessName))
            {
                
if  (process.Id  !=  current.Id)
                {
                    SetForegroundWindow(process.MainWindowHandle);
                    
break ;
                }
            }
        }
    }
}

这篇文章说,很多人通过简单地检查正在运行的进程名(通过for循环,请自行搜索其他文章,已有很多例子)来判断自己的程序是否在运行,这不是一个好办法。正确的做法是使用Mutex类,Mutex就是互斥的意思。

作者首先给出了互斥的代码(没有必要使用Mutex.WaitOne()方法) ,作者使用了using来释放资源。最后作者引入了Win32 API来让窗体重新获得焦点。

这个例子没有完全达到我们所预期的功能,当运行一个实例并最小化,再次运行这个实例时,窗口仅获得焦点,并不会恢复,在SetForegroundWindow(process.MainWindowHandle);后加入一行代码就可以搞定了,需要使用Win32 API,最终代码如下:

using  System;
using  System.Runtime.InteropServices;
using  System.Threading;
using  System.Windows.Forms;
using  System.Diagnostics;

namespace WinApp
{
    
static   class  Program
    {
        [DllImport(
" user32.dll " )]
        [
return : MarshalAs(UnmanagedType.Bool)]
        
private   static   extern   bool  SetForegroundWindow(IntPtr hWnd);
        [DllImport(
" user32.dll " )]
        
private   static   extern   bool  ShowWindowAsync(IntPtr hWnd,  int  nCmdShow);
        
private   const   int  SW_HIDE  =   0 ;            // 隐藏窗口,活动状态给令一个窗口 
         private   const   int  SW_SHOWNORMAL  =   1 ;      // 用原来的大小和位置显示一个窗口,同时令其进入活动状态 
         private   const   int  SW_SHOWMINIMIZED  =   2 ;   // 最小化窗口,并将其激活 
         private   const   int  SW_SHOWMAXIMIZED  =   3 ;   // 最大化窗口,并将其激活 
         private   const   int  SW_SHOWNOACTIVATE  =   4 // 用最近的大小和位置显示一个窗口,同时不改变活动窗口 
         private   const   int  SW_RESTORE  =   9 ;         // 用原来的大小和位置显示一个窗口,同时令其进入活动状态 
         private   const   int  SW_SHOWDEFAULT  =   10 ;    // 根据默认创建窗口时的样式来显示

        
///   <summary>
        
///  应用程序的主入口点。
        
///   </summary>
        [STAThread]
        
static   void  Main()
        {
            
bool  createdNew  =   true ;
            
using  (Mutex mutex  =   new  Mutex( true " MyApplicationName " out  createdNew))
            {
                
if  (createdNew)
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(
false );
                    Application.Run(
new  FrmMain());
                }
                
else
                {
                    Process current 
=  Process.GetCurrentProcess();
                    
foreach  (Process process  in  Process.GetProcessesByName(current.ProcessName))
                    {
                        
if  (process.Id  !=  current.Id)
                        {
                            SetForegroundWindow(process.MainWindowHandle);
                            ShowWindowAsync(process.MainWindowHandle, SW_RESTORE);
                            
break ;
                        }
                    }
                }
            }
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值