




http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0 - Single-Instance_Detection_and_Management.
В этой статье просто объясняется, как создать приложение Windows с контролем количества его экземпляров или запустить только один экземпляр. Это очень типичная потребность бизнес-приложения. Уже существует множество других возможных решений, позволяющих контролировать это.
У Хансельмана есть Почта при использовании класса WinFormsApplicationBase из сборки Microsoft.VisualBasic для этого.
Вы должны использовать System.Diagnostics.Process.
Обычно это делается с помощью именованного Mutex (используйте new Mutex («имя вашего приложения», true) и проверьте возвращаемое значение), но в Microsoft.VisualBasic.dll есть также некоторые классы поддержки, которые могу сделать это за тебя.
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;
}
Я думаю, что должен увидеть это: odetocode.com/blogs/scott/archive/2004/08/20/…
@SubmarineX Как вы уверены, что эта статья верна? это все еще споры между мьютексом и codeproject.com/Articles/4975/…
Потрясающе Просто отлично, спасибо за ваше время и усилия
-1 Хотя это быстрое решение, его также очень легко обойти, если a.exe можно переименовать в b.exe, и оба будут работать. + другие случаи, когда это просто не работает должным образом. Используйте с осторожностью!
Это не работает с моно-проявкой. Однако в среде Windows он отлично работает.
Используя Visual Studio 2005 или 2008, когда вы создаете проект для исполняемого файла, в окнах свойств на панели «Приложение» есть флажок «Создать приложение с одним экземпляром», который можно активировать, чтобы преобразовать приложение в приложение с одним экземпляром. .
Вот снимок окна, о котором я говорю:
Это проект Windows-приложения Visual Studio 2008.
Я искал этот флажок, который вы упомянули, для моего приложения C# / WPF, но его нет.
Я также не вижу этого в свойствах моего приложения VS 2008 C# / WinForms.
Тоже не в VS2005. Он, должно быть, упоминает старую студию VB.
Да, опция существует, я изменил сообщение, чтобы добавить снимок окна, в котором вы можете найти эту опцию.
Опция существует только для приложения VB.NET, но не для C#. Судя по всему, в самой опции используется класс WinFormsApplicationBase из сборки Microsoft.VisualBasic.
Используйте 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";
Использование мьютекса также работает для кода, отличного от .net (хотя синтаксис может отличаться)
Вот немного более полная версия с хорошими комментариями: stackoverflow.com/questions/229565/…
@ClarkKent: просто случайная строка, чтобы имя Mutex не совпадало с именем из другого приложения.
Может ли это ограничиться определенным количеством экземпляров?
это не работает для меня, я нашел GUID из параметров проекта application1, который я хочу проверить. При запуске application1 я запускаю application2, которое должно проверить, запущено ли application1. Это не дает мне сообщения об ошибке.
Что вы будете делать, если используете C# / WPF, где нет явного основного метода? Я не хочу явно объявлять main, поскольку он автоматически создается с некоторым дополнительным контентом.
Чтобы иметь лучший контроль при управлении версиями или изменении идентификатора вашего приложения, вы можете использовать: string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;, который получит Guid исполняемой сборки
Я думаю, что важное предостережение для Mutex заключается в следующем: класс Mutex обеспечивает идентификацию потока, поэтому мьютекс может быть выпущен только тем потоком, который его получил. Напротив, класс Semaphore не обеспечивает идентификацию потока. Мьютекс также можно передавать через границы домена приложения.
@yellavon создайте файл .cs, вставьте namespace your_app {public partial class App { private void ApplicationStart(object sender, StartupEventArgs e) { ... } } }, затем установите <Application ... Startup = "ApplicationStart"> в App.config
Разве этот ответ не зависит от того, что Application.Run() не возвращается, пока приложение не выйдет? Я не знаю, как это работает, но я бы подумал, что многопоточное приложение не может зависеть от чего-то подобного. Application.Run() предназначен для Windows Forms, не так ли? В WPF мы даже не должны использовать метод «Main», верно?
Как это могло быть ответом !? Это вообще не работает.
Мне потребовалось время, чтобы понять, что приведенный выше код работает только в том случае, если мьютекс существует, пока запущен экземпляр. Я удалил блок using и изменил переменную мьютекса на статическую (или общую в vb.net). После этого все заработало как положено.
Почему GUID? Просто имя моего приложения довольно уникально на компьютере пользователя. Какой-нибудь особый случай для GUID?
Похоже, что на данный момент было предложено 3 основных метода.
Какие-то оговорки, которые я пропустил?
Я не думаю, что 3 очень эффективен. Проголосовал бы за Mutex, много раз пользовался им без проблем. Я никогда не использовал пункт 1, не знаю, как это работает, когда вы в C#.
Вариант 1 по-прежнему работает с WPF, он просто немного сложнее. msdn.microsoft.com/en-us/library/ms771662.aspx
Вот код, который вам нужен, чтобы гарантировать, что работает только один экземпляр. Это метод использования именованного мьютекса.
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();
}
}
}
Для приложения WPF используйте Application.Current.Shutdown (); Этот метод работает как шарм. Спасибо, Terrapin.
Здесь главное сделать мьютекс статичным. Как и в другом случае, сборщик мусора его заберет.
Мне понравилась простота и ясность названного Mutex. Этот код краткий и эффективный.
Используйте VB.NET! Нет: правда;)
с помощью Microsoft.VisualBasic.ApplicationServices;
WindowsFormsApplicationBase из VB.Net предоставляет вам свойство «SingleInstace», которое определяет другие экземпляры и позволяет запускать только один экземпляр.
[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 имеет значение
-1, потому что вы не можете использовать блок using с мьютексом, что сделало бы KeepAlive излишним. И да, я действительно думаю, что Джон Скит ошибся. Он не поясняет, почему в этом случае было бы неправильно использовать мьютекс.
Это код для 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());
}
}
(Примечание: это забавное решение! Оно работает, но для этого используется плохой дизайн GDI +.)
Поместите изображение в свое приложение и загрузите его при запуске. Удерживайте, пока приложение не закроется. Пользователь не сможет запустить второй экземпляр. (Конечно, решение мьютекса намного чище)
private static Bitmap randomName = new Bitmap("my_image.jpg");
Это действительно великолепно в своей простоте, и он работает практически с любыми типами файлов, а не только с изображениями. Мне кажется, что решение Mutex далеко не «чистое». Это чрезвычайно сложно, и, по-видимому, есть много способов потерпеть неудачу из-за неправильного выполнения. Также требуется метод Main(), который противоречит тому, как должен работать WPF.
Это что-то вроде использования ошибки. Это работает, но не для этой цели. Я бы не стал использовать это как профессионал.
Да, к сожалению, у нас нет такого эффективного и простого решения, которое бы не полагалось на исключения.
Хотя это не совсем ошибка. .NET по-прежнему ведет себя так, как задумано.
Я попробовал все решения здесь, и в моем проекте 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
}
Мне нужно было закрыть другие дела только с некоторыми условиями, это хорошо сработало для моей цели
Вам не нужно фактически получать мьютекс и освобождать его. Все, что вам нужно знать, это то, что другое приложение уже создало объект (то есть его счетчик ссылок ядра> = 1).
Это сработало для меня на чистом 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());
}
Попробовав несколько решений, я вопрос. В итоге я использовал пример для 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"
1 - Создать ссылку в program.cs ->
using System.Diagnostics;
2 - Поместите в void Main() в качестве первой строки кода ->
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return;
Вот и все.
Чем это отличается от Mutex? Есть ли подвох?
Он использует имя процесса. Если имя повторяется, это генерирует ложный флаг. В любом другом случае он чище, чем мьютекс
Как насчет этого, просто используя 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);
}
Обязательно учитывайте безопасность при ограничении приложения одним экземпляром:
Полная статья: 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/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);
}
}
Я использую это в течение нескольких лет, но теперь хочу перейти на решение на основе Mutex. У меня есть клиенты, которые сообщают о проблемах с этим, и я подозреваю, что для этого используется удаленное взаимодействие.