我刚刚将项目的目标框架从.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的链接应该足够了。

10-05 23:50