Simple_Code
Simple_Code

Reputation: 40

How to include custom font to my windows Form C# program

I am working on a program and I want custom font for labels and buttons I searched a lot to find solution I tried with this code but it works only with Home form if I move the font to another form program working for maybe 5 seconds and stopped.

   [DllImport("gdi32.dll")]

   public static extern IntPtr AddFontMemResourceEx(IntPtr pbfont, uint cbfont,
                   IntPtr pdv, [In] ref uint pcFonts);

    FontFamily ff;
    Font font;
    public void AllcoBold(Font f, Control c, float size)
    {
        FontStyle fs = FontStyle.Bold;
        c.Font = new Font(ff, size, fs);
    }
       
    public void loadBold()
    {
        byte[] fontArray = Counter.Properties.Resources.TheSans;
        int datalength = Counter.Properties.Resources.TheSans.Length;
        IntPtr ptrData = Marshal.AllocCoTaskMem(datalength);
        Marshal.Copy(fontArray, 0, ptrData, datalength);

        uint cFonts = 0;
        AddFontMemResourceEx(ptrData, (uint)fontArray.Length, IntPtr.Zero, ref cFonts);
        PrivateFontCollection pfc = new PrivateFontCollection();
        pfc.AddMemoryFont(ptrData, datalength);
        Marshal.FreeCoTaskMem(ptrData);
        ff = pfc.Families[0];
        font = new Font(ff, 15f, FontStyle.Bold);
    }
     
    private void LoadFontStyleBold()
    {
        AllcoBold(font, startBtn, 14);
    }

Upvotes: 1

Views: 767

Answers (1)

dr.null
dr.null

Reputation: 4670

Well, you need to create and destroy the PrivateFontCollection the right way. The loaded in-memory font's data should not be released as long as the Font(s) is/are in use. So, calling Marshal.FreeCoTaskMem(ptrData); is a common mistake in this context. Just dispose of the PrivateFontCollection instance when the container is disposing, in the FormClosed event if you have this code in a Form, or in the Dispose method implementation/override if you have it in a class that implements the IDisposable interface.

Accordingly, you should have something like:

public partial class YourForm : Form
{
    private PrivateFontCollection pfc;

    public YourForm()
    {
        InitializeComponent();

        // ...
    }

    protected override void OnFormClosed(FormClosedEventArgs e)
    {
        base.OnFormClosed(e);
        pfc?.Dispose();
    }

    public void AllcoBold(FontFamily ff, Control c, float size)
    {
        if (ff.IsStyleAvailable(FontStyle.Bold))
            c.Font = new Font(ff, size, FontStyle.Bold);
        else
            throw new NotSupportedException($"{ff.Name} does not support Bold style.");
    }

    public void LoadPfc()
    {
        if (pfc != null) return;

        uint cFonts = 0;
        byte[] fontArray = Counter.Properties.Resources.TheSans;
        IntPtr ptrData = Marshal.AllocCoTaskMem(fontArray.Length);

        Marshal.Copy(fontArray, 0, ptrData, fontArray.Length);
        AddFontMemResourceEx(ptrData, (uint)fontArray.Length, IntPtr.Zero, ref cFonts);

        pfc = new PrivateFontCollection();
        pfc.AddMemoryFont(ptrData, fontArray.Length);
    }
}

    private void LoadFontStyleBold()
    {
        AllcoBold(pfc.Families[0], startBtn, 14);
    }

    [DllImport("gdi32.dll")]
    private static extern IntPtr AddFontMemResourceEx(
        IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts);

I don't know about your implementation, maybe you just need a function that picks up a FontFamily from the collection, create and return a Font object?

private Font GetPrivateFont(string fontFamily, FontStyle style, int size)
{
    var ff = pfc.Families.FirstOrDefault(x => x.Name.ToLower() == fontFamily.ToLower());

    if (ff == null)
        throw new KeyNotFoundException($"The collection does not contain {fontFamily}.");

    if (!ff.IsStyleAvailable(style))
        throw new NotSupportedException($"{ff.Name} does not support {style} style.");

    return new Font(ff, size, style);
}

If it's all about one FontFamily in the collection, then you can omit the fontFamily param and .FirstOrDefault query. It's pfc.Families[0].

Upvotes: 3

Related Questions