2012-01-17 15 views
16

Este código se ejecuta como se esperaba en un gran número de máquinas. Sin embargo, en una máquina en particular, la llamada al WaitForExit() parece ignorarse, y de hecho marca el proceso como salido.Process.WaitForExit inconsistentes en diferentes máquinas

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

Tenga en cuenta que a diferencia de un similar question en SO, el proceso que se llama es notepad.exe (por razones de prueba), por lo que es poco probable que la falla se encuentra con ella - es decir, no está generando un segundo sub-proceso y cierre. Aun así, no explicaría por qué funciona en todas las otras máquinas.

En la máquina del problema, la segunda llamada a Console.WriteLine(proc.HasExited)) vuelve true a pesar de que el bloc de notas sigue siendo claramente abierta, tanto en la pantalla y en el administrador de tareas.

La máquina funciona con Windows 7 y .NET 4.0.

Mi pregunta es; ¿Qué condiciones en esa máquina en particular podrían estar causando esto? ¿Qué debería estar revisando?

Editar - Cosas que he probado hasta ahora/Actualizaciones/Información Posiblemente relevantes:

  • .NET reinstalado.
  • Cerré los procesos que no conozco en el administrador de tareas.
  • Aún no se ha activado Windows en esta máquina.
  • Siguiendo los consejos en los comentarios, he intentado conseguir el proceso 'existente' Id utilizando GetProcessesByName sino que simplemente devuelve una matriz vacía en la máquina problema. Por lo tanto, es difícil decir que el problema es incluso con WaitForExit, ya que el proceso no es devuelto llamando GetProcessesByName incluso antes de llamar WaitForExit.
  • En la máquina del problema, ParentID del proceso de libreta resultante es el ID del proceso bloc de notas el código inicia manualmente, o en otras palabras, el bloc de notas está generando un proceso hijo y que termina en sí.
+1

¿Es posible que haya otro Bloc de notas abierto antes? Entonces creas uno, matas uno, pero aún ves el viejo Bloc de notas? 'proc.WaitForExit()' puede regresar inmediatamente, si el proceso no pudo ser creado o fue terminado inmediatamente debido a algunas razones, por ejemplo, la falta de privilegios del código original para crear nuevos procesos. – oleksii

+0

@oleskii, no, me he asegurado de esto. El Bloc de notas solo se utiliza aquí como un proceso "que todo el mundo sabe", este problema se produce sin importar qué archivo se utiliza para el proceso. – Rotem

+0

@oleskii "proc.WaitForExit() puede regresar inmediatamente, si el proceso no se pudo crear o se finalizó de inmediato debido a algunas razones" - ¿no sería el proceso realmente finalizado en este caso? – Rotem

Respuesta

7

El problema es que, por defecto Process.StartInfo.UseShellExecute se establece en true. Con esta variable establecida en verdadero, en lugar de comenzar el proceso usted mismo, le está pidiendo al intérprete de comandos que lo inicie por usted. Eso puede ser muy útil: le permite hacer cosas como "ejecutar" un archivo HTML (el shell usará la aplicación predeterminada adecuada).

no es tan bueno cuando se quiere realizar un seguimiento de la aplicación después de la ejecución de ella (como lo encontró), ya que la aplicación de lanzamiento a veces puede confundirse sobre qué instancia debe de seguimiento.

Los detalles internos aquí de por qué sucede esto están probablemente más allá de mis capacidades para responder: sí sé que cuando UseShellExecute == verdadero, el marco usa la API ShellExecuteEx Windows, y cuando usa UseShellExecute == falso, usa CreateProcessWithLogonW, pero por qué uno conduce a procesos rastreables y el otro no lo sé, ya que ambos parecen devolver el ID del proceso.

EDIT: Después de un poco de investigación:

This question me señaló a la bandera SEE_MASK_NOCLOSEPROCESS, que parece que en efecto ser ajustada cuando se utiliza ShellExecute. La documentación de los estados valor de máscara:

En algunos casos, como cuando la ejecución se satisface mediante una conversación DDE , será devuelto sin mango. La aplicación de llamada es responsable de cerrar el identificador cuando ya no es necesario.

Por lo tanto, sugiere que devolver el identificador del proceso no es confiable. Todavía no he llegado lo suficientemente profundo como para saber qué borde de caja particular podría estar golpeando aquí.

+0

Gracias! Si bien su solución resuelve mi problema, me encantaría encontrar la razón por la que solo pareció tener efecto en una sola máquina de un grupo de aproximadamente 50. – Rotem

+0

Espero que @EricLippert entre aquí y coloque "¿Por qué sucede esto? "parte. No soy tan fuerte. –

+2

No tengo la menor idea. Soy un experto en el diseño e implementación del lenguaje C# y su compilador. No sé prácticamente nada sobre cómo Windows gestiona los procesos. –

1

Una causa podría ser un virus que reemplazó a notepad.exe para ocultarse. Si se ejecuta, genera el bloc de notas y las salidas (solo una conjetura).

tratar este código:

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

Después Process.Start() comprobar el identificador de proceso de notepad.exe con el administrador de tareas y verifique que es el mismo que process.Id;

Ah, y que realmente debe utilizar la ruta completa a notepad.exe

var notepad = Path.Combine(Environment.GetFolderPath(
        Environment.SpecialFolder.Windows), "notepad.exe"); 
Process.Start(notepad); 
Cuestiones relacionadas