在.NET中,阻止一个应用程序的多个实例同时运行的最佳方法是什么? 而且,如果没有"最佳"技术,则每种解决方案要考虑哪些注意事项?
使用Mutex。上面使用GetProcessByName的示例之一有很多警告。这是一篇关于该主题的好文章:
http://odetocode.com/Blogs/scott/archive/2004/08/20/401.aspx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| [STAThread]
static void Main()
{
using(Mutex mutex = new Mutex(false,"Global\" + appGuid))
{
if(!mutex.WaitOne(0, false))
{
MessageBox.Show("Instance already running");
return;
}
Application.Run(new Form1());
}
}
private static string appGuid ="c0a76b5a-12ab-45c5-b9d9-d693faa6e7b9"; |
1 2 3 4 5
| if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
{
AppLog.Write("Application XXXX already running. Only one instance of this application is allowed", AppLog.LogMessageType.Warn);
return;
} |
这是您需要确保仅运行一个实例的代码。这是使用命名互斥锁的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Program
{
static System.Threading.Mutex singleton = new Mutex(true,"My App Name");
static void Main(string[] args)
{
if (!singleton.WaitOne(TimeSpan.Zero, true))
{
//there is already another instance running!
Application.Exit();
}
}
} |
Hanselman撰写了有关使用Microsoft.VisualBasic程序集的WinFormsApplicationBase类执行此操作的文章。
到目前为止,似乎已经提出了3种基本技术。
从Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase类派生并将IsSingleInstance属性设置为true。 (我认为这里需要说明的是,这不适用于WPF应用程序,对吗?)
使用命名的互斥锁并检查它是否已经创建。
获取正在运行的进程的列表,并比较进程的名称。 (这有一个警告,要求您的进程名称相对于在给定用户计算机上运行的任何其他进程是唯一的。)
有什么需要注意的事项吗?
在为可执行文件创建项目时使用Visual Studio 2005或2008,在"应用程序"面板内的属性窗口上,有一个名为"制作单实例应用程序"的复选框,您可以激活该复选框以在单实例应用程序上转换应用程序。
这是我正在谈论的窗口的捕获:

这是一个Visual Studio 2008 Windows应用程序项目。
我在这里尝试了所有解决方案,但在我的C#.net 4.0项目中没有任何效果。希望在这里为某人提供对我有用的解决方案:
作为主类变量:
1 2
| private static string appGuid ="WRITE AN UNIQUE GUID HERE";
private static Mutex mutex; |
当您需要检查应用程序是否已在运行时:
1 2 3 4 5 6 7 8 9 10
| bool mutexCreated;
mutex = new Mutex(true,"Global\" + appGuid, out mutexCreated);
if (mutexCreated)
mutex.ReleaseMutex();
if (!mutexCreated)
{
//App is already running, close this!
Environment.Exit(0); //i used this because its a console app
} |
我只需要在某些条件下关闭其他位置,这对于我的目的来说效果很好
http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0-单个实例检测和管理
1-在program.cs中创建引用->
1
| using System.Diagnostics; |
2-放入void Main()作为第一行代码->
1 2
| if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return; |
而已。
使用VB.NET!
不完全是 ;)
使用Microsoft.VisualBasic.ApplicationServices;
VB.Net的WindowsFormsApplicationBase为您提供了" SingleInstace"属性,该属性确定其他实例,并且仅允许一个实例运行。
本文仅说明如何创建一个Windows应用程序,该应用程序可以控制其实例数或仅运行单个实例。这是业务应用程序非常典型的需求。已经有很多其他可能的解决方案来控制这一点。
http://www.openwinforms.com/single_instance_application.html
这是VB.Net的代码
1 2 3 4 5 6 7 8 9 10
| Private Shared Sub Main()
Using mutex As New Mutex(False, appGuid)
If Not mutex.WaitOne(0, False) Then
MessageBox.Show("Instance already running","ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End If
Application.Run(New Form1())
End Using
End Sub |
这是C#的代码
1 2 3 4 5 6 7 8 9 10 11
| private static void Main()
{
using (Mutex mutex = new Mutex(false, appGuid)) {
if (!mutex.WaitOne(0, false)) {
MessageBox.Show("Instance already running","ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Application.Run(new Form1());
}
} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| [STAThread]
static void Main() // args are OK here, of course
{
bool ok;
m = new System.Threading.Mutex(true,"YourNameHere", out ok);
if (! ok)
{
MessageBox.Show("Another instance is already running.");
return;
}
Application.Run(new Form1()); // or whatever was there
GC.KeepAlive(m); // important!
} |
来自:确保.NET应用程序的单个实例
和:单实例应用程序互斥
与@Smink和@Imjustpondering相同的答案略有不同:
乔恩·斯凯特(Jon Skeet)关于C#的常见问题解答,以找出GC.KeepAlive为什么重要
尝试多种解决方案后,我的问题。我最终在这里使用了WPF的示例:http://www.c-sharpcorner.com/UploadFile/f9f215/how-to-restrict-the-application-to-just-one-instance/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public partial class App : Application
{
private static Mutex _mutex = null;
protected override void OnStartup(StartupEventArgs e)
{
const string appName ="MyAppName";
bool createdNew;
_mutex = new Mutex(true, appName, out createdNew);
if (!createdNew)
{
//app is already running! Exiting the application
Application.Current.Shutdown();
}
}
} |
在App.xaml中:
1 2 3
| x:Class="*YourNameSpace*.App"
StartupUri="MainWindow.xaml"
Startup="App_Startup" |
(注意:这是一个有趣的解决方案!它可以工作,但是使用了错误的GDI +设计来实现此目的。)
将图像与您的应用程序一起放入并在启动时加载。按住它,直到应用程序退出。用户将无法启动第二个实例。 (当然互斥锁解决方案要干净得多)
1
| private static Bitmap randomName = new Bitmap("my_image.webp"); |
只需使用StreamWriter,该怎么办?
1
| System.IO.File.StreamWriter OpenFlag = null; //globally |
和
1 2 3 4 5 6 7 8
| try
{
OpenFlag = new StreamWriter(Path.GetTempPath() +"OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
Environment.Exit(0);
} |
您必须使用System.Diagnostics.Process。
检出:http://www.devx.com/tips/Tip/20044
http://www.codeproject.com/KB/cs/SingleInstancingWithIpc.aspx
这些答案对我都不起作用,因为我需要使用monodevelop在Linux下工作。 这对我很有用:
调用此方法并为其传递唯一ID
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public static void PreventMultipleInstance(string applicationId)
{
// Under Windows this is:
// C:\Users\SomeUser\AppData\Local\Temp\
// Linux this is:
// /tmp/
var temporaryDirectory = Path.GetTempPath();
// Application ID (Make sure this guid is different accross your different applications!
var applicationGuid = applicationId +".process-lock";
// file that will serve as our lock
var fileFulePath = Path.Combine(temporaryDirectory, applicationGuid);
try
{
// Prevents other processes from reading from or writing to this file
var _InstanceLock = new FileStream(fileFulePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
_InstanceLock.Lock(0, 0);
MonoApp.Logger.LogToDisk(LogType.Notification,"04ZH-EQP0","Aquired Lock", fileFulePath);
// todo investigate why we need a reference to file stream. Without this GC releases the lock!
System.Timers.Timer t = new System.Timers.Timer()
{
Interval = 500000,
Enabled = true,
};
t.Elapsed += (a, b) =>
{
try
{
_InstanceLock.Lock(0, 0);
}
catch
{
MonoApp.Logger.Log(LogType.Error,"AOI7-QMCT","Unable to lock file");
}
};
t.Start();
}
catch
{
// Terminate application because another instance with this ID is running
Environment.Exit(102534);
}
} |
这在纯C#中对我有用。 try / catch是循环中列表中的某个进程可能退出的时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| using System.Diagnostics;
....
[STAThread]
static void Main()
{
...
int procCount = 0;
foreach (Process pp in Process.GetProcesses())
{
try
{
if (String.Compare(pp.MainModule.FileName, Application.ExecutablePath, true) == 0)
{
procCount++;
if(procCount > 1) {
Application.Exit();
return;
}
}
}
catch { }
}
Application.Run(new Form1());
} |
通常,它是使用一个名为Mutex的文件(使用新的Mutex("您的应用程序名称",true)并检查返回值)完成的,但是Microsoft.VisualBasic.dll中也有一些支持类可以为您完成此操作。
将应用程序限制为单个实例时,请务必考虑安全性:
全文:
https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813
We are using a named mutex with a fixed name in order to detect
whether another copy of the program is running. But that also means an
attacker can create the mutex first, thereby preventing our program
from running at all! How can I prevent this type of denial of service
attack?
...
If the attacker is running in the same security context as your
program is (or would be) running in, then there is nothing you can do.
Whatever"secret handshake" you come up with to determine whether
another copy of your program is running, the attacker can mimic it.
Since it is running in the correct security context, it can do
anything that the"real" program can do.
...
Clearly you can't protect yourself from an attacker running at the
same security privilege, but you can still protect yourself against
unprivileged attackers running at other security privileges.
尝试在互斥锁上设置DACL,这是.NET方法:
https://msdn.microsoft.com/zh-CN/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx