VS2010不会在64位版本的Windows上的WinForms应用程序中显示未处理的异常消息

Rob*_*ner 76 c# exception-handling visual-studio-2010

当我创建一个新项目时,我对未处理的异常会有一个奇怪的行为.这就是我可以重现问题的方法:

1)创建一个新的Windows窗体应用程序(C#,. NET Framework 4,VS2010)

2)将以下代码添加到Form1_Load处理程序:

int vara = 5, varb = 0;
int varc = vara / varb;
int vard = 7;
Run Code Online (Sandbox Code Playgroud)

我希望VS中断并在第二行显示未处理的异常消息.但是,会发生的是第三行只是跳过而没有任何消息,应用程序一直在运行.

我现有的C#项目没有这个问题.所以我想我的新项目是用一些奇怪的默认设置创建的.

有没有人知道我的项目有什么问题?

我试过检查Debug-> Exceptions中的方框.但即使我在try-catch块中处理异常,执行也会中断; 这也不是我想要的.如果我没记错的话,在这个对话框中有一个名为"未处理的异常"的列或者类似的东西,这会让我感到非常兴奋.但在我的项目中只有一列("Thrown").

Han*_*ant 121

这是由wow64仿真层引起的一个令人讨厌的问题,它允许32位代码在64位版本的Windows 7上运行.它吞噬了响应64位窗口管理器生成的通知而运行的代码中的异常,就像Load活动一样.防止调试器看到它​​并踩到.这个问题很难解决,微软的Windows和DevDiv小组来回指责.DevDiv对此无能为力,Windows认为这是正确且有记录的行为,听起来很神秘.

它肯定是有记录的,但只是没有人理解后果或认为它是合理的行为.特别是当窗口过程从视图中隐藏时,就像在任何使用包装类来隐藏窗口管道的项目中一样.像任何Winforms,WPF或MFC应用程序.基本问题是Microsoft无法弄清楚如何将异常从32位代码流回到64位代码,该代码将通知重新发送回尝试处理或调试异常的32位代码.

附加调试器只是一个问题,你的代码将像往常一样没有炸弹.

项目>属性>构建选项卡>平台目标= AnyCPU并取消选择首选32位.您的应用程序现在将作为64位进程运行,从而消除了wow64故障模式.一些后果,它会在VS2013之前禁用VS版本的Edit + Continue,并且当您对32位代码具有依赖性时可能并不总是可行.

其他可能的解决方法:

  • Debug> Exceptions>勾选CLR异常的Thrown框以强制调试器停止在抛出异常的代码行.
  • Load事件处理程序中编写try/catch,在catch块中编写failfast.
  • Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)Main()方法中使用,以便在调试模式下不禁用消息循环中的异常陷阱.然而,这使得所有未处理的异常难以调试,ThreadException事件是无用的.
  • 考虑一下您的代码是否真的属于Load事件处理程序.它很少需要它,但它在VB.NET和swan歌曲中非常流行,因为它是默认事件,双击简单地添加了事件处理程序.在应用用户首选项和自动缩放后,当您对实际窗口大小感兴趣时,您才真正需要Load.其他所有内容都属于构造函数.
  • 更新到Windows 8或更高版本,他们解决了这个问题.

  • Windows 8*做*有这个问题.仅供参考. (7认同)
  • 是的,有一篇Connect文章.其中很多.这个可能是最好的:https://connect.microsoft.com/VisualStudio/feedback/details/357311/silent-exceptions-on-x64-development-machines (6认同)
  • 这里有一个暗示他们不知道发生了什么的一点:https://connect.microsoft.com/VisualStudio/feedback/details/589858/form-load-event-unhandled-exception-not-caught-从-内部视觉工作室,但是,卡住时,应用程序启动的-外视觉工作室 (5认同)

Jon*_*art 10

根据我的经验,当我运行附带的调试器时,我只会看到这个问题.独立运行时,应用程序的行为相同:不会吞下异常.

随着KB976038的推出,您可以按照您的期望再次使用它.我从来没有安装过这个修补程序,所以我假设它是作为Win7 SP1的一部分而来的.

这篇文章中提到了这一点:

这是一些将启用此修补程序的代码:

public static class Kernel32
{
    public const uint PROCESS_CALLBACK_FILTER_ENABLED = 0x1;

    [DllImport("Kernel32.dll")]
    public static extern bool SetProcessUserModeExceptionPolicy(UInt32 dwFlags);

    [DllImport("Kernel32.dll")]
    public static extern bool GetProcessUserModeExceptionPolicy(out UInt32 lpFlags);


    public static void DisableUMCallbackFilter() {
        uint flags;
        GetProcessUserModeExceptionPolicy(out flags);

        flags &= ~PROCESS_CALLBACK_FILTER_ENABLED;
        SetProcessUserModeExceptionPolicy(flags);
    }
}
Run Code Online (Sandbox Code Playgroud)

在应用程序开头调用它:

    [STAThread]
    static void Main()
    {
        Kernel32.DisableUMCallbackFilter();

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
Run Code Online (Sandbox Code Playgroud)

我已经确认(使用下面显示的简单示例),这正如您所期望的那样有效.

protected override void OnLoad(EventArgs e) {
    throw new Exception("BOOM");   // This will now get caught.
}
Run Code Online (Sandbox Code Playgroud)

所以,我不明白,为什么调试器以前不可能处理交叉内核模式堆栈帧,但是使用这个修补程序,他们以某种方式弄明白了.