【发布时间】:2013-11-22 13:56:28
【问题描述】:
我的 WPF 应用程序随机崩溃(但每天至少两次)遇到问题,在 Windows 应用程序日志中留下以下消息:
应用程序:AppName.exe 框架版本:v4.0.30319 说明:由于 IP xxxxxxxx (xxxxxxxx) 处的 .NET 运行时出现内部错误,进程已终止,退出代码为 80131506。
只是为您提供背景信息,此应用程序在运行 Windows Embedded Standard 2009 的嵌入式系统上运行,并且与另一个进程一起是设备上运行的唯一应用程序(即使资源管理器也被禁用,因为它不需要)。
经过反复试验,我隔离了触发错误的代码。它是一个安装在主窗口上的钩子,用于拦截 HWND 消息以了解监视器何时关闭或处于待机模式。 由于系统配备了触摸面板,我在显示器关闭时用面板覆盖了我的应用程序主窗口,因此当用户触摸显示器使其退出待机模式时,它不会错误地单击我的按钮之一主窗口。当面板本身收到“点击”事件时,它会关闭、消失,从而允许用户恢复正常操作。
下面是我如何实例化钩子和在拦截 hwnd 时调用的函数:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
WindowInteropHelper helper = new WindowInteropHelper(this);
HwndSource.FromHwnd(helper.Handle).AddHook(HwndSourceHookHandler);
}
private IntPtr HwndSourceHookHandler(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
handled = false;
if (msg == WM_SYSCOMMAND && wParam == (IntPtr)SC_MONITORPOWER)
{
if (lParam == (IntPtr)MONITOR_OFF || lParam == (IntPtr)MONITOR_STANDBY)
{
AppName.Shell.canvasStandBy.Visibility = System.Windows.Visibility.Visible;
}
}
return IntPtr.Zero;
}
如果我注释掉 Window_Loaded 位中的代码,则不会再发生崩溃... 您能否指出这段代码有什么问题,或者给我一个提示,让我知道另一种方法可以让用户在关闭时点击监视器不会到达底层主窗口?
提前感谢您的帮助:)
【问题讨论】:
-
ExecutionEngineException 和它们一样糟糕,你必须破坏内部 CLR 状态。通常是通过破坏 GC 堆。 sn-p 中没有任何内容可以轻松解释这一点。您可以考虑的替代方法是使用 Dispatcher.BeginInvoke() 以便在更合适的时间进行可见性分配。
-
@sthotakura 是的,我已经获得了几天前从微软提到的修补程序,将其应用于我的测试系统,但错误仍然存在:(
-
@HansPassant 我会尝试这样做,但我强烈怀疑这是否能解决问题,因为崩溃主要发生在显示器关闭数小时后(上次是在今天早上 4 点,并且上次我触摸屏幕打开它是在昨天下午 6 点左右..) 所以它不应该与发出可见性分配的时间有关,因为那时面板应该已经可见几个小时而且我是 100 % 确定当时没有人触摸屏幕 :)
-
好吧,我没有争论,我认为你也没有找到真正的原因。 GC 堆损坏很难诊断,您将在 Windbg 中盯着一个小型转储一段时间才能接近。使诊断变得如此困难的原因是堆损坏在程序崩溃之前很久就完成了。当然,当一个程序完全空闲并且没有收集垃圾时,那肯定是在 2 小时前发生的 :)