Вопрос

У меня есть приложение C# winforms, которому время от времени необходимо запускать внешний exe-файл, но я не хочу запускать другой процесс, если он уже запущен, а лучше переключаюсь на него.

Итак, как бы я сделал это на C# в примере ниже?

using System.Diagnostics;

...

Process foo = new Process();

foo.StartInfo.FileName = @"C:\bar\foo.exe";
foo.StartInfo.Arguments = "Username Password";

bool isRunning = //TODO: Check to see if process foo.exe is already running


if (isRunning)
{
   //TODO: Switch to foo.exe process
}
else
{
   foo.Start(); 
}
Это было полезно?

Решение

Это должно помочь тебе.

Проверка процессов

//Namespaces we need to use
using System.Diagnostics;

public bool IsProcessOpen(string name)
{
    //here we're going to get a list of all running processes on
    //the computer
    foreach (Process clsProcess in Process.GetProcesses()) {
        //now we're going to see if any of the running processes
        //match the currently running processes. Be sure to not
        //add the .exe to the name you provide, i.e: NOTEPAD,
        //not NOTEPAD.EXE or false is always returned even if
        //notepad is running.
        //Remember, if you have the process running more than once, 
        //say IE open 4 times the loop thr way it is now will close all 4,
        //if you want it to just close the first one it finds
        //then add a return; after the Kill
        if (clsProcess.ProcessName.Contains(name))
        {
            //if the process is found to be running then we
            //return a true
            return true;
        }
    }
    //otherwise we return a false
    return false;
}


Другие советы

Вы также можете использовать LINQ,

var processExists = Process.GetProcesses().Any(p => p.ProcessName.Contains("<your process name>"));

Я использовал функцию AppActivate во время выполнения VB, чтобы активировать существующий процесс.Вам придется импортировать dll Microsoft.VisualBasic в проект C#.

using System;
using System.Diagnostics;
using Microsoft.VisualBasic;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            Process[] proc = Process.GetProcessesByName("notepad");
            Interaction.AppActivate(proc[0].MainWindowTitle);
        }
    }
}

Вы можете просто перечислить процессы, используя Process.GetProcesses метод.

Я обнаружил, что Mutex работает не так, как в консольном приложении.Таким образом, использование WMI для запроса процессов, которые можно увидеть в окне диспетчера задач, решит вашу проблему.

Используйте что-то вроде этого:

static bool isStillRunning() {
   string processName = Process.GetCurrentProcess().MainModule.ModuleName;
   ManagementObjectSearcher mos = new ManagementObjectSearcher();
   mos.Query.QueryString = @"SELECT * FROM Win32_Process WHERE Name = '" + processName + @"'";
   if (mos.Get().Count > 1)
   {
        return true;
    }
    else
        return false;
}

ПРИМЕЧАНИЕ:Добавьте ссылку на сборку «System.Management», чтобы включить тип intellisense.

Я думаю, что полный ответ на вашу проблему требует понимания того, что происходит, когда ваше приложение определяет, что экземпляр foo.exe уже запущен, то есть что делает '//TODO:Переключиться на процесс foo.exe» на самом деле означает?

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

Я просто пытался предотвратить запуск второго экземпляра из-за зависимости от конкретных аппаратных интерфейсов.В зависимости от того, что вам нужно в этой строке «переключиться на», вам может потребоваться более конкретное решение, например идентификатор или дескриптор процесса.

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

Две проблемы, о которых следует помнить:

  1. Ваш пример включал в себя размещение пароля в командную строку.Это ясное представление секрета может быть уязвимостью безопасности.

  2. При перечислении процессов спросите себя, какие процессы вы действительно хотите перечислить.Все пользователи или только текущий пользователь?Что, если текущий пользователь вошел дважды (два рабочего стола)?

Мнебуэрко писал:

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

У меня нет доступа к исходному коду процесса, который я хочу запустить.

В итоге я использовал процесс MainWindowHandle для переключения на процесс, как только обнаружил, что он уже запущен:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 public static extern bool SetForegroundWindow(IntPtr hWnd);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top