前言

因为自己写了一个框架,需要安装字体,但是找了很多例子都达不到理想的效果,琢磨了两天自己折腾出来了~~~
值得注意的是需要管理员权限~

代码

代码回复可见

此处内容需要评论回复后(审核通过)方可阅读。

参考

文献1

无论是安装一些系统字体还是自定义的字体文件,本方法都是适用的。需要注意的是目前网络上介绍的使用AddFontResource实现安装字体,但是仅仅对本次设置有效,重启之后字体还是会消失。使用本文方法可永久实现字体的安装。

看看MSDN中关于安装字体的介绍:

To install unique hidden font resources follow these steps:

1 Copy the TrueType font file to a temporary file with a unique filename such as "ttfont01.ttf" that can be owned by the instance of the application.

2、 Call the CreateScalableFontResource() function to create a uniquely named temporary hidden font resource file that can also be owned by the instance of the application.

3、Call the AddFontResource() function to install this uniquely named font resource file for this instance of the application.
4、Use the font in the application as desired.

5 When the instance of the application terminates or is otherwise finished with the font file, it should uninstall the font resource by calling the RemoveFontResource() function until it fails.

6 Lastly, the instance of the application should delete the temporary font resource file and the temporary TrueType font file that it created.

根据介绍,使用Delphi来实现:

procedure TForm11.Button12Click(Sender: TObject);
var
  sysDir, sFontFileName, sFontName, sFontDir, sFOTFile: string;
  ssourceDir: string;
  reg: TRegistry;
begin
  sFontFileName := 'msyh.ttf';//测试字体(微软雅黑)
  sysDir := GetWinDir;
  sFontDir := sysDir + '\Fonts\';
  sFOTFile := sFontDir + ChangeFileExt(sFontFileName, '.FOT');
  ssourceDir := ExtractFilePath(ParamStr(0)) + sFontFileName;
  //将字体文件复制到系统Fonts目录下
  CopyFile(PChar(ssourceDir), PChar(sFontDir+ sfontfileName), false);
  //创建字体资源文件
  CreateScalableFontResource(0, PChar(sFOTFile), PChar(sFontFileName), PChar(sFontDir));
  //添加字体资源
  AddFontResource(PChar(sFOTFile));
  //新增注册表项
  reg := TRegistry.Create;
  reg.RootKey := HKEY_LOCAL_MACHINE;
  try
    if reg.OpenKey('\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts', false) then
    begin
      if not reg.ValueExists('微软雅黑 (TrueType)') then
        reg.WriteString('微软雅黑(TrueType)', sFontFileName);
    end;
  finally
    reg.Free;
  end;
  //通知系统更新字体列表
  PostMessage(HWND_BROADCAST,  WM_FONTCHANGE,  0,  0);
end;

文献2

我笔记本使用的是win7系统,开发的duilib程序一直都使用微软雅黑字体,昨天在xp系统下测试时发现由于xp下没有微软雅黑字体而导致duilib使用了默认的宋体字,瞬间感觉界面不协调了。解决这个问题的方法就是让程序自带自己使用的字体,并且在运行时加载这个字体。以前从来没关心过这个问题。

比较简单的方法就是在程序运行时把字体文件拷贝到系统的Fonts目录下,让系统自动安装这个字体,但是这样就会修改系统的文件,这可能并不是用户需要的东西。翻了翻MSDN得知了AddFontResource和CreateScalableFontResource这两个API,使用他们可以让程序加载任意路径的字体而不必拷贝到系统路径。于是写了一个AddFont类来加载一个字体,代码如下:

#pragma once
 
#ifdef UNICODE
typedef wstring tstring;
#else
typedef string    tstring;
#endif
 
class CAddFont
{
public:
    CAddFont(void);
    ~CAddFont(void);    
       /*
        * @param filePath:字体文件相对本程序的路径,不需要加前缀\\,和后缀名
    * @param fontName:字体的名称,如宋体,微软雅黑
        */
    bool AddFont(LPCTSTR szfilePath, LPCTSTR szFontName);
 
    LPCTSTR GetFontName() const;
private:
    tstring     m_strFilePath;
    tstring     m_strFontName;
};
#include "duilib.h"
// duilib.h中已经包含如下头文件
// #include "Windows.h"
// #include "string"
// #include "tchar.h"
// using namespace std;
#include "AddFont.h"
 
 
CAddFont::CAddFont(void)
{
    TCHAR szCurrentPath[MAX_PATH] = {0};
    GetCurrentDirectory(MAX_PATH, szCurrentPath);
    m_strFilePath = szCurrentPath;
    m_strFilePath += _T("\\");
}
 
 
CAddFont::~CAddFont(void)
{
    wstring strFont = m_strFilePath;
    wstring strFontPath = m_strFilePath;
    strFont += _T(".FOT");
    strFontPath +=  _T(".TTF");
 
    RemoveFontResource(strFontPath.c_str());
    DeleteFile(strFont.c_str());
}
 
bool CAddFont::AddFont(LPCTSTR szfilePath, LPCTSTR szFontName)
{
    m_strFilePath += szfilePath;
 
    wstring strFont = m_strFilePath;
    wstring strFontPath = m_strFilePath;
    strFont += _T(".FOT");
    strFontPath +=  _T(".TTF");
 
    BOOL bResult = CreateScalableFontResource(0,  strFont.c_str(),  strFontPath.c_str(),  NULL);  
    if (bResult == FALSE)
    {
        DUI__Trace(_T("错误码为:%d"), GetLastError()); //这里使用了duilib自带的调试函数
        ::MessageBox(NULL, _T("失败"), _T("提示"), 0);  //实际使用时建议注释此行代码
        return false;
    }
 
    int nResult = AddFontResource(strFontPath.c_str());
    if (nResult == 0)
    {
        ::MessageBox(NULL, _T("失败"), _T("提示2"), 0);  //实际使用时建议注释此行代码
        return false;
    }
 
    ::SendMessage(HWND_BROADCAST,WM_FONTCHANGE,0,0);
    m_strFontName = szFontName;
 
    return true;
}
 
LPCTSTR CAddFont::GetFontName() const
{
    return m_strFontName.c_str();
}

使用起来很简单,声明一个CAddFont变量。然后调用AddFont方法就可以了(需要注意的就是,应该在窗体创建之前就调用这个方法,因为窗体的创建过程中就会去解析xml并且创建字体对象,如果在窗体创建之后再调用,就已经迟了)

    CAddFont        addFont;

同时把”华文新魏“字体文件“STXINWEI.ttf"放到了Font目录里,然后在_tWinMain里加入这行代码就可以了._

_addFont.AddFont(_T("Font\\STXINWEI"), _T("华文新魏"));

这时就可以直接在编写xml文件时使用这个字体了,效果如下:

总结:

我这里只是简单随手的封装了一个CAddFont类来做可行性测试,实际这个类的代码写的并不好,读者可以封装一个更好的,支持添加并管理多个字体。实际还有两个更好的API叫AddFontResourceEx和AddFontMemResourceEx,以后有机会再写。如果代码有错误,请联系我

参考来源

参考1:https://codeantenna.com/a/QwYWy8ap3h

参考2:http://blog.csdn.net/zhuhongshu/article/details/39396223?spm=a2c6h.12873639.0.0.5b0278763MpkKm

参考3:http://www.office-cn.net/t/api/createscalablefontresource.htm

参考4:https://zouzhongliang.com/index.php/2018/06/18/createscalablefontresourcehanshu/

最后修改:2022 年 10 月 25 日
如果觉得我的文章对你有用,请随意赞赏~