1

Im trying to get the privatefontcollection to work. But so far its not working, not in the sense of an error, just the font seen on screen is MS Sans Serif and not the Font im trying to load. so far i have tried two diffrent methods and neither seem to have worked for me.

First i tried:

 Public Function GetFontInstance(ByVal data() As Byte, ByVal Size As Single, ByVal Style As FontStyle) As Font
        Dim result As Font
        Try
            Dim pfc = New PrivateFontCollection
            'LOAD MEMORY POINTER FOR FONT RESOURCE
            Dim FontPtr As System.IntPtr = Marshal.AllocCoTaskMem(data.Length)
            'COPY THE DATA TO THE MEMORY LOCATION
            Marshal.Copy(data, 0, FontPtr, data.Length)
            'LOAD THE MEMORY FONT INTO THE PRIVATE FONT COLLECTION
            pfc.AddMemoryFont(FontPtr, data.Length)
            'FREE UNSAFE MEMORY
            'Marshal.FreeCoTaskMem(FontPtr)

            result = New Font(pfc.Families(0), Size, Style)
            pfc.Families(0).Dispose()
            pfc.Dispose()
        Catch ex As Exception
            'ERROR LOADING FONT. HANDLE EXCEPTION HERE
            MsgBox("Error in [GetFontInstance()]" & vbCrLf & ex.Message)
            result = New Font(FontFamily.GenericMonospace, 8)
        End Try
        Return result
    End Function

i called this function from the Print SubRoutine:

 Dim newFont As Font = GetFontInstance(My.Resources.OpenSans_Bold, 22, FontStyle.Bold)
  
e.Graphics.DrawString("Hello World", newFont, Brushes.Black, 50, 2)

but what i see in the printdocument print preview, is just MS Sans Serif type font. not the font i have loaded into my Resources.

I then tried this method:

 Dim sAppPath As String
        sAppPath = System.Windows.Forms.Application.StartupPath
        Dim fcollect As New PrivateFontCollection()
        fcollect.AddFontFile(sAppPath & "\OpenSans-Bold.ttf")
        Dim OpenSansFont As New Font(fcollect.Families(0), 50, FontStyle.Bold)

        e.Graphics.DrawString("Hello World", OpenSansFont, Brushes.Black, 50, 2)

again i got the same result

is there something I'm missing to get this to work. other questions asked about this seem to indicate this should just work.

I should mention that the end user will run the Application on a system admin locked PC, so the option to "install" the font wont be possible. Id need to make use of the font only while the application is running / when the subroutine gets called.

  • In the first example, the `pfc` object shouldn't be disposed of before the font `result` that the function returns, actually you're caliing the `'Marshal.FreeCoTaskMem(FontPtr)` line that you comment but in another way. In short, the `pfc` should be _alive_ as long as you need to use the loaded fonts. Move `'pfc` to be a class member and override the `OnLoad` method to create it, and override the `OnFormClosed` method to dispose of it. – dr.null Nov 14 '21 at 16:51
  • As for the second example, it should work, check the file path and use [another](https://www.1001fonts.com/) font to be sure. Also, see the [example](https://learn.microsoft.com/en-us/dotnet/desktop/winforms/advanced/how-to-create-a-private-font-collection?view=netframeworkdesktop-4.8) in docs. – dr.null Nov 14 '21 at 17:35
  • @dr.null i still seem to be having trouble getting this to work, so i moved pfc to be, ` Public pfc = New PrivateFontCollection` removed the twp disposed lines and moved them to the formclosing sub. when the code runs it shows the variable im loading the font into is of the name of the font and size, but the end result on screen is still MS sans serif. in regards to useing another font i did, i downloaded one, didnt install it and its rather cursive so i would know if it was working. im calling the font from my.resources.fontname. – Andy Andromeda Nov 14 '21 at 20:54
  • Which Framework are you on? And have you tried that different font with your second example. It should work. – dr.null Nov 14 '21 at 20:59
  • Target Framework is .Net 4.7.2 and yes iv tried the other font. – Andy Andromeda Nov 14 '21 at 21:09
  • ah.. I missed `PrintDocument` part, my bad. Then I don't think it gonna work with the `PrivateFontCollection`, to use the Font in the printing routines, it should be installed in your machine. Read the discussion in [this](https://stackoverflow.com/questions/22618745/drawing-text-using-font-from-file-not-working) post. – dr.null Nov 14 '21 at 21:42
  • @dr.null would it be possible to say take my subroutine that has all the e.graphics.draw commands (effectively what is laying out my document for printing) use a PrivateFontCollection, but save as an image and print the image? would this then allow my final printout to have the privatefontcollection? – Andy Andromeda Nov 19 '21 at 00:06
  • Yes you can do that. But the output's quality won't be that perfect. Better to install the fonts in your users' machines and keep the code as is. The installer app can do that very easy. Installing fonts in your users systems is not reprehensible. Just notify them in the installer app. – dr.null Nov 19 '21 at 08:52
  • 1
    i cant install the fonts unfortunately as the users are using the application on a machine with locked admin privileges, and the application doesn't technically "install". i figured there would be a loss in image quality. i guess i will just stick to using similar looking fonts I know are installed. – Andy Andromeda Nov 20 '21 at 00:36
  • @dr.null I noticed one of the applications we use downloads fonts and they appear available in the windows 10 settings fonts screen, but not if you look in 'C:\windows\fonts. Does this mean it's loading the font as a private font collection? Or is there a way to temp install for current session. As I noticed once you log out and log back in. If the other application hasn't been used the font is not there in the windows 10 settings screen. – Andy Andromeda Nov 22 '21 at 04:17
  • You can install a temp Font for the current session through the [`AddFontResourceA`](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-addfontresourcea?redirectedfrom=MSDN) function. It won't be in the fonts folder because it is not registered in the system's registry. The temp font won't be there when you end the current session or restart the system. See [this](https://stackoverflow.com/a/21992546/14171304) answer, could work for you. Also read the other answers there. – dr.null Nov 22 '21 at 17:35
  • @dr.null I got this to work. I can use the AddFontResource it temp installs the font for use. The only problem i now have is i have to close my application and reopen it for the PrintDocument to actually be able to "use" / "see the font is installed". if you think i should ask as a new question i will. I'm currently using this `Ret = AddFontResource(Fonts_Source.ToString) Res = SendMessageTimeout(HWND_BROADCAST, WM_FONTCHANGE, IntPtr.Zero,SendMessageTimeoutFlags.SMTO_ABORTIFHUNG Or SendMessageTimeoutFlags.SMTO_NOTIMEOUTIFNOTHUNG, ` i thought would tell the app/windows the font can be used. – Andy Andromeda Dec 14 '21 at 12:14
  • Try first to replace the `SendMessageTimeout` with [`SendNotifyMessage`](https://www.pinvoke.net/default.aspx/user32/sendnotifymessage.html) function. `SendNotifyMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);`. If the result is the same, a new question is a good idea. – dr.null Dec 14 '21 at 13:10
  • yes sadly it made no difference. i will start a new question so i can post my code. – Andy Andromeda Dec 14 '21 at 13:59

0 Answers0