将项目从.NET 3.5迁移到.NET 4.0:突然释放句柄失败

3
我刚刚将我的项目所针对的框架从.NET 3.5更改为.NET 4.0,以便享受新功能。但现在当我启动程序时,我收到以下提示:
“一个类型为'BitmapHandle'的SafeHandle或CriticalHandle未能正确释放值为0xB605123D的句柄。这通常表示该句柄是通过其他手段不正确释放的(例如使用DangerousGetHandle提取句柄并直接关闭它或建立另一个SafeHandle)。"
但我甚至不知道从哪里开始寻找原因,因为我没有获得任何更多信息,在3.5上一切都很好。

我在升级到4.0版本后也遇到了这个错误。你找到解决方案了吗? - joerage
3
我发现在我的情况下与启动画面有关。如果我不放置启动画面,错误就会消失。 - joerage
你说得对,我也是一样。虽然很奇怪...但我暂时移除了启动画面。 - metacircle
我决定关闭“Release Handle Failed”异常:http://msdn.microsoft.com/zh-cn/library/d21c150d.aspx - joerage
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上报告错误,本问答的链接应该足够。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接