Installing truetype fonts

I found some old threads about loading/installing fonts that weren’t in the system so that the running app could make use of them.
I tried the MBS function FolderItem.FontActivateMBS() but I get an error “1” (Windows system error). I don’t know if current versions of Windows aren’t compatible with this or if there are other ways to do this now.

Any advice would be appreciated.

Copy the TTF files to %SystemRoot%\Fonts

Usually it is C:\WINDOWS\Fonts

Last I knew FontActivateMBS to temporarily use your own bundled fonts was broken after 2019. I have a project that’s stuck in 2019 for that reason.

I was afraid of that. Thanks for the info.

Looks like that isn’t writable for a standard user.
I would need to either load the font local to my application or get permission to copy the fonts in.

I don’t know how to request permission to write to the folder in code. Any tips?

Innosetup will install a font happily if you bundle it as part of your installer.

1 Like

I would like to distribute the app without needing an installer (as an option)

Raise Administrative permissions for that.

can I do that programmatically or do I need to have the application run as admin?

Off topic, but

I would like to distribute the app without needing an installer

If you want to distribute to someone who is not a co-worker or friend, you will need an installer, and almost probably codesigning.
I’ll not labour the point further though… let’s explore the original question.

Alright, I was texted off line about this too (ツ)

I didn’t want to start a tangent discussion. I know I’ll be installing the app with an installer. What I should have said is that I don’t want to rely on the installer alone to install the fonts.
I have a very real reason for this, but there is no need to discuss it here.

Best scenario would be to enable the font local to my application.
I’ll settle for installing it on-the-fly if it isn’t in the font directory (or has been removed).

Kind of both?

Create a helper font installer in Xojo with raised privileges (it will ask permission for the user when you run it)

In a less secure scenario your app could ask admin privileges right from the start and handle fonts by itself.

The worst case scenarios are cases where the user have no permission to install fonts and no rights to invoke admin level.

1 Like

Not au fait with Powershell, but there may be something useful here:

https://4sysops.com/archives/install-fonts-with-a-powershell-script/

1 Like

thanks guys.
I also emailed Christian to see if his function can come back to life…

1 Like

I use this code to temporarily install fonts (windows 10):

Public Sub TemporarilyInstallFont(fontFile as FolderItem, privateFont as Boolean = true)
#if TargetWindows

Soft Declare Sub AddFontResourceExW Lib "Gdi32" ( filename as WString, flags as Integer, reserved as Integer )
Soft Declare Sub AddFontResourceA Lib "Gdi32" ( filename as CString )
Soft Declare Sub AddFontResourceW Lib "Gdi32" ( filename as WString )

Const FR_PRIVATE = &h10

if privateFont and System.IsFunctionAvailable( "AddFontResourceExW", "Gdi32" ) then
  // If the user wants to install it as a private font, then we need to
  // use the Ex APIs.  Otherwise, use the regular APIs.  We know
  // that AddFontResourceEx is available in Win2k and up, so if
  // the private flag is specified, we have to check to make sure
  // we can load the API as well.  We won't bother with the A
  // version of the call since we know the W version will be there.
  AddFontResourceExW( fontFile.ShellPath, FR_PRIVATE, 0 )
else
  // The user wants to install it as a public font, or they are running
  // on an OS without the ability to make private fonts
  if System.IsFunctionAvailable( "AddFontResourceW", "Gdi32" ) then
    AddFontResourceW( fontFile.ShellPath )
  else
    AddFontResourceA( fontFile.ShellPath )
  end if
end if

#else

#pragma unused fontFile
#pragma unused privateFont

#endif
End Sub

and this code to disinstall them:

Public Sub UninstallTemporaryFont(fontFile as FolderItem)
#if targetWindows

Soft Declare Sub RemoveFontResourceExW Lib "Gdi32" ( filename as WString, flags as Integer, reserved as Integer )
Soft Declare Sub RemoveFontResourceA Lib "Gdi32" ( filename as CString )
Soft Declare Sub RemoveFontResourceW Lib "Gdi32" ( filename as WString )

Const FR_PRIVATE = &h10

if System.IsFunctionAvailable( "RemoveFontResourceExW", "Gdi32" ) then
  RemoveFontResourceExW( fontFile.ShellPath, FR_PRIVATE, 0 )
end if

if System.IsFunctionAvailable( "RemoveFontResourceW", "Gdi32" ) then
  RemoveFontResourceW( fontFile.ShellPath )
else
  RemoveFontResourceA( fontFile.ShellPath )
end if

#else

#pragma unused fontFile

#endif
End Sub

1 Like

Cool. I’ll give this a shot.
Thank you!

Our MBS function just calls AddFontResourceExW!?

We return 1 if the function failed as AddFontResourceExW returns 0 to report 0 fonts added.

I’ll change my code to also fall back on AddFontResourceW function.

This appears to work great.
Thank you!

Glad it worked for you too.
But to be fair, thanks go to “Windows Functionality Suite” which long ago provided for it.

I’m not familiar with that.
Thanks for the information.