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:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->[STAThread]
staticvoidMain()
{
boolcreatedNew=true;
using(Mutexmutex=newMutex(true,"MyApplicationName",outcreatedNew))
{
if(createdNew)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(
false);
Application.Run(
newFrmMain());
}
}
}

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:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->[DllImport("user32.dll")]
[
return:MarshalAs(UnmanagedType.Bool)]
privatestaticexternboolSetForegroundWindow(IntPtrhWnd);

///<summary>
///Themainentrypointfortheapplication.
///</summary>
[STAThread]
staticvoidMain()
{
boolcreatedNew=true;
using(Mutexmutex=newMutex(true,"MyApplicationName",outcreatedNew))
{
if(createdNew)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(
false);
Application.Run(
newFrmMain());
}
else
{
Processcurrent
=Process.GetCurrentProcess();
foreach(ProcessprocessinProcess.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,最终代码如下:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->usingSystem;
usingSystem.Runtime.InteropServices;
usingSystem.Threading;
usingSystem.Windows.Forms;
usingSystem.Diagnostics;

namespace WinApp
{
staticclassProgram
{
[DllImport(
"user32.dll")]
[
return:MarshalAs(UnmanagedType.Bool)]
privatestaticexternboolSetForegroundWindow(IntPtrhWnd);
[DllImport(
"user32.dll")]
privatestaticexternboolShowWindowAsync(IntPtrhWnd,intnCmdShow);
privateconstintSW_HIDE=0;//隐藏窗口,活动状态给令一个窗口
privateconstintSW_SHOWNORMAL=1;//用原来的大小和位置显示一个窗口,同时令其进入活动状态
privateconstintSW_SHOWMINIMIZED=2;//最小化窗口,并将其激活
privateconstintSW_SHOWMAXIMIZED=3;//最大化窗口,并将其激活
privateconstintSW_SHOWNOACTIVATE=4;//用最近的大小和位置显示一个窗口,同时不改变活动窗口
privateconstintSW_RESTORE=9;//用原来的大小和位置显示一个窗口,同时令其进入活动状态
privateconstintSW_SHOWDEFAULT=10;//根据默认创建窗口时的样式来显示

///<summary>
///应用程序的主入口点。
///</summary>
[STAThread]
staticvoidMain()
{
boolcreatedNew=true;
using(Mutexmutex=newMutex(true,"MyApplicationName",outcreatedNew))
{
if(createdNew)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(
false);
Application.Run(
newFrmMain());
}
else
{
Processcurrent
=Process.GetCurrentProcess();
foreach(ProcessprocessinProcess.GetProcessesByName(current.ProcessName))
{
if(process.Id!=current.Id)
{
SetForegroundWindow(process.MainWindowHandle);
ShowWindowAsync(process.MainWindowHandle,SW_RESTORE);
break;
}
}
}
}
}
}
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值