安装字体并使Windows识别

时间:2015-02-24 03:29:11

标签: windows winapi fonts

下面有一个函数,通过将字体(.ttf)复制到Windows字体文件夹然后触发WM_FONTCHANGE消息,将字体(C:\Windows\Fonts\)安装到Windows中。但是,该字体不会立即在Windows资源管理器中显示。

运行此功能后,当我通过控制面板打开字体时,我的字体不会显示在那里。当我打开.ttf时,它也没有显示出来。

但是我可以确认我的explorer.exe文件确实存在。使用命令提示符在这里导航,我可以看到我的字体文件。当我打开字符映射实用程序时,我的字体列在这里。并且该字体在我的应用程序中可用。我必须重新启动WM_FONTCHANGE才能在Windows资源管理器视图中显示它。我甚至尝试以管理员身份运行我的应用程序(提升),但仍然没有运气。

我认为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; 消息本来应该照顾这个,但显然这不是伎俩。

我在此字体安装中缺少什么以确保Windows能够识别它?

Result:= InstallFont(Application.Handle, 'C:\MyTestFont.ttf');

用法:

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;

更新

以下答案的评论中建议通过shell而不是Windows API安装字体。所以,我写这个函数基本上完成了相同的事情:

31

然而,这也是有问题的。返回值为GetLastError(表示错误),当我调用1155时,它告诉我AddFontResource(“没有应用程序与此操作的指定文件关联。”

我也在下面的答案中尝试了特定的解决方案,但无济于事。我使用{{1}}并编写了相应的注册表项 - 同时尝试使用此字体安装卸载/重新启动/重试的组合。

2 个答案:

答案 0 :(得分:6)

WM_FONTCHANGE仅通知系统中新字体的应用,但它实际上并没有告诉系统新字体是什么。

在发送WM_FONTCHANGE之前,您需要调用AddFontResource将字体添加到系统字体表中。如果要在重新引导后保留字体,还需要在注册表项 HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Fonts 中添加一个条目(请参阅{{1}的文档}了解更多信息)。

答案 1 :(得分:0)

我刚刚准确地了解了Windows 7安装字体时的行为。这是一个摘要:

  • 如果该字体是真字体,并且其名称尚未以" (TrueType)"结尾,则将其附加。
  • 如果字体已经存在,可以将其卸载以便重新安装:
    • 它调用RemoveFontResourceW。
    • 描述字体的注册表项(如果有的话)将从SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts中删除。
  • 它将获取您要安装的文件名,如果Fonts目录中已经存在该文件名,则它将扫描唯一的文件名,方法是将1重复添加到计数器,然后格式化"basename_X.ttf",其中X是十六进制。所以例如如果"myfont_1.ttf""myfont_9.ttf"已经存在,则接下来将尝试"myfont_A.ttf"
  • 它将您提供的文件复制到它已标识的该免费文件名中。
  • 它在目标路径上调用AddFontResourceW
  • 它将根据您的字体的“(TrueType)”限定名称将一个条目写入SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts,其值是没有路径的目标文件名。
  • 它做了一件我还不太清楚的事情,创建了一个PropertyStore并在其中添加了一堆值。我不确定它对所得的属性存储到底有什么作用,但是将其称为FID
  • 通过调用Sleep等待2秒。
  • 它调用PostMessageW(HWND_BROADCAST, WM_SETTINGSCHANGE, NULL, L"fonts")
  • 它调用PostMessageW(HWND_BROADCAST, WM_FONTCHANGE, NULL, NULL)
  • 它调用SHGetSpecialFolderLocation(CSIDL_FONTS),然后将生成的IDLIST传递到SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, idlist, NULL)

我怀疑这后三个对使系统识别其他应用程序和“字体”文件夹中的新字体至关重要。