Как использовать C # и WPF под .NET (а не Windows Forms или консоль), как правильно создать приложение, которое можно запустить только как один экземпляр?
Я знаю, что это как-то связано с какой-то мифической вещью, называемой мьютексом, редко я могу найти кого-то, кто мешает остановиться и объяснить, что из этого.
Код должен также информировать уже запущенный экземпляр о том, что пользователь попытался запустить второй, и, возможно, также передать любые аргументы командной строки, если таковые имеются.
Ответы:
Вот очень хорошая статья о решении Mutex. Описанный в статье подход выгоден по двум причинам.
Во-первых, он не требует зависимости от сборки Microsoft.VisualBasic. Если бы мой проект уже зависел от этой сборки, я бы, вероятно, рекомендовал использовать подход, показанный в другом ответе . Но в действительности я не использую сборку Microsoft.VisualBasic, и я бы не стал добавлять ненужную зависимость в свой проект.
Во-вторых, в статье показано, как вывести существующий экземпляр приложения на передний план, когда пользователь пытается запустить другой экземпляр. Это очень приятный штрих, который не рассматриваются в других решениях Mutex, описанных здесь.
ОБНОВИТЬ
По состоянию на 01.08.2014 статья, на которую я ссылался выше, все еще активна, но блог некоторое время не обновлялся. Это заставляет меня беспокоиться о том, что в конечном итоге оно может исчезнуть, а вместе с ним и предлагаемое решение. Я воспроизводю содержание статьи здесь для потомков. Слова принадлежат исключительно владельцу блога в Sanity Free Coding .
источник
Mutex
конструктор просто требует строку, поэтому вы можете указать любое имя строки, например «This Is My Mutex». Поскольку «Mutex» - это системный объект, который доступен другим процессам, вы обычно хотите, чтобы имя было уникальным, чтобы оно не конфликтовало с другими именами «Mutex» в той же системе. В статье загадочно выглядящая строка - «Guid». Вы можете создать это программно, позвонивSystem.Guid.NewGuid()
. В случае статьи пользователь, вероятно, сгенерировал ее через Visual Studio, как показано здесь: msdn.microsoft.com/en-us/library/ms241442(VS.80).aspxВы можете использовать класс Mutex, но вскоре вы обнаружите, что вам нужно будет реализовать код для передачи аргументов и тому подобное. Что ж, я научился уловке при программировании в WinForms, когда читал книгу Криса Села . Этот трюк использует логику, которая уже доступна нам в рамках. Я не знаю о вас, но когда я узнаю о вещах, которые я могу повторно использовать в рамках, это обычно - путь, который я выбираю вместо того, чтобы заново изобретать колесо. Если, конечно, он не делает все, что я хочу.
Когда я попал в WPF, я нашел способ использовать тот же код, но в приложении WPF. Это решение должно отвечать вашим потребностям исходя из вашего вопроса.
Во-первых, нам нужно создать класс нашего приложения. В этом классе мы собираемся переопределить событие OnStartup и создать метод с именем Activate, который будет использоваться позже.
Во-вторых, нам нужно создать класс, который сможет управлять нашими экземплярами. Прежде чем мы пройдем через это, мы на самом деле собираемся повторно использовать некоторый код, который находится в сборке Microsoft.VisualBasic. Поскольку в этом примере я использую C #, мне пришлось сделать ссылку на сборку. Если вы используете VB.NET, вам не нужно ничего делать. Класс, который мы будем использовать, - это WindowsFormsApplicationBase, который наследует от нас наш менеджер экземпляров, а затем использует свойства и события для обработки одного экземпляра.
По сути, мы используем биты VB для обнаружения одного экземпляра и обработки соответственно. OnStartup будет запущен при загрузке первого экземпляра. OnStartupNextInstance запускается при повторном запуске приложения. Как видите, я могу получить то, что было передано в командной строке через аргументы события. Я установил значение в поле экземпляра. Вы можете проанализировать командную строку здесь или передать ее приложению через конструктор и вызов метода Activate.
В-третьих, пришло время создать нашу EntryPoint. Вместо того, чтобы обновлять приложение, как вы это обычно делаете, мы собираемся воспользоваться нашим SingleInstanceManager.
Что ж, я надеюсь, что вы сможете следить за всем и сможете использовать эту реализацию и сделать ее своей.
источник
От сюда .
Обычное использование межпроцессного Mutex состоит в том, чтобы гарантировать, что только экземпляр программы может работать одновременно. Вот как это делается:
Хорошей особенностью Mutex является то, что если приложение завершается без предварительного вызова ReleaseMutex, CLR автоматически освобождает Mutex.
источник
MSDN на самом деле имеет пример приложения для C # и VB, чтобы сделать именно это: http://msdn.microsoft.com/en-us/library/ms771662(v=VS.90).aspx
'Another instance of the app is running. Bye'
оно не будет очень счастливым пользователем. Вы просто ДОЛЖНЫ (в приложении с графическим интерфейсом) переключиться на это приложение и передать предоставленные аргументы - или, если параметры командной строки не имеют значения, вы должны открыть приложение, которое, возможно, было свернуто.Фреймворк уже имеет поддержку для этого - просто какой-то идиот назвал DLL,
Microsoft.VisualBasic
и его не вставилиMicrosoft.ApplicationUtils
или что-то в этом роде. Преодолеть это - или открыть Reflector.Совет: Если вы используете этот подход в точности так, как есть, и у вас уже есть App.xaml с ресурсами и т. Д., Вы тоже захотите взглянуть на это .
источник
Этот код должен идти к основному методу. Посмотрите здесь для получения дополнительной информации о методе main в WPF.
Способ 2
Примечание. Вышеуказанные методы предполагают, что ваш процесс / приложение имеет уникальное имя. Потому что он использует имя процесса, чтобы найти, если какие-либо существующие процессоры. Таким образом, если ваше приложение имеет очень распространенное имя (например, «Блокнот»), вышеуказанный подход не будет работать.
источник
ProcessName
возвращает имя исполняемого файла минусexe
. Если вы создадите приложение под названием «Блокнот», и блокнот Windows будет запущен, он обнаружит его как запущенное приложение.Ну, у меня есть одноразовый класс для этого, который легко работает для большинства случаев использования:
Используйте это так:
Вот:
источник
Новым приложением WPF Single Instance является новое приложение, которое использует Mutex и IPC, а также передает любые аргументы командной строки в работающий экземпляр .
источник
Код C # .NET Single Instance Application который является ссылкой для помеченного ответа, является отличным началом.
Однако я обнаружил, что он не очень хорошо справляется со случаями, когда уже существующий экземпляр имеет модальное диалоговое окно, независимо от того, является ли это диалоговое окно управляемым (например, другой формой, такой как поле about), или неуправляемым (например, OpenFileDialog даже при использовании стандартного класса .NET). В исходном коде активируется основная форма, но модальная остается неактивной, что выглядит странно, плюс пользователь должен щелкнуть по ней, чтобы продолжить использование приложения.
Итак, я создал служебный класс SingleInstance для автоматической обработки всего этого для приложений Winforms и WPF.
Winforms :
1) измените класс Program следующим образом:
2) изменить класс главного окна следующим образом:
WPF:
1) измените страницу приложения следующим образом (и убедитесь, что вы установили действие ее сборки на страницу, чтобы можно было переопределить метод Main):
2) изменить класс главного окна следующим образом:
А вот и полезный класс:
источник
Вот пример, который позволяет вам иметь один экземпляр приложения. Когда загружаются какие-либо новые экземпляры, они передают свои аргументы основному запущенному экземпляру.
источник
Просто некоторые мысли: бывают случаи, когда требуется, чтобы только один экземпляр приложения не был «хромым», как некоторые заставили бы вас поверить. Приложения баз данных и т. Д. На порядок усложняются, если разрешить нескольким экземплярам приложения для одного пользователя доступ к базе данных (вы знаете, все это обновляет все записи, которые открываются в нескольких экземплярах приложения для пользователей машина и тд). Во-первых, для «конфликта имен» не используйте удобочитаемое имя - используйте вместо него GUID или, еще лучше, GUID + читаемое имя. Возможности столкновения имен просто выпали из радара, и Mutex это не волнует. Как кто-то указал, DOS-атака будет неудачной, но если злоумышленник попытается получить имя мьютекса и включить его в свое приложение, В любом случае вы в значительной степени являетесь целью, и вам придется сделать НАМНОГО больше, чтобы защитить себя, чем просто поиграть с именем мьютекса. Кроме того, если вы используете вариант: новый Mutex (true, «некоторый GUID плюс имя», вне AIsFirstInstance), у вас уже есть индикатор того, является ли Mutex первым экземпляром.
источник
Так много ответов на такой, казалось бы, простой вопрос. Просто чтобы немного встряхнуть, вот мое решение этой проблемы.
Создание Mutex может быть проблематичным, потому что JIT-er видит, что вы используете его только для небольшой части вашего кода, и хочет пометить его как готовый для сборки мусора. Он очень хочет превзойти вас, думая, что вы не собираетесь использовать этот Mutex так долго. На самом деле вы хотите использовать этот Mutex до тех пор, пока ваше приложение работает. Лучший способ убедить сборщика мусора оставить вас Mutex в одиночестве - сказать, чтобы он оставался в живых, несмотря на разные поколения гаражной коллекции. Пример:
Я поднял идею с этой страницы: http://www.ai.uga.edu/~mc/SingleInstance.html
источник
Похоже, есть действительно хороший способ справиться с этим:
Приложение для одного экземпляра WPF
Это обеспечивает класс, который вы можете добавить, который управляет всеми мьютексами и сообщениями, чтобы упростить вашу реализацию до такой степени, что это просто тривиально.
источник
Следующий код - мое решение WCF с именованными каналами для регистрации приложения с одним экземпляром. Это хорошо, потому что это также вызывает событие, когда другой экземпляр пытается запустить, и получает командную строку другого экземпляра.
Он ориентирован на WPF, поскольку использует
System.Windows.StartupEventHandler
класс, но его можно легко изменить.Этот код требует ссылки на
PresentationFramework
, иSystem.ServiceModel
.Применение:
Исходный код:
источник
Никогда не следует использовать именованный мьютекс для реализации приложения с одним экземпляром (или, по крайней мере, не для производственного кода). Вредоносный код может легко сделать DoS ( отказ в обслуживании ) вашей задницей ...
источник
Посмотрите на следующий код. Это отличное и простое решение для предотвращения нескольких экземпляров приложения WPF.
источник
Вот что я использую. Он объединил перечисление процессов для переключения и мьютекса для защиты от «активных кликеров»:
источник
Я нашел более простое решение, похожее на Дейла Рэйгана, но немного измененное. Он делает практически все, что вам нужно, и на основе стандартного класса Microsoft WindowsFormsApplicationBase.
Во-первых, вы создаете класс SingleInstanceController, который вы можете использовать во всех других приложениях с одним экземпляром, которые используют Windows Forms:
Затем вы можете использовать его в своей программе следующим образом:
И программа, и решение SingleInstanceController_NET должны ссылаться на Microsoft.VisualBasic. Если вы просто хотите повторно активировать запущенное приложение как обычное окно, когда пользователь пытается перезапустить запущенную программу, второй параметр в SingleInstanceController может быть нулевым. В данном примере окно развернуто.
источник
Обновление 2017-01-25. Попробовав несколько вещей, я решил пойти с VisualBasic.dll, это проще и работает лучше (по крайней мере, для меня). Я позволил свой предыдущий ответ просто как ссылку ...
Так же, как ссылка, это то, как я обошелся без передачи аргументов (что я не могу найти для этого никакой причины ... Я имею в виду одно приложение с аргументами, которые должны передаваться из одного экземпляра в другой). Если требуется сопоставление файлов, то приложение (согласно стандартному ожиданию пользователя) должно быть создано для каждого документа. Если вам нужно передать аргументы существующему приложению, я думаю, я бы использовал vb dll.
Не передавая аргументы (только приложение с одним экземпляром), я предпочитаю не регистрировать новое сообщение Window и не перезаписывать цикл сообщений, как это определено в Matt Davis Solution. Хотя добавить VisualBasic dll не составляет особого труда, но я предпочитаю не добавлять новую ссылку только для создания приложения с одним экземпляром. Кроме того, я предпочитаю создавать новый класс с помощью Main вместо вызова Shutdown из переопределения App.Startup, чтобы обеспечить выход как можно скорее.
В надежде, что это кому-нибудь понравится ... или немного вдохновит :-)
Класс запуска проекта должен быть установлен как «SingleInstanceApp».
WindowHelper:
источник
Не используя Mutex, простой ответ:
Поместите это в
Program.Main()
.Пример :
Вы можете добавить
MessageBox.Show
вif
-statement и поставить «Приложение уже запущено».Это может быть полезно для кого-то.
источник
Подходы на основе именованных мьютексов не являются кроссплатформенными, поскольку именованные мьютексы не являются глобальными в Mono. Подходы, основанные на перечислении процессов, не имеют никакой синхронизации и могут привести к некорректному поведению (например, несколько процессов, запущенных одновременно, могут завершаться самостоятельно в зависимости от времени). Подходы на основе оконной системы нежелательны в консольном приложении. Это решение, основанное на ответе Дивина, решает все эти проблемы:
источник
Я использую Mutex в своем решении для предотвращения нескольких случаев.
источник
Используйте решение мьютекса:
источник
Вот легковесное решение, которое я использую, которое позволяет приложению вывести уже существующее окно на передний план, не прибегая к настраиваемым сообщениям Windows или не просматривая имена процессов вслепую.
Редактировать: Вы также можете хранить и инициализировать мьютекс и статический новый, но вам нужно явно удалить / освободить мьютекс, как только вы закончите с ним. Лично я предпочитаю сохранять мьютекс локальным, так как он будет автоматически удален, даже если приложение закроется, не достигнув конца Main.
источник
Вы также можете использовать CodeFluent Runtime, который является бесплатным набором инструментов. Он предоставляет класс SingleInstance для реализации приложения с одним экземпляром.
источник
Я добавил метод sendMessage в класс NativeMethods.
Очевидно, что метод postmessage не работает, если приложение не отображается на панели задач, однако использование метода sendmessage решает эту проблему.
источник
Вот то же самое, что реализовано через Event.
источник
[Ниже приведен пример кода для консольных и wpf-приложений.]
Вам нужно только проверить значение
createdNew
переменной (пример ниже!) После создания именованного экземпляра Mutex.Логическое значение
createdNew
вернет false:Логическое
createdNew
вернет true:Консольное приложение - Пример:
WPF-Пример:
источник
Экономящее время решение для C # Winforms ...
Program.cs:
источник
Пожалуйста, проверьте предложенное решение здесь которое использует семафор, чтобы определить, работает ли уже существующий экземпляр, работает ли для приложения WPF и может передавать аргументы из второго экземпляра в первый уже запущенный экземпляр, используя TcpListener и TcpClient:
Это работает также для .NET Core, а не только для .NET Framework.
источник
Я не могу найти короткое решение здесь, поэтому я надеюсь, что кому-то понравится это:
ОБНОВЛЕНО 2018-09-20
Вставьте этот код в свой
Program.cs
:источник