¿Por qué Environment.Exit () no termina el progtwig más?

Esto es algo que descubrí hace unos días, obtuve la confirmación de que esta cuestión no se limita a mi máquina.

La forma más fácil de reproducirlo es iniciar una aplicación de Windows Forms, agregar un botón y escribir este código:

private void button1_Click(object sender, EventArgs e) { MessageBox.Show("yada"); Environment.Exit(1); // Kaboom! } 

El progtwig falla después de que se ejecuta la instrucción Exit (). En Windows Forms, aparece el mensaje “Error al crear el identificador de ventana”.

Al habilitar la depuración no administrada, queda algo claro de lo que está sucediendo. El ciclo modal COM se está ejecutando y permite que se entregue un mensaje WM_PAINT. Eso es fatal en una forma eliminada.

Los únicos hechos que he reunido hasta ahora son:

  • No se limita a ejecutar con el depurador. Esto también falla sin uno. Demasiado pobre también, el cuadro de diálogo de locking de WER aparece dos veces .
  • No tiene nada que ver con la fragilidad del proceso. La capa wow64 es bastante notoria, pero una comstackción AnyCPU falla de la misma manera.
  • No tiene nada que ver con la versión .NET, 4.5 y 3.5 se bloquean de la misma manera.
  • El código de salida no importa.
  • Llamar a Thread.Sleep () antes de llamar a Exit () no lo soluciona.
  • Esto sucede en la versión de 64 bits de Windows 8, y Windows 7 no parece verse afectado de la misma manera.
  • Este debería ser un comportamiento relativamente nuevo, no he visto esto antes. No veo actualizaciones relevantes entregadas a través de Windows Update , aunque el historial de actualizaciones ya no es preciso en mi máquina.
  • Este es un comportamiento de ruptura total. Escribiría un código como este en un controlador de eventos para AppDomain.UnhandledException, y se bloquea de la misma manera.

Estoy particularmente interesado en lo que podrías hacer para evitar este locking. En particular, el escenario AppDomain.UnhandledException me topa; no hay muchas formas de finalizar un progtwig .NET. Tenga en cuenta que llamar a Application.Exit () o Form.Close () no son válidos en un controlador de eventos para UnhandledException, por lo que no son soluciones.


ACTUALIZACIÓN: Mehrdad señaló que el hilo del finalizador podría ser parte del problema. Creo que estoy viendo esto y también estoy viendo algunas pruebas para el tiempo de espera de 2 segundos que el CLR da el hilo del finalizador para terminar la ejecución.

El finalizador está dentro de NativeWindow.ForceExitMessageLoop (). Hay una función Win32 de IsWindow () que se corresponde aproximadamente con la ubicación del código, offset 0x3c cuando se mira el código de máquina en modo de 32 bits. Parece que IsWindow () está bloqueando. No puedo obtener un buen seguimiento de la stack para las partes internas, sin embargo, el depurador cree que la llamada P / Invoke acaba de regresar. Esto es difícil de explicar. Si puedes obtener un mejor seguimiento de stack, me encantaría verlo. Mía:

 System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.ForceExitMessageLoop() + 0x3c bytes System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Finalize() + 0x16 bytes [Native to Managed Transition] kernel32.dll!@BaseThreadInitThunk@12() + 0xe bytes ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes 

Nada por encima de la llamada ForceExitMessageLoop, depurador no administrado habilitado.

Contacté a Microsoft sobre este problema y pareció haber valido la pena. Al menos me gustaría pensar que sí 🙂 Aunque no obtuve una confirmación de una resolución, el grupo de Windows es difícil de contactar directamente y tuve que usar un intermediario.

Una actualización entregada a través de Windows Update resolvió el problema. La notable demora de 2 segundos antes del locking ya no está presente, lo que sugiere fuertemente que el punto muerto IsWindow () se resolvió. Y el progtwig se apaga de forma limpia y confiable. La actualización instaló parches para Windows Defender, wdboot.sys, wdfilter.sys, tcpip.sys, rpcrt4.dll, uxtheme.dll, crypt32.dll y wintrust.dll

Uxtheme.dll es el extraño. Implementa la API de temática de Estilos visuales y es utilizada por este progtwig de prueba. No puedo estar seguro, pero mi dinero está en ese como el origen del problema. La copia en C: \ WINDOWS \ system32 tiene la versión número 6.2.9200.16660, creada el 14 de agosto de 2013 en mi máquina.

Caso cerrado.

No sé por qué no funciona “más” , pero creo que Environment.Exit ejecuta finalizadores pendientes. Environment.FailFast no lo hace.

Puede ser que (por alguna extraña razón) tengas extraños finalizadores pendientes que deben ejecutarse después, haciendo que esto suceda.

Esto no explica por qué está sucediendo, pero no llamaría a Environment.Exit en un controlador de eventos de botón como su ejemplo, en su lugar cierre el formulario principal como se sugiere en la respuesta de René .

En cuanto a un controlador AppDomain.UnhandledException , tal vez podría simplemente establecer Environment.ExitCode lugar de llamar a Environment.Exit .

No estoy seguro de lo que estás tratando de lograr aquí. ¿Por qué quiere devolver un código de salida desde una aplicación de Windows Forms? Normalmente, las aplicaciones de consola utilizan códigos de salida.

Estoy particularmente interesado en lo que podría hacer para evitar este locking. Calling Environment .Exit () es necesario para evitar que se muestre el cuadro de diálogo WER.

¿Tienes una try / catch en el método Main? Para las aplicaciones de Windows Forms, siempre tengo una try / catch alrededor del bucle de mensajes, así como los manejadores de excepciones no manejados.

He encontrado el mismo problema en nuestra aplicación, lo hemos resuelto con la siguiente construcción:

 Environment.ExitCode=1; Application.Exit();