Как я могу узнать, запущен ли процесс?

155

Когда я получаю ссылку на a System.Diagnostics.Process, как я могу узнать, запущен ли в данный момент процесс?

reshefm
источник

Ответы:

252

Это способ сделать это с именем:

Process[] pname = Process.GetProcessesByName("notepad");
if (pname.Length == 0)
  MessageBox.Show("nothing");
else
  MessageBox.Show("run");

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

Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
   Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}
Патрик Дежарден
источник
Это именно то, что я искал. Несмотря на то, что это очень старый пост, не могли бы вы объяснить мне, как это правильно C #. Я не сомневаюсь в этом, я вижу, что это работает, но я никогда не видел, если бы без {}.
MatthewD
4
@MatthewD: if/elseоператоры C # длиной всего одну строку не обязательно должны иметь фигурные скобки для обозначения оператора блока. Это касается foreachи forзаявлений. Это сводится к стилю кодирования.
Hallmanac
Я также провел некоторое исследование по этому вопросу, нашел эту информацию, но я не видел эту forинформацию. Годы c # .net dev и я никогда не видели этот стиль. Как говорится, «каждый день узнаешь что-то новое». Спасибо за сообщение и ответ ..
MatthewD
3
@ MatthewD да, на самом деле это касается большинства языков (например, Java). Как правило, рекомендуется избегать однострочных символов, подобных этим, и всегда ставить фигурные скобки, поскольку всегда есть вероятность, что в будущем вам, возможно, придется добавить больше утверждений, и в этом случае скобки уже будут там, когда они вам понадобятся. Но для таких вещей, если вы на 100% уверены, что вам нужен только один оператор, это нормально делать и синтаксически правильно.
Дэвид Мордигал
1
Если вы не можете найти процесс, попробуйте удалить расширение. (Пример: .exe)
DxTx
28

Это самый простой способ, который я нашел после использования отражателя. Я создал метод расширения для этого:

public static class ProcessExtensions
{
    public static bool IsRunning(this Process process)
    {
        if (process == null) 
            throw new ArgumentNullException("process");

        try
        {
            Process.GetProcessById(process.Id);
        }
        catch (ArgumentException)
        {
            return false;
        }
        return true;
    }
}

Process.GetProcessById(processId)Метод вызывает ProcessManager.IsProcessRunning(processId)метод и броски ArgumentExceptionв случае , если процесс не существует. По какой-то причине ProcessManagerкласс является внутренним ...

