I have a function below which installs a font (.ttf
) into Windows by copying it into the Windows font folder and then triggering the WM_FONTCHANGE
message. However, that font does not immediately become visible across Windows Explorer.
After running this, when I open Fonts through the Control Panel, my font does not show there. And when I open C:\Windows\Fonts\
it does not show there either.
However I can confirm that my .ttf
file is really there. Navigating here with the Command Prompt, I can see my font file. When I open the Character Map utility, my font is listed here. And the font is usable in my application. I have to restart explorer.exe
to get it to show within the Windows Explorer views. I've even tried running my app as administrator (elevated), and still no luck.
I thought the WM_FONTCHANGE
message was supposed to take care of this but apparently this is not doing the trick.
What am I missing in this Font Installation to make sure Windows is aware of it?
uses
SysUtils, ShlObj, ComObj, ActiveX;
function SystemDir(Handle: THandle; Folder: Integer): String;
var
R: HRESULT;
PIDL: PItemIDList;
Path: array[0..MAX_PATH] of Char;
begin
Result:= '';
R:= SHGetSpecialFolderLocation(Handle, Folder, PIDL);
if R = S_OK then begin
if SHGetPathFromIDList(PIDL, Path) then
Result:= StrPas(Path);
end;
end;
function InstallFont(Handle: THandle; const Filename: String): Boolean;
var
Dir, FN: String;
begin
Result:= False;
FN:= ExtractFileName(Filename);
Dir:= IncludeTrailingPathDelimiter(SystemDir(Handle, CSIDL_FONTS));
Result:= FileExists(Filename);
if Result then begin
Result:= CopyFile(PChar(Filename), PChar(Dir + FN), False);
end;
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
end;
Usage:
Result:= InstallFont(Application.Handle, 'C:\MyTestFont.ttf');
UPDATE
It was suggested in the comments of an answer below to install the font via the shell instead of Windows API. So, I wrote this function to essentially accomplish the same:
function InstallFont2(Handle: THandle; const Filename: String): Boolean;
var
R: HINST;
begin
Result:= False;
R:= ShellExecuteW(Handle, 'install', PWideChar(Filename), nil, nil, SW_HIDE);
Result:= R > 32;
end;
However this too is problematic. The return value is 31
(indicating an error) and when I call GetLastError
it tells me 1155
("No application is associated with the specified file for this operation.")
I also tried the particular resolution in the answer below, but to no avail. I both used AddFontResource
and written the appropriate registry key - while trying combinations of uninstalling/restarting/retrying with this font installation.
WM_FONTCHANGE
only notifies applications of a new font in the system, but it doesn't actually tell the system what the new font is.
Before sending WM_FONTCHANGE
you need to call AddFontResource
to add the font to the system font table. If you want the font to remain after a reboot, you also need to add an entry to the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts (see the documentation for AddFontResource
for more information).
I have just traced through exactly what Windows 7 does when it installs a font. Here is a summary:
" (TrueType)"
then it appends this.SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts
."basename_X.ttf"
where X is in hexadecimal. So e.g. if "myfont_1.ttf"
through "myfont_9.ttf"
already exist, then it will try "myfont_A.ttf"
next.AddFontResourceW
on the target path.SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts
based on the "(TrueType)"-qualified name of your font whose value is the target filename without path.FID
.Sleep
.PostMessageW(HWND_BROADCAST, WM_SETTINGSCHANGE, NULL, L"fonts")
PostMessageW(HWND_BROADCAST, WM_FONTCHANGE, NULL, NULL)
SHGetSpecialFolderLocation(CSIDL_FONTS)
and then passes the resulting IDLIST
into SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, idlist, NULL)
.I suspect it is these latter three that are crucial in getting the system to recognize the new font in other applications and in the Fonts folder.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With