一、主要目的
目的是在Windows系统中安装字体文件。具体功能包括:
-
将字体文件复制到系统的字体目录(
Fonts文件夹)。 -
加载字体到当前会话。
-
通知其他运行的程序字体已更新。
-
在注册表中记录字体信息,以便系统识别和管理。
二、实现程序
import os
import shutil
import ctypes
from ctypes import wintypes
import sys
import time
import winreg
user32 = ctypes.WinDLL('user32', use_last_error=True)
gdi32 = ctypes.WinDLL('gdi32', use_last_error=True)
FONTS_REG_PATH = r'Software\Microsoft\Windows NT\CurrentVersion\Fonts'
HWND_BROADCAST = 0xFFFF
SMTO_ABORTIFHUNG = 0x0002
WM_FONTCHANGE = 0x001D
GFRI_DESCRIPTION = 1
GFRI_ISTRUETYPE = 3
if not hasattr(wintypes, 'LPDWORD'): wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD)
user32.SendMessageTimeoutW.restype = wintypes.LPVOID
user32.SendMessageTimeoutW.argtypes = (
wintypes.HWND, # hWnd
wintypes.UINT, # Msg
wintypes.LPVOID, # wParam
wintypes.LPVOID, # lParam
wintypes.UINT, # fuFlags
wintypes.UINT, # uTimeout
wintypes.LPVOID) # lpdwResult
gdi32.AddFontResourceW.argtypes = (wintypes.LPCWSTR,) # lpszFilename
gdi32.GetFontResourceInfoW.argtypes = (
wintypes.LPCWSTR, # lpszFilename
wintypes.LPDWORD, # cbBuffer
wintypes.LPVOID, # lpBuffer
wintypes.DWORD) # dwQueryType
def resource_path(relative_path):
"""获取资源文件的绝对路径"""
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
def install_font(src_path):
# copy the font to the Windows Fonts folder
dst_path = os.path.join(os.environ['SystemRoot'], 'Fonts',os.path.basename(src_path))
print("源路径: "+src_path)
print("目标路径: "+dst_path)
shutil.copy(src_path, dst_path)
# load the font in the current session
if not gdi32.AddFontResourceW(dst_path):
os.remove(dst_path)
raise WindowsError('AddFontResource failed to load "%s"' % src_path)
# notify running programs
user32.SendMessageTimeoutW(HWND_BROADCAST, WM_FONTCHANGE, 0, 0,SMTO_ABORTIFHUNG, 1000, None)
# store the fontname/filename in the registry
filename = os.path.basename(dst_path)
fontname = os.path.splitext(filename)[0]
# try to get the font's real name
cb = wintypes.DWORD()
if gdi32.GetFontResourceInfoW(filename, ctypes.byref(cb), None,GFRI_DESCRIPTION):
buf = (ctypes.c_wchar * cb.value)()
if gdi32.GetFontResourceInfoW(filename, ctypes.byref(cb), buf,GFRI_DESCRIPTION):
fontname = buf.value
is_truetype = wintypes.BOOL()
cb.value = ctypes.sizeof(is_truetype)
gdi32.GetFontResourceInfoW(filename, ctypes.byref(cb),ctypes.byref(is_truetype), GFRI_ISTRUETYPE)
if is_truetype: fontname += ' (TrueType)'
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, FONTS_REG_PATH, 0,winreg.KEY_SET_VALUE) as key:
winreg.SetValueEx(key, fontname, 0, winreg.REG_SZ, filename)
# 主程序
if __name__ == "__main__":
start_time = time.time()
font_path = resource_path('SourceHanSansSC-Regular.otf') # 安装思源黑体
print("字体安装中,请稍等...")
# 安装字体
install_font(font_path)
end_time = time.time()
print("总共运行 %d 秒" % (end_time - start_time))
time.sleep(1)
采用pyinstaller打包成单个EXE程序,注意字体文件SourceHanSansSC-Regular.otf要和该py文件放置在同目录下。打包命令:
pip install pyinstaller
pyinstaller --onefile --add-data="SourceHanSansSC-Regular.otf;." .\InstallerFront.py
三、程序说明
代码分为以下几个主要部分:
1. 导入模块:引入必要的系统模块和Windows API相关库。
2. Windows API配置:定义和配置与字体操作相关的Windows API函数和常量。
3. 辅助函数:提供资源路径解析功能。
4. 核心功能函数:实现字体安装的核心逻辑。
5. 主程序:调用核心功能函数完成字体安装。
(1) 导入模块
- os、shutil:用于文件路径操作和文件复制。
- ctypes、wintypes:调用Windows API,与系统底层交互。
- winreg:操作Windows注册表,记录字体信息。
- sys、time:用于资源路径解析和计时。
(2)Windows API配置
- user32和gdi32:通过ctypes加载Windows动态链接库(DLL),用于调用字体相关的API函数。
- AddFontResourceW:加载字体文件到当前会话。
- GetFontResourceInfoW:获取字体文件的详细信息(如字体名称、是否为TrueType字体)。
- SendMessageTimeoutW:广播消息通知其他程序字体已更新。
- 常量和参数类型:定义了Windows消息类型(如WM_FONTCHANGE)和API函数的参数类型。
(3)辅助函数
- resource_path:
- 功能:解析资源文件的绝对路径。
- 逻辑:优先尝试从sys._MEIPASS(PyInstaller打包时的临时目录)获取路径,否则使用当前目录。
(4)核心功能函数
- install_font:
- 复制字体文件:将字体文件从源路径复制到系统的Fonts目录。
- 加载字体:使用AddFontResourceW加载字体到当前会话。如果失败,删除复制的文件并抛出异常。
- 通知其他程序:通过SendMessageTimeoutW广播WM_FONTCHANGE消息,通知其他程序字体已更新。
- 注册字体信息:使用GetFontResourceInfoW获取字体的真实名称和类型(如TrueType)。在注册表HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts中记录字体名称和文件名。
(5)主程序
- 功能:
- 调用resource_path获取字体文件的路径。
- 调用install_font安装字体。
- 输出安装成功信息和运行时间。
1865

被折叠的 条评论
为什么被折叠?



