Question

Should I dispose each font in System.Drawing.FontFamily.Families property, which returns me an array of FontFamily class which implements IDisposable?

Should I dispose any other class instances or array of instances which also implement IDisposable in that rare cases when they are returned by a property accessor?

Was it helpful?

Solution

I looked at the code using Reflector, and I can tell you that when you access that property, a load of Font handles are being allocated using SafeNativeMethods.Gdip.GdipCloneFontFamily() for each font.

You should if it isn't too hard. If you do not, the finalizer will free the OS handle allocated for each font, but if there are a lot of fonts you don't really want to take a long time to dispose them. It could take an arbitrarily long time before the finalizer is called.

If you were accessing the Families[] property repeatedly, you could end up with a lot of unreleased OS handles which could cause problems.

Here's the Dispose() method for the FontFamily type:

private void Dispose(bool disposing)
{
    if (this.nativeFamily != IntPtr.Zero)
    {
        try
        {
            SafeNativeMethods.Gdip.GdipDeleteFontFamily(new HandleRef(this, this.nativeFamily));
        }
        catch (Exception exception)
        {
            if (ClientUtils.IsCriticalException(exception))
            {
                throw;
            }
        }
        finally
        {
            this.nativeFamily = IntPtr.Zero;
        }
    }
}

Note that you would be missing out on the call to GdipDeleteFontFamily() which would be freeing underlying the OS handle for the font.

(Sidenote: Microsoft's documentation for this kind of thing is very poor, because their sample code typically ignores the issue of disposing fonts.)

Here's the implementation of Families:

public FontFamily[] Families
{
    get
    {
        int numFound = 0x0;
        int status = SafeNativeMethods.Gdip.GdipGetFontCollectionFamilyCount(new HandleRef(this, this.nativeFontCollection), out numFound);
        if (status != 0x0)
        {
            throw SafeNativeMethods.Gdip.StatusException(status);
        }
        IntPtr[] gpfamilies = new IntPtr[numFound];
        int num3 = 0x0;
        status = SafeNativeMethods.Gdip.GdipGetFontCollectionFamilyList(new HandleRef(this, this.nativeFontCollection), numFound, gpfamilies, out num3);
        if (status != 0x0)
        {
            throw SafeNativeMethods.Gdip.StatusException(status);
        }
        FontFamily[] familyArray = new FontFamily[num3];
        for (int i = 0x0; i < num3; i++)
        {
            IntPtr ptr;
            SafeNativeMethods.Gdip.GdipCloneFontFamily(new HandleRef(null, gpfamilies[i]), out ptr);
            familyArray[i] = new FontFamily(ptr);
        }
        return familyArray;
    }
}

Note how it counts how many fonts there are, and then calls GdipCloneFontFamily() for each one and initialises a new FontFamily with the returned IntPtr.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top