我刚刚将项目的目标框架从 .NET 3.5 更改为 .NET 4.0,以从新功能中受益。但是现在当我开始我的程序时,我得到:
“BitmapHandle”类型的 SafeHandle 或 CriticalHandle 未能正确释放值为 0xB605123D 的句柄。这通常表明句柄通过其他方式被错误地释放(例如使用 DangerousGetHandle 提取句柄并直接关闭它或围绕它构建另一个 SafeHandle。)
但我什至不知道从哪里开始寻找原因我没有得到更多信息,在 3.5 上一切都很好。
我刚刚将项目的目标框架从 .NET 3.5 更改为 .NET 4.0,以从新功能中受益。但是现在当我开始我的程序时,我得到:
“BitmapHandle”类型的 SafeHandle 或 CriticalHandle 未能正确释放值为 0xB605123D 的句柄。这通常表明句柄通过其他方式被错误地释放(例如使用 DangerousGetHandle 提取句柄并直接关闭它或围绕它构建另一个 SafeHandle。)
但我什至不知道从哪里开始寻找原因我没有得到更多信息,在 3.5 上一切都很好。
这是 WPF SplashScreen 类中的一个错误。在 .NET 4.6 BitmapHandle 中仍然存在一个 SafeHandle 类,它的ReleaseHandle()方法如下所示:
protected override bool ReleaseHandle()
{
return UnsafeNativeMethods.DeleteObject(handle);
}
这是非常正确的,它确保 GDI 位图对象无论发生什么都被正确销毁。该错误存在于SplashScreen.DestroyResources()方法中,它帮助太大了:
private void DestroyResources()
{
//...
if (_hBitmap != null && !_hBitmap.IsClosed)
{
UnsafeNativeMethods.DeleteObject(_hBitmap.MakeHandleRef(null).Handle);
_hBitmap.Close();
_hBitmap = null;
}
//...
}
两个电话DeleteObject,太多了。调试器有一个 MDA(托管调试助手)来监视此类错误,它会看到 ReleaseHandle() 失败并介入。您通常不会看到这一点,因为(不明智地)MDA 默认情况下是关闭的。调试 > 异常 > 托管调试助手 > ReleaseHandleFailed。取消勾选它以停止接收通知。
像这样的错误非常讨厌,它们打开了处理回收攻击的大门。然而,它实际上可被利用的几率非常低,Close() 调用紧跟 DeleteObject() 调用之后,位图并不是特别危险 :) 技术上可能发生事故,您必须让另一个线程同时创建 GDI 对象时间,这在 WPF 应用程序中并不经常发生。
您可以在 connect.microsoft.com 上提交错误,指向此 Q+A 的链接就足够了。