如何让 WinForms 停止默默地忽略未处理的异常?

Posted

技术标签:

【中文标题】如何让 WinForms 停止默默地忽略未处理的异常?【英文标题】:How can I get WinForms to stop silently ignoring unhandled exceptions? 【发布时间】:2011-11-26 05:51:22 【问题描述】:

这变得非常烦人。现在我有一个 winforms 应用程序,但事情不正常,但据我所知,没有抛出异常。在浏览了几乎所有相关代码之后,事实证明在我的应用程序开始时抛出了一个异常。

长话短说,在 WinForms 中,尽管发生异常,但 WinForms 库会忽略它。没有“发生未处理的异常”JIT 消息被抛出,它只是停止处理当前事件并返回到 GUI。

这会导致随机错误,因为加载数据之前发生的异常导致加载数据的代码没有被调用。

为了看到这一点,我创建了一个全新的 WinForms 应用程序,并输入了以下代码:

public partial class Form1 : Form

    public Form1()
    
        InitializeComponent();
    

    private void Form1_Load(object sender, EventArgs e)
    
        string blah = null;
        blah.Trim();
    

按 F5 并加载表单而不会显示任何错误,即使抛出空引用也是如此。

然后我尝试转到我的 Program.cs 主要方法并将 Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); 添加到它。我的表单仍然加载而不会引发任何错误。

尽管我知道我可以告诉 VS 中断所有异常,但我发现这种情况非常糟糕。它会导致在生产环境中难以调试的非常奇怪的问题,而且由于这是一个内部工具,我真的很想拥有它,所以当异常发生时它实际上会出错,而不是默默地忽略它。

有人知道怎么做吗?


更新: 只是为了更新我从 cmets 学到的东西。

这似乎是 Windows 的 64 位问题,正如我从 this question 了解到的,我在发布之前没有看到。在那个问题中,它指向了一个Microsoft bug report,它有这样的说法:

你好,

此错误已作为“外部”关闭,因为此行为是由 x64 版本的 Windows 处理异常的方式引起的。当用户模式异常跨越内核转换时,x64 版本的 Windows 不允许传播异常。因此,附加的调试器不知道发生了异常,导致调试器无法中断未处理的异常。

不幸的是,Visual Studo 团队无法解决这个问题,这是操作系统设计的结果。有关此问题的所有反馈都应提交给 Windows 团队;但是 Windows 团队认为这是“正确”的操作系统设计,并认为 x86 行为是“不正确的”。

最好的问候, Visual Studio 调试器

话虽如此,如果您的Program.cs 中有以下代码,则不通过 Visual Studio 运行的构建(或使用 Ctrl+F5 运行)似乎会显示 JIT 异常消息框 EXCEPT

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

该代码将导致窗口忽略异常。

但是,如果您(改为)订阅 Application.ThreadException 事件,不仅您的异常会被捕获,Visual Studio 的调试器会在未处理的异常上中断!

【问题讨论】:

您尝试订阅 Application.UnhandledException 吗? @Tigran: 坏主意,恕我直言...我做了一次 ... 您确定订阅了 Form.Load 事件吗? ...只是一个健全的检查;) VS2010 does not show unhandled exception message in a 64-bit WinForms Application 的可能副本 有趣的链接,虽然一切都符合这个问题,但我的平台已经设置为 x86 并且无法修复它 【参考方案1】:

在您的 Program.cs 的 Main 函数中,您还应该确保您已将调用包装起来,以便在 try/catch 中打开表单。另外使用AppDomain.UnhandledException 来捕获异常。我们也添加了Application.ThreadException

我相信以下内容会让您了解所有可以抛出的异常...

static void Main()

    try
    
        System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
        System.Windows.Forms.Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(OnGuiUnhandedException);
        AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;

        var form = new MainForm();
        form.ShowDialog();
    
    catch (Exception e)
    
        HandleUnhandledException(e);
    
    finally
    
        // Do stuff
    


private static void HandleUnhandledException(Object o)

    // TODO: Log it!
    Exception e = o as Exception;

    if (e != null)
    

    


private static void OnUnhandledException(Object sender, UnhandledExceptionEventArgs e)

    HandleUnhandledException(e.ExceptionObject);


private static void OnGuiUnhandedException(object sender, System.Threading.ThreadExceptionEventArgs e)

    HandleUnhandledException(e.Exception);

【讨论】:

注意:可能有更好的方法来拦截所有这些东西,但上面的方法至少可以捕捉到所有东西......这样做是否是好的做法,我将留给其他评论员决定...【参考方案2】:

试试下面的。

在您的主应用程序入口点处理异常。 另外,使用ThreadExceptionEventHandler 管理未处理的线程异常

这是代码sn-p:

[STAThread]
public static void Main(string[] args)

    try
    
        Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
        //your program entry point
    
    catch (Exception ex)
    
       //manage also these exceptions
    


private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)

    ProcessException(e.Exception);

【讨论】:

订阅ThreadExceptionEventHandler 实际上确实会导致调试器在未处理的异常上中断!现在问题转向在Application_ThreadException 方法中做什么 这不会吞下外部异常吗?这部分有什么建议吗?更多信息:***.com/q/59146505/7453【参考方案3】:

一个简单的解决方法是不在调试器下运行。

调试器出于某种原因屏蔽了异常。如果您正常运行您的应用程序 (Ctrl+F5),您将收到通常的“您的应用程序中发生未处理的异常...继续/退出?”对话框。

【讨论】:

Ctrl+F5 仍然有同样的问题。不抛出异常 使用您的示例代码在我的盒子上扔得很好。您正在运行什么操作系统,它是 32 位还是 64 位?您的项目是 32 位还是 AnyCPU?您正在运行什么版本的 Visual Studio,以及您构建的 .NET 版本是什么? 64 位,平台目标 x86 VS 2010,.Net 4 这里也一样。在 Windows 7 上运行。不知道你在做什么不同,但如果我使用你的示例代码,并且在没有调试的情况下运行,我会立即得到未处理的异常对话框。 仅供参考,如果您的 Program.cs 中有 Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);,那么即使 ctrl+f5 也不会显示异常(这就是为什么我第一次建议时没有看到它的原因)跨度> 【参考方案4】:

我经常遇到这种情况并发现有关 64 位操作系统和 Form.Load 事件的问题,我总是强调在 Form.Shown 事件中执行所有启动功能。出于所有实际目的,这是同一件事(除了少数罕见的例外情况),并且 JIT 消息是在 Shown 事件中生成的。

【讨论】:

以上是关于如何让 WinForms 停止默默地忽略未处理的异常?的主要内容,如果未能解决你的问题,请参考以下文章

如何让 Fiddler 停止忽略到 localhost 的流量?

我可以让 Visual Studio 停止任务代码中未处理的异常吗?

我怎样才能找到程序停滞的原因?

Erlang 机器立即停止(分发名称冲突?)。服务未重新启动,因为 OnFail 设置为忽略

有没有办法让 Resharper 忽略未使用的引用?

如何在更新数据源时让绑定的 winforms 控件刷新?