在.NET中,防止应用程序的多个实例同时运行的最佳方法是什么?如果没有“最佳”技术,每种解决方案需要考虑哪些注意事项?
答案 0 :(得分:143)
使用互斥锁。上面使用GetProcessByName的一个例子有很多警告。这是一篇关于这个主题的好文章:
http://odetocode.com/Blogs/scott/archive/2004/08/20/401.aspx
[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 :(得分:18)
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;
}
答案 2 :(得分:17)
以下是确保只运行一个实例所需的代码。这是使用命名互斥锁的方法。
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();
}
}
}
答案 3 :(得分:7)
Hanselman有a post使用Microsoft.VisualBasic程序集中的WinFormsApplicationBase类来执行此操作。
答案 4 :(得分:5)
听起来到目前为止已经提出了3种基本技术。
我错过了任何警告?
答案 5 :(得分:4)
我在这里尝试了所有的解决方案,在我的C#.net 4.0项目中没有任何效果。希望能帮助这里的人找到适合我的解决方案:
作为主要类变量:
private static string appGuid = "WRITE AN UNIQUE GUID HERE";
private static Mutex mutex;
当您需要检查应用是否已在运行时:
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
}
我需要在某些条件下关闭其他问题,这对我的目的很有效
答案 6 :(得分:4)
在为可执行文件创建项目时使用Visual Studio 2005或2008,在“应用程序”面板内的属性窗口上有一个名为“创建单实例应用程序”的复选框,您可以激活该复选框以转换应用程序单实例应用程序。
这是我正在谈论的窗口的捕获:
这是一个Visual Studio 2008 Windows应用程序项目。
答案 7 :(得分:3)
http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0 - 单Instance_Detection_and_Management
答案 8 :(得分:3)
1 - 在program.cs中创建一个引用 - >
using System.Diagnostics;
2 - 作为第一行代码加入void Main()
- >
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return;
就是这样。
答案 9 :(得分:2)
本文简单介绍如何创建一个Windows应用程序,控制其实例数或仅运行单个实例。这是业务应用程序的非常典型的需求。已经有很多其他可能的解决方案来控制它。
http://www.openwinforms.com/single_instance_application.html
答案 10 :(得分:2)
使用VB.NET! 不:真的;)
使用Microsoft.VisualBasic.ApplicationServices;
来自VB.Net的WindowsFormsApplicationBase为您提供了一个“SingleInstace”属性,它确定其他实例并且只运行一个实例。
答案 11 :(得分:1)
这是VB.Net的代码
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#的代码
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());
}
}
答案 12 :(得分:1)
(注意:这是一个有趣的解决方案!它有效,但使用糟糕的GDI +设计来实现这一点。)
将图片放入您的应用并在启动时加载它。按住它直到应用程序退出。用户将无法启动第二个实例。 (当然互斥解决方案更清洁)
private static Bitmap randomName = new Bitmap("my_image.jpg");
答案 13 :(得分:1)
您必须使用System.Diagnostics.Process。
答案 14 :(得分:1)
尝试多种解决方案之后我就回答了问题。我最终在这里使用了 WPF 的示例:http://www.c-sharpcorner.com/UploadFile/f9f215/how-to-restrict-the-application-to-just-one-instance/
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中:
x:Class="*YourNameSpace*.App"
StartupUri="MainWindow.xaml"
Startup="App_Startup"
答案 15 :(得分:1)
答案 16 :(得分:1)
只需使用StreamWriter
,这个怎么样?
System.IO.File.StreamWriter OpenFlag = null; //globally
和
try
{
OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
Environment.Exit(0);
}
答案 17 :(得分:0)
通常使用命名的互斥锁(使用新的互斥锁(“你的应用程序名称”,真实)并检查返回值),但Microsoft.VisualBasic.dll中还有一些支持类can do it for you。< / p>
答案 18 :(得分:0)
[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!
}
来自:Ensuring a single instance of .NET Application
和:Single Instance Application Mutex
与@Smink和@Imjustpondering相同的答案:
答案 19 :(得分:0)
这对我来说是纯粹的C#。 try / catch是在循环期间列表中的进程可能退出的时候。
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());
}
答案 20 :(得分:0)
将应用程序限制为单个实例时,请务必考虑安全性:
全文: https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813
我们正在使用具有固定名称的命名互斥锁来检测 是否正在运行另一个程序副本。但这也意味着一个 攻击者可以先创建互斥锁,从而阻止我们的程序 从一切运行!如何防止此类拒绝服务 攻击?
...
如果攻击者在与您的安全环境相同的安全环境中运行 程序是(或将要)运行,然后你无能为力。 无论你提出什么“秘密握手”来确定是否 你的程序的另一个副本正在运行,攻击者可以模仿它。 由于它在正确的安全上下文中运行,它可以做到 “真实”程序可以做的任何事情。
...
显然,你无法保护自己免受攻击者的攻击 相同的安全权限,但您仍然可以保护自己免受攻击 没有特权的攻击者以其他安全权限运行。
尝试在互斥锁上设置DACL,这是.NET方式: https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx
答案 21 :(得分:0)
这些答案都没有对我有用,因为我需要使用monodevelop在Linux下使用它。这对我来说很棒:
调用此方法并为其传递唯一ID
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);
}
}