And here we go again, the same old story - corporate environment, users unable to install additional fonts. I find the font management in Windows pretty weak, all users are locked into the same setting, without any kind of possibility how to tailor it to their preferences. Until now that is!
What happens during font installation:
- Font file is copied to
%WINDIR%\Fontsdirectory - New font entry is created in registry
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fontsdescribing font's name and file. - Function AddFontResource is called, which updates the global font table.
Since the AddFontResource function doesn't require the font to reside in Windows Fonts directory neither the relevant entry in registry to exist, we can just call it with font placed anywhere. The following code illustrates how:
#include <windows.h>
#include <ctype.h>
char* lower(char *s)
{
char *result = (char *)malloc(strlen(s)+1);
result[strlen(s)] = '\0';
for (int i = strlen(s) - 1; i >= 0; i--)
{
result[i] = tolower(s[i]);
}
return result;
}
void processDirectory(char *initial, char *dir)
{
char *wildcard = (char *)malloc(strlen(initial) + strlen(dir) + 2);
memset(wildcard, 0, strlen(initial) + strlen(dir) + 2);
strcat(wildcard, initial);
strcat(wildcard, "\\");
strcat(wildcard, dir);
char *fulldir = (char *)malloc(strlen(wildcard));
strcpy(fulldir, wildcard);
strcat(wildcard, "\\*");
WIN32_FIND_DATA data;
HANDLE search = FindFirstFile(wildcard, &data);
if (search == INVALID_HANDLE_VALUE)
return;
do
{
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& (strcmp(data.cFileName, ".") != 0)
&& (strcmp(data.cFileName, "..") != 0))
{
processDirectory(fulldir, data.cFileName);
}
else if (!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
char *s = lower(data.cFileName);
if (strstr(s+strlen(s)-4, ".ttf") != 0)
{
int fontLength = strlen(fulldir) + strlen(data.cFileName) + 2;
char *font = (char*)malloc(fontLength);
memset(font, 0, fontLength);
strcat(font, fulldir);
strcat(font, "\\");
strcat(font, data.cFileName);
AddFontResource(font);
free(font);
}
free(s);
}
} while(FindNextFile(search, &data));
free(wildcard);
free(fulldir);
FindClose(search);
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
for (int i = 1; i < argc; i++)
processDirectory(argv[i], "");
}
else
processDirectory(".", "");
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
return 0;
}
Most of the code is dealing with string concatenation and not the real task at hand, but I didn't want to use C++ string to keep it nicely Win32 :)
What it actually does is that it takes a list of directories as arguments and goes recursively through all of them and every file ending with .ttf adds as a new font resource to the system. In case no directories are supplied as parameters, the current directory is used.
If you want to use it regularly, create a directory with your fonts and add to your Startup folder link to fontload.exe and give it as a parameter the name of your folder. Then after every computer start, your fonts get loaded automatically.

Please note:
- It takes quite a while to broadcast the notification that new fonts are available to all windows. The time is quite independent on amount of fonts installed and takes about twenty seconds on my computer.
- Some applications might be very unhappy about this, if you encounter crashes, it could be this program's fault. Although it works fine for me, doesn't mean it will work for you :).
- There is nothing preventing you from deleting the font files, which are loaded, so expect hilarious results upon doing so.
- This program doesn't care about font unloading. If you want to unload the fonts, just restart the computer or figure out, how to use the RemoveFontResource function
Source and binary version can be downloaded here - fontload.zip - 7kB.
Next time, we will use this knowledge to create a simple font viewer, which will pollute the global font table only on request :).
Obligatory thanks to Mark James for creating the amazing Silk icons.
