Icon.FromHandle:我应该处理它,还是调用DestroyIcon?
我使用Win32 SHGetFileInfo来获取属于某个文件的图标的句柄。 有很多描述如何执行此操作,也可以在stackoverflow上执行此操作,例如: 获取shell使用的图标
调用该函数后,您将拥有一个带有Icon图标句柄的结构。 使用静态方法Icon.FromHandle我可以将它转换为System.Drawing.Icon类的对象。 该类实现System.IDisposable。 正确的用法如下:
using (Icon icon = Icon.FromHandle(shFileInfo.hIcon)) { // do what you need to do with the icon }
在离开using语句时,将放置图标对象。
MSDN在Icon.FromHandle的描述中警告(点击查看) :
使用此方法时,必须使用Win32 API中的DestroyIcon方法处置原始图标,以确保释放资源。
并在Icon.Dispose(点击查看)
释放此Icon使用的所有资源。
题:
Dispose()对象是否足够,或者我应该调用Dispose()和DestroyIcon,还是调用DestroyIcon而不是Disposing对象?
OP增加。 这个答案有一个错误。 由于所有的评论,看到森林穿过树林变得苛刻。 因此我决定编辑这个答案。 (对不起,如果我冒犯了某人)
.net源代码在线: http : //referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Icon.cs,81a28d20524554ae
看看Icon.FromHandle:
public static Icon FromHandle(IntPtr handle) { IntSecurity.ObjectFromWin32Handle.Demand(); return new Icon(handle); } internal Icon(IntPtr handle) : this(handle, false) { } internal Icon(IntPtr handle, bool takeOwnership) { if (handle == IntPtr.Zero) { throw new ArgumentException(SR.GetString(SR.InvalidGDIHandle, (typeof(Icon)).Name)); } this.handle = handle; this.ownHandle = takeOwnership; }
请注意,在Icon.FromHandle之后,ownHandle为false。
我们来看看Dispose:
void Dispose(bool disposing) { if (handle != IntPtr.Zero) { DestroyHandle(); } } internal void DestroyHandle() { if (ownHandle) { SafeNativeMethods.DestroyIcon(new HandleRef(this, handle)); handle = IntPtr.Zero; } }
结论:在Icon.FromHandle之后,字段ownHandle为false,因此Dispose / FromHandle不会调用DestroyIcon
因此:如果你使用Icon.FromHandle创建一个Icon,你必须Dispose()Icon以及调用DestroyIcon,就像备注部分所说的那样
.NET Icon类非常笨拙,需要自己处理。 SHFILEICON的MSDN文章没有任何关于它的内容,你必须调用DestroyIcon()。 Icon.FromHandle()的MSDN文章也是如此。 你调用DestroyIcon的确切时刻也很重要,它必须延迟,直到某些代码已经复制了图标或者你不再需要这个图标并且通常会调用它的Dispose()方法。
请注意MSDN文章中的代码片段,它显示了早期调用DestroyIcon()的场景。 好的,在那个特定的情况下,因为它被分配给Form.Icon属性。 一个角落的情况,肯定不是你想要做的。
处理此问题的唯一正确方法是覆盖Icon.FromHandle()的行为并强制该对象获取本机图标句柄的所有权。 这样它在你处理时会自动调用DestroyIcon()。 这需要一个hack,允许你这样做的Icon构造函数是内部的 。 反思救援,你可以使用这篇post中的代码,注意GetConstructor()调用。 通过编写一次这样做一百万次的小unit testing,开始感觉良好。 如果你讨厌它,那么编写你自己的IDisposable包装器,这样你就可以处理图标并调用DestroyIcon()。
我在这个领域没有悲伤 – 我一直试图在不泄漏资源的情况下为表单的图标(以及任务栏中的图标)设置动画。
当我处理图标(如MSDN上建议的)资源泄露时,当我使用“DestroyIcon”时,所有后续更新都失败了。 下面的代码以正确的顺序显示所有内容。
API声明:
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = CharSet.Auto)] extern static bool DestroyIcon(IntPtr handle);
最后的解决方案:
IntPtr iconHandle = dynamicBitmap.GetHicon(); Icon tempManagedRes = Icon.FromHandle(iconHandle); this.Icon = (Icon)tempManagedRes.Clone(); tempManagedRes.Dispose(); DestroyIcon(iconHandle);
也发布在这个问题: Win32.DestroyIcon与Icon.Dispose