当我在MSDN上阅读Application.Exit()的文档时,它说:
通知所有消息泵必须终止,然后在处理完消息后关闭所有应用程序窗口.
根据我的理解,为了通知所有消息泵终止,这种方法最终会将WM_QUIT消息发送到应用程序消息队列.发布消息后,该方法将关闭每个窗口(通过MSDN).问题出在这里,当这个方法试图关闭每个窗口时,WM_QUIT消息应该没有被处理,但是MSDN说"它在消息被处理后关闭所有窗口".
文档似乎与我的推论相矛盾.这里有什么问题,非常感谢任何帮助.
das*_*ash 14
有趣的问题; 使用ILSpy,让我们看一下Application.Exit():
我们看到关键的方法是 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;
}
Run Code Online (Sandbox Code Playgroud)
如果一切顺利,应用程序将首先关闭所有表单,然后关闭它错过的任何表单,然后,最后,它调用Application.ThreadContext.ExitApplication();
作为ExitApplication的一部分,我们看到了清理:
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();
}
Run Code Online (Sandbox Code Playgroud)
是什么ExitThreadCore办?
好吧,它不直接杀死线程,但它确实启动了进程:
ExitThread和ExitThreadCore实际上不会导致线程终止.这些方法引发Application对象侦听的ThreadExit事件.然后,Application对象终止该线程.
然而,真正有趣的一点似乎发生在 array[i].Dispose(disposing)
作为此方法的一部分,我们看到:
if (this.messageLoopCount > 0 && postQuit)
{
this.PostQuit();
}
Run Code Online (Sandbox Code Playgroud)
PostQuit()是发送WM_QUIT消息的内容.因此我们也应该考虑何时Application.ThreadContext.Dispose被调用,并且似乎总是在表格关闭之后,尽管我很高兴在那里得到纠正.
所以命令似乎接近所有形式,然后发送WM_QUIT消息.我认为你是对的,文档可能实际上有错误的顺序事件......
它也证实了我们经常看到的另一个副作用; 当一个应用程序关闭但仍有一个线程在后台运行时,exe仍然会在正在运行的应用程序列表中.表格已经关闭,但仍然存在流氓线程,哼唱着阻止Exit()完成.
正如Tergiver所提到的:
线程是后台线程或前台线程.后台线程与前台线程相同,除了后台线程不会阻止进程终止.一旦属于进程的所有前台线程终止,公共语言运行库就结束该进程.任何剩余的后台线程都会停止并且不会完成.
我也想知道Environment.Exit:
[SecurityCritical, SuppressUnmanagedCodeSecurity]
[DllImport("QCall", CharSet = CharSet.Unicode)]
internal static extern void _Exit(int exitCode);
Run Code Online (Sandbox Code Playgroud)
它有效地呼吁操作系统杀死这个过程; 这会以很少的优雅终止所有窗户; 例如,OnFormClosing可能永远不会被解雇.作为批发终止的一部分,它[我会犹豫使用尝试,因为我从未见过它失败]杀死任何线程,包括消息循环正在运行的'main'线程.
| 归档时间: |
|
| 查看次数: |
551 次 |
| 最近记录: |