2012-01-17 3 views
16

Этот код работает, как ожидалось, на большом количестве машин. Однако на одной конкретной машине вызов WaitForExit(), по-видимому, игнорируется и фактически отмечает процесс как завершенный.Process.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(); 
} 

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

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

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

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

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

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

Возможно ли, что раньше открывался еще один Блокнот? Итак, вы создаете один, убиваете одного, но видите старый блокнот? 'proc.WaitForExit()' может немедленно возвращаться, если процесс не может быть создан или был немедленно разорван по некоторым причинам, например, отсутствие привилегий исходного кода для создания новых процессов. – oleksii

+0

@oleskii, нет, я убедился в этом. Блокнот используется здесь только как процесс, «который все знают», эта проблема возникает независимо от того, какой файл используется для этого процесса. – Rotem

+0

@oleskii "proc.WaitForExit() может немедленно вернуться, если процесс не может быть создан или был расторгнут сразу по каким-либо причинам" - не будет ли процесс фактически прекращен в этом случае? – Rotem

ответ

7

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

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

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

EDIT: После небольшого копания:

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

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

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

+0

Спасибо! Хотя ваше решение решает мою проблему, я бы с удовольствием нашел причину, по которой она только показала, что она воздействует только на одну машину из группы около 50. – Rotem

+0

Я надеюсь, что @EricLippert попадет сюда и пометит «Почему это происходит " часть. Я не настолько острый. –

+2

У меня нет ни малейшего представления. Я эксперт по разработке и внедрению языка C# и его компилятора. Я практически ничего не знаю о том, как Windows управляет процессами. –

1

Причиной может быть вирус, который заменил 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); 
Смежные вопросы