Process.WaitForExit несовместим на разных машинах - PullRequest
15 голосов
/ 17 января 2012

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

static void Main(string[] args)
{
    Process proc = Process.Start("notepad.exe");
    Console.WriteLine(proc.HasExited); //Always False
    proc.WaitForExit(); //Blocks on all but one machines
    Console.WriteLine(proc.HasExited); //**See comment below
    Console.ReadLine();
}

Обратите внимание, что в отличие от аналогичного вопроса по SO, вызываемый процесс называется notepad.exe (по соображениям тестирования), поэтому маловероятно, что ошибка связана с ним - то есть он не порождает вторую подпрограмму -обработка и закрытие. Тем не менее, это не объясняет, почему это работает на всех других машинах.

На проблемном компьютере второй вызов Console.WriteLine(proc.HasExited)) возвращает true, хотя блокнот все еще четко открыт как на экране, так и в диспетчере задач.

Машина работает под управлением Windows 7 и .NET 4.0.

Мой вопрос; какие условия на этой конкретной машине могут быть причиной этого? Что я должен проверять?

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

  • Переустановил .NET.
  • Закрыты все процессы, которые я не знаю в диспетчере задач.
  • Windows еще не была активирована на этом компьютере.
  • Следуя советам в комментариях, я попытался получить «существующий» идентификатор процесса, используя GetProcessesByName, но он просто возвращает пустой массив на проблемной машине. Поэтому трудно сказать, что проблема даже в WaitForExit, так как процесс не возвращается при вызове GetProcessesByName даже до вызова WaitForExit.
  • На проблемном компьютере ParentID полученного процесса блокнота представляет собой идентификатор процесса блокнота, который код запускает вручную, или, другими словами, блокнот порождает дочерний процесс и завершает сам себя.

Ответы [ 2 ]

7 голосов
/ 17 января 2012

Проблема в том, что по умолчанию для Process.StartInfo.UseShellExecute установлено значение true. Если для этой переменной задано значение true, а не запускать процесс самостоятельно, вы просите оболочку запустить его для вас. Это может быть очень полезно - это позволяет вам выполнять такие вещи, как «выполнение» HTML-файла (оболочка будет использовать соответствующее приложение по умолчанию).

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

Внутренние детали того, почему это происходит, вероятно, выходят за рамки моих возможностей ответить. Я знаю, что когда UseShellExecute == true, платформа использует Windows API ShellExecuteEx, а когда UseShellExecute == false, она использует CreateProcessWithLogonW, но почему один ведет к отслеживаемым процессам, а другой - не знаю, так как они оба возвращают идентификатор процесса.

РЕДАКТИРОВАТЬ: после небольшого копания:

Этот вопрос указал мне на флаг SEE_MASK_NOCLOSEPROCESS , который действительно, кажется, устанавливается при использовании ShellExecute. В документации по значению маски указано:

В некоторых случаях, например, когда выполнение выполняется через DDE разговор, никакая ручка не будет возвращена. Приложение вызова отвечает за закрытие ручки, когда она больше не нужна.

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

1 голос
/ 17 января 2012

Причиной может быть вирус, который заменил notepad.exe, чтобы скрыть себя. Если выполнено, он порождает блокнот и выходит (только предположение).

попробуйте этот код:

        var process = Process.Start("notepad.exe");
        var process2 = Process.GetProcessById(process.Id);
        while (!process2.HasExited)
        {
            Thread.Sleep(1000);
            try
            {
                process2 = Process.GetProcessById(process.Id);
            }
            catch (ArgumentException)
            {

                break;
            }

        }

        MessageBox.Show("done");

После Process.Start () проверьте идентификатор процесса notepad.exe с помощью диспетчера задач и убедитесь, что он совпадает с process.Id;

Да, и вы действительно должны использовать полный путь к notepad.exe

 var notepad = Path.Combine(Environment.GetFolderPath(
                   Environment.SpecialFolder.Windows), "notepad.exe");
 Process.Start(notepad);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...