Icon.FromHandle:我应该处理它,还是调用DestroyIcon?

Har*_*lse 7 .net c# winapi icons idisposable

我使用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
}
Run Code Online (Sandbox Code Playgroud)

在离开using语句时,处理图标对象.

MSDN在Icon.FromHandle的描述中警告(点击查看):

使用此方法时,必须使用Win32 API中的DestroyIcon方法处置原始图标,以确保释放资源.

并在Icon.Dispose(点击查看)

释放此Icon使用的所有资源.

题:

Dispose()对象是否足够,或者我应该调用Dispose()和DestroyIcon,还是调用DestroyIcon而不是Disposing对象?

Dav*_*ave 7

我在这方面经历了无尽的悲伤 - 我一直在尝试为表单的图标(以及任务栏中的图标)设置动画而不泄漏资源。

当我处置图标(如 MSDN 上的建议)资源泄漏时,当我使用“DestroyIcon”时,所有后续更新都失败。下面的代码以正确的顺序显示了所有内容。

API声明:

[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);
Run Code Online (Sandbox Code Playgroud)

最后解决方案:

IntPtr iconHandle = dynamicBitmap.GetHicon();
Icon tempManagedRes = Icon.FromHandle(iconHandle);
this.Icon = (Icon)tempManagedRes.Clone();
tempManagedRes.Dispose();
DestroyIcon(iconHandle);
Run Code Online (Sandbox Code Playgroud)

还发布在这个问题中: Win32.DestroyIcon vs. Icon.Dispose


Ste*_*ens 6

由 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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,在 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

结论:在 Icon.FromHandle 之后,字段 ownHandle 为 false,因此 Dispose / FromHandle 不会调用 DestroyIcon

因此:如果你使用 Icon.FromHandle 创建一个图标,你将不得不 Dispose() 图标以及调用 DestroyIcon,正如备注部分所说


Han*_*ant 6

.NET Icon类非常笨拙,需要自己处理.SHFILEICON的MSDN文章没有任何关于它的内容,你必须调用DestroyIcon().Icon.FromHandle()的MSDN文章也是如此.你调用DestroyIcon的确切时刻也很重要,它必须延迟,直到某些代码已经复制了图标或者你不再需要图标并且通常会调用它的Dispose()方法.

请注意MSDN文章中的代码段,它显示了早期调用DestroyIcon()的场景.好的,在那个特定的情况下,因为它被分配给Form.Icon属性.一个角落的情况,肯定不是你想要做的.

处理此问题的唯一正确方法是覆盖Icon.FromHandle()的行为并强制对象获取本机图标句柄的所有权.这样当你处理它时它会自动调用DestroyIcon().这需要一个hack,允许你这样做的Icon构造函数是内部的.反思救援,你可以使用这篇帖子中的代码,注意GetConstructor()调用.通过编写一个这样做一百万次的小单元测试,开始感觉良好.如果你讨厌它,那么编写你自己的IDisposable包装器,这样你就可以处理图标 pinvoke DestroyIcon().