reshefm
источник
Это был действительно хороший ответ; однако через аргумент null исключение не должно быть (поскольку исключение нулевой ссылки все равно было бы сгенерировано, и вы ничего не сделали с этим исключением. Кроме того, вы получите InvalidOperationException, если вы не вызывали Start () метод или вы вызвали метод close (). Я отправил другой ответ, чтобы объяснить эти две ситуации.
Aelphaeis
16

Синхронное решение:

void DisplayProcessStatus(Process process)
{
    process.Refresh();  // Important


    if(process.HasExited)
    {
        Console.WriteLine("Exited.");
    }
    else
    {
        Console.WriteLine("Running.");
    } 
}

Асинхронное решение:

void RegisterProcessExit(Process process)
{
    // NOTE there will be a race condition with the caller here
    //   how to fix it is left as an exercise
    process.Exited += process_Exited;
}

static void process_Exited(object sender, EventArgs e)
{
   Console.WriteLine("Process has exited.");
}
Coincoin
источник
6
Для первого варианта: как я могу узнать, был ли процесс запущен в первую очередь?
reshefm
8

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

Вот измененная версия того, что он написал.

    public static bool IsRunning(this Process process)
    {
        try  {Process.GetProcessById(process.Id);}
        catch (InvalidOperationException) { return false; }
        catch (ArgumentException){return false;}
        return true;
    }

Я удалил его ArgumentNullException, потому что он фактически подразумевает исключение нулевой ссылки, и оно все равно вызывается системой, и я также учел ситуацию, в которой процесс никогда не начинался, или метод close () использовался для закрытия обработать.

Aelphaeis
источник
Лично я предпочел бы видеть ArgumentNullException при просмотре зарегистрированного исключения, а не NullReferenceException, так как ArgumentNullException гораздо более четко описывает, что пошло не так.
Шон,
1
@Sean Я бы с тобой согласился, но это метод расширения. Я думаю, что более уместно выдавать исключение нулевого указателя с учетом синтаксиса, оно просто более соответствует вызову методов нулевых объектов.
Эльфай
Это будет вызывать обработчик события FirstHandledException каждый раз. Способ спамить ваши логи там, приятель.
Латентность
6

Это должно быть однострочно:

public static class ProcessHelpers {
    public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}
guneysus
источник
3

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

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

Второй элемент - это дескриптор процесса. У него та же проблема, что и у идентификатора, и работать с ним более неудобно.

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

JaredPar
источник
1

Process.GetProcesses()это путь Но вам может потребоваться использовать один или несколько различных критериев для поиска вашего процесса, в зависимости от того, как он выполняется (например, в качестве службы или обычного приложения, независимо от того, есть ли у него заголовок).

Джефф Котула
источник
Если вы поместите этот метод в цикл, он будет стоить много циклов ЦП. Я рекомендую использовать GetProcessByName () или GetProcessByID ().
Хао Нгуен
0

Возможно (возможно) я читаю вопрос неправильно, но вы ищете свойство HasExited, которое сообщит вам, что процесс, представленный вашим объектом Process, завершился (нормально или нет).

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

Вы также можете установить EnableRaisingEvents и обработать событие Exited (которое отправляется асинхронно) или вызвать WaitForExit (), если хотите заблокировать.


источник
0

Вы можете создать экземпляр экземпляра Process один раз для нужного процесса и продолжать отслеживать процесс, используя этот объект .NET Process (он будет продолжать отслеживание, пока вы явно не вызовете Close для этого объекта .NET, даже если отслеживаемый процесс умер [это должно быть в состоянии дать вам время завершения процесса, иначе ExitTime и т. д.])

Цитирование http://msdn.microsoft.com/en-us/library/fb4aw7b8.aspx :

Когда связанный процесс завершается (то есть, когда он закрывается операционной системой из-за нормального или ненормального завершения), система сохраняет административную информацию о процессе и возвращается к компоненту, который вызвал WaitForExit. Компонент Process может затем получить доступ к информации, включая ExitTime, используя дескриптор завершенного процесса.

Поскольку связанный процесс завершен, свойство Handle компонента больше не указывает на существующий ресурс процесса. Вместо этого дескриптор можно использовать только для доступа к информации операционной системы о ресурсе процесса. Система знает о дескрипторах завершенных процессов, которые не были освобождены компонентами Process, поэтому она хранит информацию ExitTime и Handle в памяти до тех пор, пока компонент Process не освободит ресурсы. По этой причине каждый раз, когда вы вызываете Start для экземпляра Process, вызывайте Close, когда связанный процесс завершен, и вам больше не нужна никакая административная информация о нем. Close освобождает память, выделенную для завершенного процесса.

Джордж Бирбилис
источник
0

Я попробовал решение Coincoin:
перед обработкой какого-либо файла я копирую его как временный файл и открываю.
Когда я закончу, я закрываю приложение, если оно все еще открыто, и удаляю временный файл:
я просто использую переменную Process и проверяю ее потом:

private Process openApplication;  
private void btnOpenFile_Click(object sender, EventArgs e) {  
    ...
    // copy current file to fileCache  
    ...  
    // open fileCache with proper application
    openApplication = System.Diagnostics.Process.Start( fileCache );  
}

Позже я закрываю приложение:

 ...   
openApplication.Refresh(); 

// close application if it is still open       
if ( !openApplication.HasExited() ) {
    openApplication.Kill();  
}

// delete temporary file  
System.IO.File.Delete( fileCache );

Работает (пока)

Джек Гриффин
источник
3
В openApplication.HasExited()HasExited это не функция. Правильный путь был бы openApplication.HasExited.
caiosm1005
0

Несмотря на поддерживаемый API из .Net каркасов в отношении проверки существующего процесса по идентификатору процесса, эти функции работают очень медленно. Для запуска Process.GetProcesses () или Process.GetProcessById / Name () требуется огромное количество циклов ЦП.

Гораздо более быстрый способ проверки запущенного процесса по идентификатору - использовать нативный API OpenProcess () . Если возвращаемый дескриптор равен 0, процесс не существует. Если дескриптор отличается от 0, процесс выполняется. Нет никакой гарантии, что этот метод будет работать на все 100% из-за разрешения.

Хао Нгуен
источник
0

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

  • Любые члены экземпляра не гарантированно являются потокобезопасными. Это означает, что существуют условия гонки, которые могут возникать в течение срока действия снимка при попытке оценить свойства объекта.
  • Дескриптор процесса выбрасывает Win32Exception для ACCESS DENIED, где разрешения для оценки этого и других подобных свойств не разрешены.
  • Для статуса ISN'T RUNNING, ArgumentException также будет вызываться при попытке оценить некоторые из его свойств.

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

var x = obj.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);

Вы можете закрепить код Win32 для Snapshot или использовать WMI, который работает медленнее.

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);

Другой вариант - OpenProcess / CloseProcess, но вы все равно столкнетесь с теми же проблемами, за исключением тех же исключений, что и раньше.

Для WMI - OnNewEvent.Properties ["?"]:

  • "ParentProcessID"
  • "ProcessId"
  • "Имя процесса"
  • "SECURITY_DESCRIPTOR"
  • "Идентификатор сессии"
  • "Sid"
  • "Time_created"
Задержка
источник
0
string process = "notepad";
if (Process.GetProcessesByName(process).Length == 0)
{
    MessageBox.Show("Working");
}
else
{
    MessageBox.Show("Not Working");
}

Также вы можете использовать таймер для проверки процесса каждый раз

Беркай
источник
3
Не будет ли наоборот? если длина == 0, значит не работает?
Джей Джейкобс
Ответ такой же, как и у Патрика Дежардинса: stackoverflow.com/a/262291/7713750
Рекшино,
Другой путь длины> 0 означает, что процессы найдены.
HaseeB Мир
Это может иметь ошибку, ( length == 0должна отображаться Not Working), но все еще выполняет свою работу.
Моморо