Reputation: 40
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
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