Search code examples
c#.netwinapiiconsidisposable

Icon.FromHandle: should I Dispose it, or call DestroyIcon?


I use Win32 SHGetFileInfo to get a handle to the icon belonging to a certain file. There are a lot of descriptions how to do this, also on stackoverflow, for instance: Get icons used by shell

After calling the function you have a struct with the handle to the Icon. Using the static method Icon.FromHandle I can convert it to an object of class System.Drawing.Icon. This class implements System.IDisposable. Proper usage would be like:

using (Icon icon = Icon.FromHandle(shFileInfo.hIcon))
{
    // do what you need to do with the icon
}

Upon leaving the using statement the icon object is disposed.

MSDN warns in the description of Icon.FromHandle (click to view):

When using this method, you must dispose of the original icon by using the DestroyIcon method in the Win32 API to ensure that the resources are released.

And in Icon.Dispose (click to view)

Releases all resources used by this Icon.

Question:

Is it enough to Dispose() the object, or should I call both Dispose() and DestroyIcon, or maybe call DestroyIcon instead of Disposing the object?


Solution

  • Addition by OP. There is an error in this answer. Because of all the comments it became harsh to see the forest through the trees. Hence I decided to edit this answer. (Sorry if I offended someone)

    The .Net source code is online: System.Drawing.Icon.cs

    Take a look at 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;
    }
    

    Note that after Icon.FromHandle() ownHandle is false.

    Let's look at Dispose():

    void Dispose(bool disposing)
    {
        if (handle != IntPtr.Zero)
        {
            DestroyHandle();
        }
    }
    
    internal void DestroyHandle()
    {
        if (ownHandle)
        {
            SafeNativeMethods.DestroyIcon(new HandleRef(this, handle));
            handle = IntPtr.Zero;
        }
    }
    

    Conclusion: After Icon.FromHandle, the field ownHandle is false, and thus Dispose / FromHandle won't call DestroyIcon

    Therefore: if you create an Icon using Icon.FromHandle you'll have to Dispose() the Icon as well as call DestroyIcon, just as the remarks section says