Как лучше всего предотвратить одновременный запуск нескольких экземпляров приложения в .NET? И если нет «лучшей» техники, какие предостережения следует учитывать при каждом решении?
Как лучше всего предотвратить одновременный запуск нескольких экземпляров приложения в .NET? И если нет «лучшей» техники, какие предостережения следует учитывать при каждом решении?
Ответы:
Используйте Mutex. В одном из приведенных выше примеров использования 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";
string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;который получит руководство исполняемой сборки
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;
}
Вот код, который вам нужен, чтобы гарантировать, что работает только один экземпляр. Это метод использования именованного мьютекса.
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();
}
}
}
У Хансельмана есть сообщение об использовании для этого класса WinFormsApplicationBase из сборки Microsoft.VisualBasic.
Похоже, что на данный момент было предложено 3 основных метода.
Какие-то оговорки, которые я пропустил?
1 - Создать ссылку в program.cs ->
using System.Diagnostics;
2 - Поместите в void Main()первую строку кода ->
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return;
Вот и все.
Mutex? Есть ли подвох?
Используя Visual Studio 2005 или 2008, когда вы создаете проект для исполняемого файла, в окнах свойств на панели «Приложение» есть флажок «Создать приложение с одним экземпляром», который вы можете активировать для преобразования приложения в приложение с одним экземпляром. ,
Вот снимок окна, о котором я говорю:
Это проект Windows-приложения Visual Studio 2008.
Я попробовал все решения здесь, и в моем проекте 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
}
Мне нужно было закрыть другие дела только с некоторыми условиями, это хорошо сработало для моей цели
http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0 - Single-Instance_Detection_and_Management
Попробовав несколько решений, я вопрос. В итоге я использовал пример для 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"
В этой статье просто объясняется, как создать приложение Windows с контролем количества его экземпляров или запустить только один экземпляр. Это очень типичная потребность бизнес-приложения. Уже существует множество других возможных решений для контроля этого.
http://www.openwinforms.com/single_instance_application.html
Это код для 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());
}
}
Вы должны использовать System.Diagnostics.Process.
Проверить: http://www.devx.com/tips/Tip/20044
(Примечание: это забавное решение! Оно работает, но для этого используется плохой дизайн GDI +.)
Вставьте изображение в свое приложение и загрузите его при запуске. Удерживайте, пока приложение не закроется. Пользователь не сможет запустить второй экземпляр. (Конечно, решение мьютекса намного чище)
private static Bitmap randomName = new Bitmap("my_image.jpg");
Main()метод, который противоречит принципу работы WPF.
[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, но с изюминкой:
Часто задаваемые вопросы Джона Скита по C #, чтобы узнать, почему GC.KeepAlive имеет значение
Просто используя a 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);
}
Обычно это делается с помощью именованного Mutex (используйте new Mutex («имя вашего приложения», true) и проверьте возвращаемое значение), но в Microsoft.VisualBasic.dll есть также несколько классов поддержки, которые могут сделать это за вас .
Это сработало для меня на чистом C #. попытка / улов - это когда, возможно, процесс в списке завершается во время вашего цикла.
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());
}
Обязательно учитывайте безопасность при ограничении приложения одним экземпляром:
Полная статья: 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
Ни один из этих ответов не помог мне, потому что мне нужно, чтобы это работало под Linux с использованием monodevelop. Это отлично работает для меня:
Вызовите этот метод, передав ему уникальный идентификатор
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);
}
}