如何让WinForms静静地忽略未处理的异常?

时间:2011-09-27 17:07:15

标签: c# winforms exception

这令人非常恼火。现在我有一个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打破所有异常,我发现这种情况非常糟糕。它导致了很难在生产中调试的奇怪问题,因为这是一个内部工具,我真的想拥有它,以便在发生异常时实际上出错,而​​不是默默地忽略它。

有谁知道怎么做?

<小时/> 更新:只是为了更新我从评论中学到的东西。

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

  

您好,

     

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

     

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

     

最诚挚的问候,   Visual Studio调试器

话虽如此,如果你的{{1}中有以下代码,那么构建不通过visual studio运行(或使用Ctrl + F5运行)似乎确实显示了JIT异常消息框 EXCEPT }}:

Program.cs

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

但是,如果您(而不是)订阅Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); 事件,不仅会捕获您的异常,Visual Studio的调试器中断未处理的异常!

4 个答案:

答案 0 :(得分:16)

在Program.cs的主要功能中,您还应确保已打包调用以在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);
}

答案 1 :(得分:7)

请尝试以下操作。

这是代码段:

[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);
}

答案 2 :(得分:4)

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

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

答案 3 :(得分:-1)

经常遇到这个并确定了有关64位操作系统和Form.Load事件的问题,我总是在Form.Shown事件中完成所有启动功能。出于所有实际目的,这是相同的事情(除了一些罕见的特殊情况),并且JIT消息在Shown事件中产生。