2012-01-17 11 views
16

Ten kod działa zgodnie z oczekiwaniami na dużej liczbie komputerów. Jednak na jednej konkretnej maszynie wywołanie WaitForExit() wydaje się być ignorowane, a w rzeczywistości oznacza proces jako zakończony.Process.WaitForExit niespójne na różnych komputerach

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(); 
} 

Należy zauważyć, że w przeciwieństwie do similar question WŁĄCZONYM tak, proces nazywany jest notepad.exe (z powodów testowych), tak że jest mało prawdopodobne, że usterka znajduje się z nim - to znaczy nie jest tarło drugi podproces i zamykanie. Mimo to nie wyjaśniałoby, dlaczego działa na wszystkich innych maszynach.

Na komputerze problemowym drugie wywołanie Console.WriteLine(proc.HasExited)) zwraca true, mimo że notatnik nadal jest wyraźnie otwarty, zarówno na ekranie, jak i w menedżerze zadań.

Urządzenie pracuje w systemie Windows 7 i .NET 4.0.

Moje pytanie brzmi; jakie warunki na tej konkretnej maszynie mogą być przyczyną tego? Co powinienem sprawdzić?

Edit - Czego próbowałem tak daleko/poprawki/prawdopodobnie istotnych informacji:

  • ponownej instalacji .NET.
  • Zamknął wszelkie procesy, których nie znam w menedżerze zadań.
  • System Windows nie został jeszcze aktywowany na tym komputerze.
  • Po otrzymaniu porady w komentarzach, próbowałem uzyskać "istniejący" identyfikator procesu za pomocą GetProcessesByName, ale to po prostu zwraca pustą tablicę na maszynie problemu. Dlatego trudno jest powiedzieć, że problem jest nawet z WaitForExit, ponieważ proces nie jest zwracany przez wywołanie GetProcessesByName nawet przed wywołaniem WaitForExit.
  • Na problematycznym komputerze wynikowy identyfikator procesu notatnika jest identyfikatorem procesu notatnika, który ręcznie uruchamia kod, lub innymi słowy, notatnik tworzy proces potomny i kończy działanie.
+1

Czy to możliwe, że wcześniej był otwarty inny Notatnik? Więc tworzysz jedną, zabijasz, ale wciąż widzisz stary Notatnik? 'proc.WaitForExit()' może natychmiast wrócić, jeśli proces nie mógł zostać utworzony lub został zakończony od razu z powodu pewnych powodów, na przykład brak przywilejów oryginalnego kodu do tworzenia nowych procesów. – oleksii

+0

@oleskii, nie upewniłem się o tym. Notatnik jest tutaj używany tylko jako proces "każdy wie", ten problem występuje bez względu na to, który plik jest używany w procesie. – Rotem

+0

@oleskii "proc.WaitForExit() może natychmiast powrócić, jeśli proces nie mógł zostać utworzony lub został zakończony od razu z powodu pewnych powodów" - czy proces nie zostałby w takim przypadku faktycznie zakończony? – Rotem

Odpowiedz

7

Problem polega na tym, że domyślnie Process.StartInfo.UseShellExecute jest ustawiona na wartość true. Przy tej zmiennej ustawionej na wartość true, zamiast samemu uruchamiać proces, prosisz powłokę, aby uruchomiła go za Ciebie. To może być całkiem użyteczne - pozwala na wykonywanie takich czynności jak "wykonanie" pliku HTML (powłoka użyje odpowiedniej domyślnej aplikacji).

To nie jest tak dobre, gdy chcesz śledzić aplikację po jej uruchomieniu (tak, jak znalazłeś), ponieważ aplikacja uruchomieniowa może czasami nie wiedzieć, która instancja powinna być śledzona.

Wewnętrzne szczegóły tego, dlaczego tak się dzieje, są prawdopodobnie poza moimi możliwościami odpowiedzi - wiem, że gdy UseShellExecute == true, framework używa interfejsu API ShellExecuteEx Windows, a gdy UseShellExecute == false, używa CreateProcessWithLogonW, ale dlaczego jeden prowadzi do procesów, które można śledzić, a drugi nie, nie wiem, ponieważ oba wydają się zwracać identyfikator procesu.

EDIT: Po trochę kopania:

This question wskazał mi do flagi SEE_MASK_NOCLOSEPROCESS, który rzeczywiście wydaje się być ustawiona przy użyciu ShellExecute. Dokumentacja dla wartości maski określa:

W niektórych przypadkach, na przykład gdy wykonanie zostanie spełnione przez konwersję DDE , uchwyt nie zostanie zwrócony. Aplikacja wywołująca jest odpowiedzialna za zamknięcie klamki, gdy nie jest już potrzebna.

Sugeruje to, że zwrócenie uchwytu procesu jest niewiarygodne. Wciąż nie doszedłem dostatecznie głęboko, żeby wiedzieć, który konkretny przypadek uderzysz tutaj.

+0

Dzięki! Podczas gdy twoje rozwiązanie rozwiązuje mój problem, z przyjemnością znajdę powód, dla którego wydaje się, że ma on wpływ tylko na jedną maszynę z grupy około 50. – Rotem

+0

Mam nadzieję, że @EricLippert dotrze tutaj i wyświetli odpowiedź "Dlaczego tak się dzieje? "część. Nie jestem taki bystry. –

+2

Nie mam zielonego pojęcia. Jestem ekspertem w projektowaniu i implementacji języka C# i jego kompilatora. Nie wiem praktycznie nic o tym, jak system Windows zarządza procesami. –

1

Przyczyną może być wirus, który zastąpił notatnik.exe, aby się ukryć. Po wykonaniu, spawnuje notatnik i wychodzi (tylko zgadnij).

próby kod:

 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"); 

Po Process.Start (id) sprawdzania procesu Notepad.exe z taskmanager i sprawdzić, czy to to samo, co process.Id;

Aha, i na pewno należy użyć pełnej ścieżki do NOTEPAD.EXE

var notepad = Path.Combine(Environment.GetFolderPath(
        Environment.SpecialFolder.Windows), "notepad.exe"); 
Process.Start(notepad); 
Powiązane problemy