Як я можу знати, чи працює процес?


155

Коли я отримую посилання на a System.Diagnostics.Process, як я можу дізнатися, чи працює процес на даний момент?

Відповіді:


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: C # if/elseзаяви, які мають довжину лише один рядок, не повинні мати фігурні дужки для позначення оператора блоку. Це стосується 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клас внутрішній ...


Це була справді гарна відповідь; однак, ви не повинні мати аргумент 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.");
}

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, тому що він насправді повинен бути виключенням з нульовим посиланням, і його все одно викидає система, і я також пояснив ситуацію, в якій процес ніколи не починався, або метод закриття () використовувався для закриття процес.


Особисто я б швидше бачив ArgumentNullException при перегляді виключеного в журнал, ніж NullReferenceException, оскільки ArgumentNullException набагато чіткіше про те, що пішло не так.
Шон

1
@Sean Я зазвичай погоджуюся з вами, але це метод розширення. Я думаю, що більш доцільно викинути виключення з нульовим вказівником з огляду на синтаксис, воно просто більше відповідає методам виклику нульових об'єктів.
Aelphaeis

Це щоразу запускатиме обробник подій FirstHandledException. Спосіб спаму ваших журналів там приятель.
Затримка

6

Це має бути однолінійний:

public static class ProcessHelpers {
    public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}

3

Це залежить від того, наскільки надійною ви бажаєте бути такою функцією. Якщо ви хочете дізнатися, чи наявний у вас певний примірник процесу все ще працює і доступний із 100% точністю, то вам не пощастить. Причина полягає в тому, що від об'єкта керованого процесу існує лише два способи ідентифікації процесу.

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

Другий пункт - Ручка процесу. Він має таку ж проблему, що і Id, і з цим незручніше працювати.

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


1

Process.GetProcesses()це шлях. Але вам може знадобитися використовувати один або декілька різних критеріїв, щоб знайти свій процес, залежно від того, як він працює (наприклад, як служба чи звичайний додаток, незалежно від того, має він чи ні).


Якщо ви помістите цей метод у цикл, це коштує чимало циклів процесора. Я рекомендую використовувати GetProcessByName () або GetProcessByID ().
Хао Нгуен

0

Можливо (напевно) я неправильно читаю питання, але ви шукаєте властивість HasExited, яка скаже вам, що процес, представлений вашим об'єктом Process, вийшов (нормально чи ні).

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

Ви також можете встановити EnableRaisingEvents та обробити подію Exited (яке надсилається асинхронно) або зателефонувати WaitForExit (), якщо ви хочете заблокувати.


0

Ви можете інстанціювати екземпляр Process один раз для потрібного процесу та продовжувати відстежувати процес за допомогою цього об’єкта .NET Process (він буде тримати відстеження, поки ви не викликаєте явно Закрити цей об’єкт .NET, навіть якщо процес, який він відстежував, загинув. [це для того, щоб дати вам час завершення процесу, він же ExitTime тощо])

Цитуючи http://msdn.microsoft.com/en-us/library/fb4aw7b8.aspx :

Коли пов'язаний процес закінчується (тобто коли він закривається операційною системою через нормальне або аномальне припинення), система зберігає адміністративну інформацію про процес і повертається до компонента, який назвав WaitForExit. Потім компонент Process може отримати доступ до інформації, яка включає в себе ExitTime, використовуючи ручку до завершеного процесу.

Оскільки пов'язаний процес закінчився, властивість Handle компонента більше не вказує на існуючий ресурс процесу. Натомість ручку можна використовувати лише для доступу до інформації операційної системи про ресурс процесу. Система обізнана з ручками для завершених процесів, які не були випущені компонентами Process, тому вона зберігає інформацію про ExitTime і Handle в пам'яті, поки компонент Process спеціально не звільнить ресурси. З цієї причини, кожного разу, коли ви зателефонуєте запустити екземпляр процесу, зателефонуйте Закрити, коли пов'язаний процес припиниться, і вам більше не потрібна адміністративна інформація про нього. Закриття звільняє пам'ять, що виділяється на процес, що вийшов.


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
At openApplication.HasExited(), HasExited - це не функція. Правильний шлях був би openApplication.HasExited.
caiosm1005

0

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

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


0

З цим пов'язано багато проблем, оскільки, здається, інші частково вирішують:

  • Будь-які члени екземплярів не гарантують безпеку потоку. Тобто існують умови перегонів, які можуть виникати протягом життя знімка, намагаючись оцінити властивості об'єкта.
  • Обробник процесу передасть програму Win32Exception для ДОСТУПНОГО ЗАБЕЗПЕЧЕННЯ, коли дозволи для оцінки цього та інших таких властивостей не дозволені.
  • Для статусу ISN'T RUNNING також буде піднято ArgumentException при спробі оцінити деякі його властивості.

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

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

Ви можете підключити код Win32 для знімка або використовувати WMI, який повільніше.

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);

Іншим варіантом буде OpenProcess / CloseProcess, але ви все одно будете стикатися з тими ж проблемами, за винятками, які викидаються так само, як і раніше.

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

  • "ParentProcessID"
  • "ProcessID"
  • "ProcessName"
  • "SECURITY_DESCRIPTOR"
  • "SessionID"
  • "Сід"
  • "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
Rekshino

Інший шлях до довжини> 0 означає процеси.
HaseeB Mir

У цьому може виникнути помилка ( length == 0повинна відображатися Not Working), але все-таки виконується робота.
Моморо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.