3

我刚刚将项目的目标框架从 .NET 3.5 更改为 .NET 4.0,以从新功能中受益。但是现在当我开始我的程序时,我得到:

“BitmapHandle”类型的 SafeHandle 或 CriticalHandle 未能正确释放值为 0xB605123D 的句柄。这通常表明句柄通过其他方式被错误地释放(例如使用 DangerousGetHandle 提取句柄并直接关闭它或围绕它构建另一个 SafeHandle。)

但我什至不知道从哪里开始寻找原因我没有得到更多信息,在 3.5 上一切都很好。

4

1 回答 1

3

这是 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 的链接就足够了。

于 2015-10-11T07:40:52.103 回答