Как я могу проверить запущенный процесс для каждой пользовательской сессии?

У меня есть приложение.NET, которое я позволяю запускать только одному процессу за раз, однако это приложение время от времени используется на коробках Citrix и, следовательно, может запускаться несколькими пользователями на одном компьютере.

Я хочу проверить и убедиться, что приложение выполняется только один раз за пользовательский сеанс, потому что сейчас, если пользователь A запускает приложение, пользователь B получает сообщение "Приложение уже используется", и не должен.

Это то, что я сейчас проверяю для запуска процесса:

Process[] p = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName);
            if (p.Length > 1)
            {
#if !DEBUG
                allowedToOpen &= false;
                errorMessage +=
                    string.Format("{0} is already running.{1}", Constants.AssemblyTitle, Environment.NewLine);
#endif
            }

4 ответа

Решение

РЕДАКТИРОВАТЬ: Улучшен ответ в соответствии с этим непрерывным вопросом...

Вы можете использовать мьютекс для проверки, запущено ли уже приложение:

using( var mutex = new Mutex( false, AppGuid ) )
{
    try
    {
        try
        {
            if( !mutex.WaitOne( 0, false ) )
            {
                MessageBox.Show( "Another instance is already running." );
                return;
            }
        }
        catch( AbandonedMutexException )
        {
            // Log the fact the mutex was abandoned in another process,
            // it will still get aquired
        }

        Application.Run(new Form1());
    }
    finally
    {
        mutex.ReleaseMutex();
    }
}

Важным является AppGuid - вы можете сделать это зависит от пользователя.

Может быть, вам нравится читать эту статью: неправильно понятый мьютекс

Как уже сказал танаскиус, вы можете использовать Mutex.

На сервере, на котором запущены службы терминалов, именованный системный мьютекс может иметь два уровня видимости. Если его имя начинается с префикса "Global\", мьютекс виден во всех сеансах терминального сервера. Если его имя начинается с префикса "Local\", мьютекс виден только в сеансе сервера терминалов, где он был создан.

Источник: MSDN, Mutex Class

Просто констатирую очевидное - хотя Mutex Обычно считается лучшим решением, вы можете решить проблему с одним экземпляром на сеанс без Mutex - просто проверить SessionId также.

    private static bool ApplicationIsAlreadyRunning()
    {
        var currentProcess = Process.GetCurrentProcess();
        var processes = Process.GetProcessesByName(currentProcess.ProcessName);

        // test if there's another process running in current session.
        var intTotalRunningInCurrentSession = processes.Count(prc => prc.SessionId == currentProcess.SessionId);

        return intTotalRunningInCurrentSession > 1;
    }

Источник (без Linq)

Если Form1 запускает не фоновые потоки, и эта Form1 завершается, у вас есть проблема: мьютекс освобождается, но процесс все еще там. Что-то в этом роде лучше ИМХО:

static class Program {
    private static Mutex mutex;



    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main() {
        bool createdNew = true;
        mutex = new Mutex(true, @"Global\Test", out createdNew);
        if (createdNew) {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());        
        }
        else {
            MessageBox.Show(
                "Application is already running",
                "Error",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error
            );
        }
    }
}

Мьютекс не будет освобожден, пока основной домен приложения все еще работает. И это будет происходить до тех пор, пока приложение работает.

Другие вопросы по тегам