Как реализовать один экземпляр для машинного приложения? - PullRequest
10 голосов
/ 19 ноября 2010

Я должен ограничить свое приложение .net 4 WPF, чтобы оно могло запускаться только один раз для каждой машины. Обратите внимание, что я сказал для каждой машины, а не для каждой сессии.
До сих пор я реализовывал приложения с одним экземпляром, используя простой мьютекс, но, к сожалению, такой мьютекс за сеанс.

Есть ли способ создать мьютекс всей машины или есть какое-то другое решение для реализации одного экземпляра для одного машинного приложения?

Ответы [ 7 ]

14 голосов
/ 19 ноября 2010

Я бы сделал это с глобальным объектом Mutex, который должен храниться в течение всего срока службы вашего приложения.

MutexSecurity oMutexSecurity;

//Set the security object
oMutexSecurity = new MutexSecurity();
oMutexSecurity.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), MutexRights.FullControl, AccessControlType.Allow));

//Create the global mutex and set its security
moGlobalMutex = new Mutex(True, "Global\\{5076d41c-a40a-4f4d-9eed-bf274a5bedcb}", bFirstInstance);
moGlobalMutex.SetAccessControl(oMutexSecurity);

Где возвращается bFirstInstance, если это первый экземпляр вашего приложения, работающий глобально.Если вы пропустили глобальную часть мьютекса или заменили ее локальной, тогда мьютекс будет только для сеанса (это, вероятно, то, как работает ваш текущий код).

Я полагаю, что сначала я получил эту технику от Jon Skeet .

В разделе MSDN об объекте Mutex объясняются две области действия объекта Mutex и подчеркивается, почему это важно при использовании служб терминаловпоследнее примечание).

3 голосов
/ 19 ноября 2010

Думаю, вам нужно использовать системный семпахор для отслеживания экземпляров вашего приложения.

Если вы создаете объект семафора с помощью конструктора, который принимает имя, онсвязан с семафором операционной системы с таким именем.

Именованные системные семафоры видны во всей операционной системе и могут использоваться для синхронизации действий процессов.

РЕДАКТИРОВАТЬ: обратите внимание, что я не знаю, работает ли этот подход в нескольких сеансах Windows намашина.Я думаю, что это должно быть как конструкция уровня ОС, но я не могу сказать наверняка, поскольку я не проверял это таким образом.

РЕДАКТИРОВАТЬ 2: Я не знал этого, но после прочтения ответа Stevo2000, я сделал некоторые взглядыхорошо, и я думаю, что префикс «Global \», чтобы сделать объект применимым к глобальному пространству имен, применим также и к семафорам, и семафор, если он создан таким образом, должен работать.

2 голосов
/ 19 ноября 2010

Вы можете открыть файл с эксклюзивными правами где-нибудь в% PROGRAMDATA% Второй экземпляр, который запускается, попытается открыть тот же файл и потерпит неудачу, если он уже открыт.

1 голос
/ 19 ноября 2010

Как насчет использования реестра?

  1. Вы можете создать registry entry under HKEY_LOCAL_MACHINE.
  2. Пусть значением будет flag, если приложение запущено или нет.
  3. Encrypt the key с использованием некоторыхстандартный метод symmetric key encryption, чтобы никто не мог изменить значение.
  4. On application start-up check for the key и прервать \ продолжить соответственно.
  5. Не забудьте obfuscate your assembly, который выполняет эту часть шифрования \ дешифрования, чтобы никто не мог взломать ключ в реестре, посмотрев накод в отражателе.
0 голосов
/ 19 ноября 2010

Ради полноты я хотел бы добавить следующее, что я только что нашел:
Этот веб-сайт имеет интересный подход к отправке сообщений Win32 другим процессам.Это решило бы проблему переименования сборки пользователем, чтобы обойти тест, и других сборок с тем же именем.
Они используют сообщение для активации главного окна другого процесса, но кажется, что сообщение моглобыть фиктивным сообщением, используемым только для того, чтобы узнать, отвечает ли на него другой процесс, чтобы узнать, является ли он нашим процессом.

0 голосов
/ 19 ноября 2010

Ниже приведен полный пример того, как выполняется одно приложение instace в WPF 3.5

.
public class SingleInstanceApplicationWrapper :
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
{
public SingleInstanceApplicationWrapper()
{
// Enable single-instance mode.
this.IsSingleInstance = true;
}
// Create the WPF application class.
private WpfApp app;
protected override bool OnStartup(
Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
{
app = new WpfApp();
app.Run();
return false;
}
// Direct multiple instances.
protected override void OnStartupNextInstance(
Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e)
{
if (e.CommandLine.Count > 0)
{
app.ShowDocument(e.CommandLine[0]);
}
}
}

Вторая часть:

public class WpfApp : System.Windows.Application
{
protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);
WpfApp.current = this;
// Load the main window.
DocumentList list = new DocumentList();
this.MainWindow = list;
list.Show();
// Load the document that was specified as an argument.
if (e.Args.Length > 0) ShowDocument(e.Args[0]);
}
public void ShowDocument(string filename)
{
try
{
Document doc = new Document();
doc.LoadFile(filename);
doc.Owner = this.MainWindow;
doc.Show();
// If the application is already loaded, it may not be visible.
// This attempts to give focus to the new window.
doc.Activate();
}
catch
{
MessageBox.Show("Could not load document.");
}
}
}

Третья часть:

 public class Startup
    {
    [STAThread]
    public static void Main(string[] args)
    {
    SingleInstanceApplicationWrapper wrapper =
    new SingleInstanceApplicationWrapper();
    wrapper.Run(args);
    }
    }

Возможно, вам понадобится добавить ссылки на soem и добавить несколько операторов using, но это должно сработать.

Вы также можете загрузить пример полного решения VS, загрузив исходный код книги с здесь .

Взято из книги «Pro WPF in C # 3 2008, Апресс, Мэтью Макдональд», купите книгу за золото. Я сделал.

0 голосов
/ 19 ноября 2010

Я однажды сделал нечто подобное.

При запуске списка приложений я проверял все запущенные процессы на наличие процесса с одинаковым именем, и если бы он существовал, я бы не позволил запустить программу.

Конечно, это не пуленепробиваемый, так как если другое приложение имеет точно такое же имя процесса, ваше приложение никогда не запустится, но если вы используете неуниверсальное имя, оно, вероятно, будет более чем достаточно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...