I'm having a problem with custom cursors in a WPF application. I use the following code to create the Cursor
objects:
[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:
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.
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.
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.
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.
You're wrapping the
HICON
returned fromCreateIconIndirect
in aSafeFileHandle
which, on releasing, callsCloseHandle
on theHICON
instead of the neededDestroyIcon
. Don't wrapHICON
inSafeFileHandle
but instead in an own, specializedSafeHandle
: