Pregunta interesante; utilizando ILSpy, vamos a echar un vistazo a lo Application.Exit()
hace:
Vemos que el método crítico es ExitInternal
private static bool ExitInternal()
{
bool flag = false;
lock (Application.internalSyncObject)
{
if (Application.exiting)
{
return false;
}
Application.exiting = true;
try
{
if (Application.forms != null)
{
foreach (Form form in Application.OpenFormsInternal)
{
if (form.RaiseFormClosingOnAppExit())
{
flag = true;
break;
}
}
}
if (!flag)
{
if (Application.forms != null)
{
while (Application.OpenFormsInternal.Count > 0)
{
Application.OpenFormsInternal[0].RaiseFormClosedOnAppExit();
}
}
Application.ThreadContext.ExitApplication();
}
}
finally
{
Application.exiting = false;
}
}
return flag;
}
Si todo va bien, la aplicación primeros cierre todas formas, a continuación, cierre todas las formas que se perdió, y luego, por último, se llama Application.ThreadContext.ExitApplication();
Como parte de ExitApplication, vemos la limpieza:
private static void ExitCommon(bool disposing)
{
lock (Application.ThreadContext.tcInternalSyncObject)
{
if (Application.ThreadContext.contextHash != null)
{
Application.ThreadContext[] array = new Application.ThreadContext[Application.ThreadContext.contextHash.Values.Count];
Application.ThreadContext.contextHash.Values.CopyTo(array, 0);
for (int i = 0; i < array.Length; i++)
{
if (array[i].ApplicationContext != null)
{
array[i].ApplicationContext.ExitThread();
}
else
{
array[i].Dispose(disposing);
}
}
}
}
}
// System.Windows.Forms.ApplicationContext
/// <summary>Terminates the message loop of the thread.</summary>
/// <filterpriority>1</filterpriority>
public void ExitThread()
{
this.ExitThreadCore();
}
¿Qué hace ExitThreadCore?
Bueno, no mata directamente el hilo, pero se pone en marcha el proceso:
ExitThread y ExitThreadCore en realidad no causa el hilo a terminar. Estos métodos generan el evento ThreadExit al que escucha el objeto de aplicación . El objeto Aplicación finaliza el subproceso .
Sin embargo, la parte realmente interesante parece suceder en array[i].Dispose(disposing)
Como parte de este método, vemos:
if (this.messageLoopCount > 0 && postQuit)
{
this.PostQuit();
}
después del abandono() es lo que envía el mensaje WM_QUIT
. Así que también deberíamos considerar cuándo se llama al Application.ThreadContext.Dispose
, y siempre parece serlo después de que se cierren los formularios, aunque me complace que se corrijan allí.
De modo que el orden parece estar cerca de todas las formas, luego envíe el mensaje WM_QUIT. Creo que tiene razón, la documentación puede tener los eventos en el orden incorrecto ...
También confirma otro efecto secundario que a menudo vemos; cuando se cierra una aplicación pero todavía hay un hilo ejecutándose en segundo plano, el exe seguirá en la lista de aplicaciones en ejecución. Los formularios se han cerrado, pero todavía hay ese hilo deshonesto, zumbando a lo largo de evitar que se complete la salida().
Como Tergiver menciones:
Un hilo es o bien un hilo de fondo o un hilo plano. Los subprocesos de fondo son idénticos a los subprocesos de primer plano, excepto que los subprocesos de fondo no impiden que un proceso finalice. Una vez que todos los hilos de primer plano que pertenecen a un proceso han terminado, el tiempo de ejecución de lenguaje común finaliza el proceso. Los hilos de fondo restantes se detienen y no se completan.
(de Thread.IsBackgroundThread)
también me pregunté que hace Environment.Exit
:
[SecurityCritical, SuppressUnmanagedCodeSecurity]
[DllImport("QCall", CharSet = CharSet.Unicode)]
internal static extern void _Exit(int exitCode);
Se llama efectivamente a cabo con el sistema operativo para matar el proceso; esto terminará todas las ventanas con poca gracia; el OnFormClosing probablemente nunca llegue a disparar, por ejemplo. Como parte de esta finalización al por mayor, también [vacilaré en intentar el intento, ya que nunca lo he visto que falle] mato cualquier hebra, incluido el hilo "principal" en el que se está ejecutando el ciclo de mensajes.
¿Por qué crees que el mensaje WM_QUIT no se habría procesado? –
Una mejor pregunta sería: "¿Qué problema tiene debido a este orden de operaciones?" – Tergiver
No hay un solo signo de interrogación en la PREGUNTA ... –