Reputation: 295
After much trial and error I have finally got my application to work with custom fonts on machines other than the development machine, however, I'm not sure which of the two methods I have gotten to work is the preferred way of doing things.
Either embedding the font as a resource and using Assembly.GetManifestResourceStream()
to push the font files data into unmanaged memory and adding it to a PrivateFontCollection
using AddMemoryFont()
like this:
(All error handling and superfluous code removed)
Imports System.Runtime.InteropServices
Imports System.Drawing.Text
Public Class FormExample
Private ReadOnly pfc As New PrivateFontCollection
Private f As Font
Private ReadOnly Bytes() As Byte = GetFontData(Reflection.Assembly.GetExecutingAssembly, "MyFont.ttf")
Private ReadOnly fontPtr As IntPtr = Marshal.AllocCoTaskMem(Me.Bytes.Length)
Private Sub FormExample_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Marshal.Copy(Me.Bytes, 0, Me.fontPtr, Me.Bytes.Length)
Me.pfc.AddMemoryFont(Me.fontPtr, Me.Bytes.Length)
Me.f = New Font(Me.pfc.Families(0), 14, FontStyle.Regular)
'Iterate through forms controls and set font where valid
SetFormsCustomFont(Me, Me.f)
End Sub
Private Sub FormExample_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
Marshal.FreeCoTaskMem(Me.fontPtr)
Me.pfc.Dispose()
End Sub
Private Function GetFontData(Asm As Assembly, Name As String) As Byte()
Using Stream As Stream = Asm.GetManifestResourceStream(Name)
Dim Buffer() As Byte = New Byte(CInt(Stream.Length - 1)) {}
Stream.Read(Buffer, 0, CInt(Stream.Length))
Return Buffer
End Using
End Function
End Class
Or by simply including the font with the application rather than embedding it as a resource and using PrivateFontCollection.AddFontFile()
:
Public Class FormExample2
Private ReadOnly pfc As New PrivateFontCollection
Private f As Font
Private Sub FormExample2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim fontFile As String = ".\Path\To\MyFont.ttf"
Me.pfc.AddFontFile(fontFile)
Me.f = New Font(Me.pfc.Families(0), 14)
'Iterate through forms controls and set font where valid
SetFormsCustomFont(Me, Me.f)
End Sub
Private Sub FormExample2_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
Me.pfc.Dispose()
End Sub
End Class
In both methods the font collections need to be kept around for the life of the form, and I have to repeat the code and have font objects for each form in the application so that I don't trample over the unmanaged memory.
Other than the fact that the second method gives users access to your font file, is there any other benefit to doing it the first way?
OR, is there another preferred way of doing this that I am unaware of?
Upvotes: 0
Views: 536