Уничтожьте дерево процессов программно на C#

StackOverflow https://stackoverflow.com/questions/5901679

  •  29-10-2019
  •  | 
  •  

Вопрос

Я запускаю Internet Explorer программно с кодом, который выглядит следующим образом:

ProcessStartInfo startInfo = new ProcessStartInfo("iexplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "http://www.google.com";
Process ieProcess = Process.Start(startInfo);

Это генерирует 2 процесса, видимых в диспетчере задач Windows.Затем я пытаюсь остановить процесс с помощью:

ieProcess.Kill();

Это приводит к тому, что один из процессов в диспетчере задач завершается, а другой остается.Я попытался проверить наличие каких-либо свойств, у которых были бы дочерние процессы, но не нашел ни одного.Как я могу также убить другой процесс?В более общем плане, как вы завершаете все процессы, связанные с процессом, который вы запускаете с помощью Process.Запустить?

Это было полезно?

Решение

У меня это сработало очень хорошо:

родовое слово

Обновление 26.04.2016

Протестировано на Visual Studio 2015 Update 2 на Win7 x64.По-прежнему работает так же хорошо, как и 3 года назад.

Обновление от 14 ноября 2017 г.

Добавлена проверка на наличие кода простоя системы, генерирующего код тега

Обновление 2018-03-02

Необходимо добавить ссылку на пространство имен if (pid == 0), см. комментарий от @MinimalTech ниже.Если у вас установлен ReSharper, он предложит сделать это за вас автоматически.

Обновление 2018-10-10

Наиболее распространенный вариант использования - уничтожение дочерних процессов, запущенных нашим собственным процессом C #.

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

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

Я не поклонник ни одного из представленных здесь решений.

Вот что я придумал:

родовое слово

Как использовать:

родовое слово

Если кому-то нужно решение ядра dotnet, dotnet cli предложил реализацию, основанную на taskill , как упомянуто выше, и рекурсивном pgrep / kill .для систем на базе unix. Можно найти полную реализациюна github .К сожалению, это внутренний класс, поэтому вам придется скопировать его в свою базу кода.

Список дочерних процессов (должно выполняться рекурсивно):

родовое слово

Завершить процесс:

родовое слово

Вы должны вызвать Process.CloseMainWindow(), который отправит сообщение в главное окно процесса.Думайте об этом как о том, что пользователь нажимает кнопку закрытия «X» или Файл | Выход из пункта меню.

Безопаснее послать в Internet Explorer сообщение о закрытии, чем пойти и убить все его процессы.Эти процессы могут делать что угодно, и вам нужно позволить IE сделать свое дело и завершить его, прежде чем просто убить его в середине выполнения чего-то, что может быть важно для будущих запусков.Это верно для любой программы, которую вы убиваете.

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

родовое слово

Другое решение - использовать команду taskill.Я использую в своих приложениях следующий код:

родовое слово

Вы используете IE8 или IE9?Из-за новой многопроцессорной архитектуры это, безусловно, запустило бы несколько процессов.В любом случае, взгляните на этот другойответ за получение дерева процессов и его уничтожение.

Другой подход, который может быть очень полезным, - это использование Windows API для объектов заданий . Объекту задания можно назначить процесс. Дочерние процессы такого процесса автоматически назначаются одному и тому же объекту задания.

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

<цитата>

Завершает все процессы, связанные в данный момент с заданием.

Пример C # в этом ответе ( на основе этого ответа ) использует флаг JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE , который:

<цитата>

Вызывает завершение всех процессов, связанных с заданием, при закрытии последнего дескриптора задания.

Как правильно закрыть Internet Explorer при запуске из PowerShell?

Некоторые из тех, кто прокомментировал в приведенной выше теме, что это вызвано ошибкой в Win7 (поскольку, похоже, это не встречается у пользователей, использующих другие версии Windows).Многие страницы в Интернете, включая страницу Microsoft, заявляют об ошибке пользователя и советуют вам просто использовать доступный метод quit для объекта IE, который также должен закрывать все дочерние процессы (и, как сообщается, делает это в Win8 / XP и т.д.)

Я должен признать, со своей стороны, что это БЫЛА ошибка пользователя.Я нахожусь в win7, и причина, по которой метод quit у меня не работал, заключалась в ошибке в кодировании.А именно, я создавал объект IE при объявлении, а затем создавал другой (прикрепленный к тому же объекту) позже в коде...Я почти закончил взламывать процедуру убийства родителей и детей, чтобы она работала на меня, когда осознал проблему.

Из-за того, как функционирует IE, ProcessId, который вы создали в качестве родительского, может быть привязан к другим окнам / подпроцессам, которые вы НЕ создавали.Используйте quit и имейте в виду, что в зависимости от пользовательских настроек (например, пустой кэш при выходе) процессам может потребоваться несколько минут, чтобы завершить свои задачи и закрыться.

В .NET Core 3.0 для этого есть метод, а именно новая перегрузка уже существующего метода Process.Kill().IOW, выполнение process.Kill(true) для переменной process типа Process уничтожает процесс со всеми его потомками.Это, естественно, кроссплатформенный.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top