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.