【问题标题】:App doesn't exit when main window is closed关闭主窗口时应用程序不退出
【发布时间】:2010-02-03 21:41:32
【问题描述】:

我一直遇到这个问题,解决它,然后当我实现新代码时它又回来了。快把我逼疯了!

我最终发现,如果您实例化任何类型的 Window,即使您从未调用 Show() 或 ShowDialog(),当您关闭应用程序时,它也不会终止。所以现在我确保在适当的时候调用 Close(),并且我创建的所有 Windows 都没有出现问题。

我已经实现了更多不创建窗口的新功能(据我所知!),但现在我的应用程序不会再次终止。我认为在 VS IDE 中暂停是没有用的,因为线程没有任何上下文,所以我无法弄清楚是什么代码导致了挂起。

通常情况下,我希望在后台执行但尚未退出(并且未设置为后台线程)的线程会导致此行为,但此时我没有创建任何线程。

谁能推荐一个好工具(免费或需要许可证)来帮助我快速解决这些愚蠢的问题?现在,我要回去,注释掉大量新代码,然后逐行取消注释,直到问题再次出现。蛮力是我通常最终修复这些事情的方式,并且非常感谢一种让我的生活更轻松的工具。 :)

【问题讨论】:

  • WinForms :如果这些都是“愚蠢”的问题,你可能已经完成了所有工作来“确定这一点”,请原谅:你在使用 ApplicationContext 吗?您是否在 Program.cs 文件中做任何不寻常的事情?您是否为主窗体的 FormClosing 和 FormClosed 事件(通常在 Program.cs 中启动的事件)编写了一个处理程序,并在这些事件处理程序中放置断点和/或记录消息并检查了状态,查看了“应用程序”的内容.OpenForms ?你在用 AppDomains 做些什么吗?
  • 我使用的是 WPF,而不是 Windows 窗体。我发现它在反射代码中,它现在挂起而以前没有挂起的原因是因为我对插件使用的接口进行了一些更改。所以现在我必须对代码进行比较,这样我才能准确地看到接下来需要注释的内容。 :)

标签: c# .net wpf multithreading


【解决方案1】:

听起来您可能在其他答案正在解决的后台线程方面存在其他问题,但对于 WPF Windows,您是否尝试过更改 App 类的 ShutdownMode?您也可以尝试通过显式调用 Shutdown 来强制应用退出:

Application.Current.Shutdown();

【讨论】:

  • 我没有尝试过关机模式(我不知道!),但我会试一试。感谢您的建议。
  • 您如何实际设置关机模式?我试图这样做,但不知道要使用什么常量。 MSDN 提到 OnMainWindowClosed,但我不知道如何指定它。我可能需要尝试从 Window_Unloaded 显式调用 Shutdown。
  • ShutdownMode 是 Application 上的一个属性,因此您可以在 App.xaml 中设置它。选项是在主窗口关闭时退出,在所有窗口关闭后退出,或者需要显式调用 Shutdown()。
  • 事实证明(我相信)挂起是由于我的插件无法加载,并且没有正确处理异常造成的。它在 InitializeComponent 中引发了异常,但它并没有让应用程序崩溃,而是默默地失败了。我没有手动“抛出”异常,因为我跳过了 UC 的实例化,而环境只是弹出了我的主 GUI,而没有进入下一行。这是我在 VC++ 时代从未见过的 .NET 中的新事物。不过,我将恢复到之前冻结的代码,所以我可以试试你的建议。
  • 约翰,成功了!一般来说,我想我会选择不指定这个属性,因为这可能意味着我遇到了一个真正的问题,就像我在上面的评论中提到的那样。但我认为有一天它也会真正派上用场,而且它似乎确实有效!很酷。
【解决方案2】:

如果您同时使用托管代码和非托管代码进行附加,您可能会获得更多信息。在 Visual Studio 2008 中,您可以在“附加到进程”表单中更改模式。按“选择...”按钮并为“托管”和“本机”指定调试。

(在执行此操作之前,请确保已设置符号路径。转到工具/选项、调试、符号。在符号文件位置列表中输入 http://msdl.microsoft.com/download/symbols。在某个目录中本地缓存符号。)

当您在托管和非托管模式下附加时,您应该获得更大的调用堆栈。我建议在调用堆栈调试窗口中单击鼠标右键并选择“包括对/来自其他线程的调用”。

如果您的主线程显示 System.Windows.Forms.Application.Run 或 ThreadContext.RunMessageLoop,则您的 UI 线程的消息泵是活动的并且仍在泵送消息。如果由于某种原因,它正在转换到另一个线程,那么它在完成之前不能退出。

您还可以查看其余托管和非托管线程的完整堆栈跟踪。您可能想寻找一个垃圾收集器线程并查看它在做什么。查找其中包含“GCHeap::FinalizerThreadStart”的堆栈。那可能正在做某事。

可能还有一个 GID+ 线程正忙于尝试工作。

【讨论】:

  • 太棒了,我会试试看!谢谢。使用我的蛮力调试“技术”,我确定发生冻结是因为在我的应用程序中调用了一些加载插件。我没有把它隔离到那个函数中的代码,但它主要是反射代码。有趣的是,我从其他地方调用了相同的函数,当调用者没有被注释掉时,它并没有冻结。直到我实现了一个从其他三个接口乘以继承的接口,它才冻结......有什么想法吗? :)
【解决方案3】:

我并不是要过分简化事情,但是您是否尝试过将对话框窗口的所有者设置为 MainWindow?这将在 MainWindow 关闭时强制关闭对话框窗口。换句话说,它看起来像这样:

dialog.Owner = Window.GetWindow(this);
// Or...
dialog.Owner = Application.Current.MainWindow;

这对你来说可能不是一个选项,但我只是想把它扔掉,因为你的帖子没有提到你不想设置窗口的所有者。

【讨论】:

  • 我也可以试一试,谢谢!无论如何我都应该设置窗口所有者。
【解决方案4】:

虽然它在您的特定情况下可能无济于事,但 Process Explorer 是一款出色的工具,可用于查看正在运行的进程并查看有多少线程等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多