提问人:Robert Hegner 提问时间:2/8/2011 最后编辑:participantRobert Hegner 更新时间:4/25/2020 访问量:24998
VS2010 在 64 位版本的 Windows 上的 WinForms 应用程序中不显示未经处理的异常消息
VS2010 does not show unhandled exception message in a WinForms Application on a 64-bit version of Windows
问:
当我创建一个新项目时,我收到一个奇怪的行为,即未经处理的异常。这是我重现问题的方法:
1) 创建新的 Windows 窗体应用程序(C#、.NET Framework 4、VS2010)
2) 将以下代码添加到处理程序中:Form1_Load
int vara = 5, varb = 0;
int varc = vara / varb;
int vard = 7;
我希望 VS 中断并在第二行显示未经处理的异常消息。但是,发生的情况是,第三行只是跳过而没有任何消息,应用程序继续运行。
我现有的 C# 项目没有这个问题。所以我想我的新项目是用一些奇怪的默认设置创建的。
有谁知道我的项目出了什么问题???
我尝试选中 Debug->Exceptions 中的框。但是,即使我在块中处理异常,执行也会中断;这也不是我想要的。如果我没记错的话,此对话框中有一个名为“未处理的异常”或类似内容的列,它完全可以满足我的要求。但是在我的项目中,只有一列(“抛出”)。try-catch
答:
这是一个令人讨厌的问题,由 wow64 仿真层引起,它允许 32 位代码在 64 位版本的 Windows 7 上运行。它吞噬为响应 64 位窗口管理器生成的通知而运行的代码中的异常,例如事件。阻止调试器看到它并单步执行。这个问题很难解决,Microsoft的Windows和DevDiv小组来回指责。DevDiv 对此无能为力,Windows 认为这是正确且有据可查的行为,听起来很神秘。Load
它当然被记录在案,但几乎没有人理解后果或认为这是合理的行为。当然,当窗口过程从视图中隐藏时尤其如此,就像在任何使用包装类隐藏窗口管道的项目中一样。与任何 Winforms、WPF 或 MFC 应用一样。根本问题是 Microsoft 无法弄清楚如何将异常从 32 位代码流回触发通知的 64 位代码,再流回尝试处理或调试异常的 32 位代码。
这只是附加调试器的问题,如果没有调试器,您的代码将像往常一样轰炸。
“项目>属性”>“生成”选项卡>“平台目标 = AnyCPU”,然后取消勾选“首选 32 位”。您的应用现在将作为 64 位进程运行,从而消除了 wow64 失败模式。某些后果是,它会禁用 VS2013 之前的 VS 版本的“编辑 + 继续”,并且当您依赖于 32 位代码时,可能并不总是可行的。
其他可能的解决方法:
- “调试>异常”>勾选“CLR 异常”的“引发”框,以强制调试器在引发异常的代码行处停止。
- 在事件处理程序中写入 try/catch,在 catch 块中写入 failfast。
Load
- 在方法中使用,以便在调试模式下不会禁用消息循环中的异常陷阱。但是,这使得所有未处理的异常都难以调试,该事件非常无用。
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)
Main()
ThreadException
- 考虑您的代码是否真的属于事件处理程序。需要它的情况非常罕见,但是它在 VB.NET 和绝唱中非常流行,因为它是默认事件,双击可以轻松添加事件处理程序。只有在应用用户首选项和自动缩放后,您才真正需要对实际窗口大小感兴趣。其他所有内容都属于构造函数。
Load
Load
- 更新到 Windows 8 或更高版本,他们解决了这个 wow64 问题。
评论
Application.ThreadException
根据我的经验,我只有在连接调试器的情况下运行时才会看到此问题。应用程序在独立运行时的行为相同:不会吞没异常。
随着 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);
}
}
在应用程序的开头调用它:
[STAThread]
static void Main()
{
Kernel32.DisableUMCallbackFilter();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
我已经确认(使用下面显示的简单示例)这有效,正如您所期望的那样。
protected override void OnLoad(EventArgs e) {
throw new Exception("BOOM"); // This will now get caught.
}
所以,我不明白的是,为什么调试器以前不可能处理跨内核模式堆栈帧,但有了这个修补程序,他们以某种方式解决了这个问题。
评论
Set/GetProcessUserModeExceptionPolicy
仍未记录在 MSDN 上,并且 Windows 8 的Kernel32.dll不会导出它们。
我正在使用 WPF 并遇到了同样的问题。我已经尝试过 Hans 1-3 的建议,但不喜欢它们,因为工作室不会停在错误所在的地方(所以我无法查看我的变量并查看问题所在)。
所以我尝试了汉斯的第四个建议。令我惊讶的是,我的代码中有多少可以毫无问题地移动到 MainWindow 构造函数中。不知道为什么我养成了在 Load 事件中放置这么多逻辑的习惯,但显然其中大部分都可以在 ctor 中完成。
但是,这与 1-3 存在相同的问题。在 WPF 的 ctor 期间发生的错误将包装到泛型 Xaml 异常中。(内部异常有真正的错误,但我再次希望工作室在实际的麻烦点中断)。
最终对我有用的是创建一个线程,休眠 50 毫秒,调度回主线程并做我需要的事情......
void Window_Loaded(object sender, RoutedEventArgs e)
{
new Thread(() =>
{
Thread.Sleep(50);
CrossThread(() => { OnWindowLoaded(); });
}).Start();
}
void CrossThread(Action a)
{
this.Dispatcher.BeginInvoke(a);
}
void OnWindowLoaded()
{
...do my thing...
这样,工作室将在发生未捕获的异常时中断。
正如 Hans 所提到的,编译应用程序并在不附加调试器的情况下运行 exe。
对我来说,问题是更改 BindingSource 控件绑定到的 Class 属性名称。在没有IDE的情况下运行,我能够看到错误:
无法绑定到 SendWithoutProofReading 上的属性或列 数据源。参数名称:dataMember
修复 BindingSource 控件以绑定到更新的属性名称解决了以下问题:
一个简单的解决方法是,您可以将初始化代码移动到另一个事件,例如 which 调用晚于 ,并使用标志在所示的第一个形式运行启动代码:Form_Shown
Form_Load
bool firstLoad = true; //flag to detect first form_shown
private void Form1_Load(object sender, EventArgs e)
{
//firstLoad = true;
//dowork(); //not execute initialization code here (postpone it to form_shown)
}
private void Form1_Shown(object sender, EventArgs e)
{
if (firstLoad) //simulate Form-Load
{
firstLoad = false;
dowork();
}
}
void dowork()
{
var f = File.OpenRead(@"D:\NoSuchFile756.123"); //this cause an exception!
}
评论