在。net下使用c#和WPF(而不是Windows窗体或控制台),创建一个只能作为单个实例运行的应用程序的正确方法是什么?
我知道它与某种叫做互斥的神秘事物有关,我很少能找到有人费心停下来解释其中一个是什么。
代码还需要通知已经运行的实例,用户试图启动第二个实例,如果存在命令行参数,还可能传递任何命令行参数。
在。net下使用c#和WPF(而不是Windows窗体或控制台),创建一个只能作为单个实例运行的应用程序的正确方法是什么?
我知道它与某种叫做互斥的神秘事物有关,我很少能找到有人费心停下来解释其中一个是什么。
代码还需要通知已经运行的实例,用户试图启动第二个实例,如果存在命令行参数,还可能传递任何命令行参数。
当前回答
我在这里找不到一个简单的解决方案,所以我希望有人会喜欢这个:
更新2018-09-20
把这段代码放在Program.cs中:
using System.Diagnostics;
static void Main()
{
Process thisProcess = Process.GetCurrentProcess();
Process[] allProcesses = Process.GetProcessesByName(thisProcess.ProcessName);
if (allProcesses.Length > 1)
{
// Don't put a MessageBox in here because the user could spam this MessageBox.
return;
}
// Optional code. If you don't want that someone runs your ".exe" with a different name:
string exeName = AppDomain.CurrentDomain.FriendlyName;
// in debug mode, don't forget that you don't use your normal .exe name.
// Debug uses the .vshost.exe.
if (exeName != "the name of your executable.exe")
{
// You can add a MessageBox here if you want.
// To point out to users that the name got changed and maybe what the name should be or something like that^^
MessageBox.Show("The executable name should be \"the name of your executable.exe\"",
"Wrong executable name", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// Following code is default code:
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
其他回答
使用互斥量解决方案:
using System;
using System.Windows.Forms;
using System.Threading;
namespace OneAndOnlyOne
{
static class Program
{
static String _mutexID = " // generate guid"
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Boolean _isNotRunning;
using (Mutex _mutex = new Mutex(true, _mutexID, out _isNotRunning))
{
if (_isNotRunning)
{
Application.Run(new Form1());
}
else
{
MessageBox.Show("An instance is already running.");
return;
}
}
}
}
}
基于Matt Davis的答案,为方便起见包装成一个类。
public static class SingleAppInstanceChecker
{
/// <summary>
/// Arbitrary unique string
/// </summary>
private static Mutex _mutex = new Mutex(true, "0d12ad74-026f-40c3-bdae-e178ddee8602");
public static bool IsNotRunning()
{
return _mutex.WaitOne(TimeSpan.Zero, true);
}
}
使用示例:
private void Application_Startup(object sender, StartupEventArgs e)
{
if (!SingleAppInstanceChecker.IsNotRunning())
{
MessageBox.Show("Application is already running.");
// Exit application using:
// Environment.Exit(1);
// Application.Current.Shutdown();
// Etc...
return;
}
// Allow startup and continue with normal processing
// ...
}
永远不要使用命名互斥来实现单实例应用程序(至少在生产代码中不要这样做)。恶意代码可以很容易地DoS(拒绝服务)你的屁股…
这里有一个解决方案:
Protected Overrides Sub OnStartup(e As StartupEventArgs)
Const appName As String = "TestApp"
Dim createdNew As Boolean
_mutex = New Mutex(True, appName, createdNew)
If Not createdNew Then
'app is already running! Exiting the application
MessageBox.Show("Application is already running.")
Application.Current.Shutdown()
End If
MyBase.OnStartup(e)
End Sub
请检查这里提出的解决方案,它使用信号量来确定现有实例是否已经在运行,适用于WPF应用程序,并且可以通过使用TcpListener和TcpClient将参数从第二个实例传递给第一个已经运行的实例:
它不仅适用于。net Framework,也适用于。net Core。