I'm having a problem with custom cursors in a WPF application. I use the following code to create the Cursor
objects:
我在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;
}
When I close my application and GC starts picking up the trash, it throws an exception:
当我关闭我的应用程序并且GC开始拾取垃圾时,它会引发异常:
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:
I did some further investigation by placing a breakpoint on if (handle.IsClosed)
and using the immediate window to call handle.Close()
. Some of the SafeFileHandle
's close just fine, others throw the same exception — immediately after the handle was created.
我通过在if(handle.IsClosed)上放置一个断点并使用立即窗口调用handle.Close()做了一些进一步的调查。一些SafeFileHandle接近正常,其他人抛出相同的异常 - 在创建句柄后立即执行。
And just to make things fun, the handles themselves work just fine. IsInvalid
is false, IsClosed
is false, and the cursors appear. It's just that some of the handles can never be closed.
只是为了让事情变得有趣,手柄本身工作得很好。 IsInvalid为false,IsClosed为false,并且显示游标。只是有些句柄永远不会被关闭。
As I never intend to close the handles manually, and they will only be closed during finalization of the Cursor
objects when the application closes, I might be able to just ignore them. I haven't tried a Release build outside VS2010 and I don't know if that will cause a crash dialog to appear. But even if I can ignore them, it's still messy.
因为我从不打算手动关闭句柄,并且只有在应用程序关闭时完成Cursor对象的过程中才会关闭它们,我可能只能忽略它们。我没有在VS2010之外尝试过Release版本,我不知道是否会导致出现崩溃对话框。但即使我可以忽略它们,它仍然是凌乱的。
So basically I'm looking for any info on what might be going wrong here, where to look to try and debug this... everything seems to be in native code or GC and I can't debug any of it.
所以基本上我正在寻找关于这里可能出现什么问题的任何信息,在哪里寻找尝试和调试这一切......一切似乎都在本机代码或GC中,我无法调试其中任何一个。
1 个解决方案
#1
16
You're wrapping the HICON
returned from CreateIconIndirect
in a SafeFileHandle
which, on releasing, calls CloseHandle
on the HICON
instead of the needed DestroyIcon
. Don't wrap HICON
in SafeFileHandle
but instead in an own, specialized SafeHandle
:
您将从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);
}
}
#1
16
You're wrapping the HICON
returned from CreateIconIndirect
in a SafeFileHandle
which, on releasing, calls CloseHandle
on the HICON
instead of the needed DestroyIcon
. Don't wrap HICON
in SafeFileHandle
but instead in an own, specialized SafeHandle
:
您将从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);
}
}