SafeFileHandle.Close抛出exception,但句柄有效且有效

我在WPF应用程序中遇到自定义游标的问题。 我使用以下代码来创建Cursor对象:

 [DllImport("user32.dll")] private static extern IntPtr CreateIconIndirect(ref IconInfo icon); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo); private static Cursor CreateCursor(string cursorName, System.Drawing.Bitmap bmp, int xHotspot, int yHotspot, out SafeFileHandle handle) { IconInfo tmp = new IconInfo(); GetIconInfo(bmp.GetHicon(), ref tmp); tmp.xHotspot = xHotspot; tmp.yHotspot = yHotspot; tmp.fIcon = false; IntPtr ptr = CreateIconIndirect(ref tmp); handle = new SafeFileHandle(ptr, true); if (handle.IsClosed) { return null; } Cursor cur = CursorInteropHelper.Create(handle); return cur; } 

当我关闭我的应用程序并且GC开始拾取垃圾时,它会引发exception:

 System.Runtime.InteropServices.SEHException was unhandled Message=External component has thrown an exception. Source=mscorlib ErrorCode=-2147467259 StackTrace: at Microsoft.Win32.Win32Native.CloseHandle(IntPtr handle) at Microsoft.Win32.SafeHandles.SafeFileHandle.ReleaseHandle() at System.Runtime.InteropServices.SafeHandle.InternalDispose() at System.Runtime.InteropServices.SafeHandle.Dispose(Boolean disposing) at System.Runtime.InteropServices.SafeHandle.Dispose() at System.Windows.Input.Cursor.Finalize() InnerException: 

我通过在if (handle.IsClosed)上放置一个断点并使用立即窗口调用handle.Close()做了一些进一步的调查。 一些SafeFileHandle的关闭很好,其他人抛出相同的exception – 在创建句柄后立即执行。

只是为了让事情变得有趣,手柄本身工作得很好。 IsInvalid为false, IsClosed为false,并且显示游标。 只是有些句柄永远不会被关闭。

因为我从不打算手动关闭句柄,并且只有在应用程序关闭时完成Cursor对象的过程中才会关闭它们,我可能只能忽略它们。 我没有在VS2010之外尝试过Release版本,我不知道是否会导致出现崩溃对话框。 但即使我可以忽略它们,它仍然是凌乱的。

所以基本上我正在寻找关于这里可能出现什么问题的任何信息,在哪里寻找尝试和调试这一切……一切似乎都在本机代码或GC中,我无法调试其中任何一个。

您将从CreateIconIndirect返回的HICON包装在SafeFileHandle中,在释放时,它会调用HICON上的CloseHandle而不是所需的DestroyIcon 。 不要将HICON包装在SafeFileHandle ,而是包含在自己的专用SafeHandle

 class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid { [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool DestroyIcon( [In] IntPtr hIcon); private SafeIconHandle() : base(true) { } public SafeIconHandle(IntPtr hIcon) : base(true) { this.SetHandle(hIcon); } protected override bool ReleaseHandle() { return DestroyIcon(this.handle); } }