获取 Windows 系统默认字体和对应的字体文件
自 Windows Vista 和 Windows Server 2008 开始,操作系统界面默认的字体为 Segoe UI ,而 Windows XP 及之前的系统界面默认字体为 Tahoma 。不过 Segoe UI 字体的字形并不包含包括汉字在内的东亚文字。中文版 Windows 使用微软雅黑作为默认中文字体。
其他语言的默认字体见下表:
语言 | 字体 |
---|---|
简体中文 | Microsoft YaHei UI |
繁体中文 | Microsoft JhengHei UI |
日文 | Yu Gothic UI |
韩文 | Malgun Gothic |
希伯来文 | Gisha |
泰文 | Leelawadee |
不过相较于查表获取 Windows 系统的默认字体,使用 Windows API 来获取当前系统的默认字体会更加可靠。
获取 Windows 系统默认字体
本文介绍有两种方法来获取 Windows 系统默认字体。第一种方法仅支持 Windows Vista 和 Windows Server 2003 及以上版本的 Windows 系统。第二种方法可以适用于 Windows XP 系统及更低版本的系统,但是没有实际测试过。
方法一
使用 GetThemeFont
API 来获取系统默认字体:
C++#include <windows.h>
#include <uxtheme.h>
#include <vssym32.h>
#include <stdio.h>
#pragma comment(lib, "uxtheme")
int main()
{
LOGFONTW lf = { 0 };
HTHEME hTheme = OpenThemeData(0, VSCLASS_TEXTSTYLE);
if (hTheme)
{
if (SUCCEEDED(GetThemeFont(hTheme, 0, TEXT_BODYTEXT, 0, TMT_FONT, &lf)))
{
wprintf(L"System default font name is \"%ls\"\n", lf.lfFaceName);;
}
CloseThemeData(hTheme);
}
return 0;
}
方法二
使用 SystemParametersInfo
API 来获取系统默认字体:
C++#include <windows.h>
#include <stdio.h>
int main()
{
LOGFONTW lf = { 0 };
if (SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(LOGFONTW), &lf, 0))
{
wprintf(L"System default font name is \"%ls\"\n", lf.lfFaceName);
}
return 0;
}
获取对应的字体文件
Windows 似乎没有提供 API 来找到字体对应的字体文件。不过我们可以在注册表路径 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts
下找到系统所有的字体和对应的字体文件名。
Windows 9X/Me 的注册表路径为
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Fonts
。不过对于这些上个世纪的操作系统,除非特殊情况,通常可以不用考虑。
C++#include <windows.h>
#include <wchar.h>
#include <stdio.h>
BOOL GetFontFile(const wchar_t* fontName, wchar_t* fileName, size_t* fileNameSize)
{
constexpr auto REG_SUBKEY_FONTS = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
constexpr auto REG_SAM_DESIRED = KEY_READ | KEY_QUERY_VALUE;
constexpr auto FONT_NAME_SEPARATOR = L'&';
constexpr auto FONT_NAME_TERMINATOR = L'(';
constexpr auto FONT_NAME_SPACE = L' ';
BOOL result = FALSE;
HKEY fontsKey = NULL;
wchar_t valueName[MAX_PATH] = { 0 };
BYTE valueData[MAX_PATH] = { 0 };
DWORD valueNameSize = sizeof(valueName) / sizeof(wchar_t) - 1,
valueNameLength = valueNameSize,
valueType = 0,
valueDataSize = sizeof(valueData),
valueDataLength = valueDataSize,
index = 0,
fontNameLength = wcslen(fontName);
if (ERROR_SUCCESS != RegOpenKeyExW(HKEY_LOCAL_MACHINE, REG_SUBKEY_FONTS, 0, REG_SAM_DESIRED, &fontsKey)) {
return FALSE;
}
while (ERROR_SUCCESS == RegEnumValueW(fontsKey, index, valueName, &valueNameLength, NULL, &valueType, valueData, &valueDataLength)) {
if (REG_SZ != valueType || valueNameLength < fontNameLength) {
goto NEXT;
}
int fragmentLength, i, j;
const wchar_t *fragmentValueName;
for (i = 0, j = 0; i < valueNameLength; i++) {
if (FONT_NAME_SEPARATOR == valueName[i]) {
fragmentLength = FONT_NAME_SPACE == valueName[i - 1] ? i - j - 1 : i - j;
fragmentValueName = valueName + j;
if (fragmentLength == fontNameLength && 0 == wcsnicmp(fontName, fragmentValueName, fontNameLength)) {
goto SUCCESS;
}
i += FONT_NAME_SPACE == valueName[i + 1] ? 2 : 1;
j = i;
}
else if (FONT_NAME_TERMINATOR == valueName[i]) {
fragmentLength = FONT_NAME_SPACE == valueName[i - 1] ? i - j - 1 : i - j;
fragmentValueName = valueName + j;
if (fragmentLength == fontNameLength && 0 == wcsnicmp(fontName, fragmentValueName, fontNameLength)) {
goto SUCCESS;
}
break;
}
}
fragmentLength = i - j;
fragmentValueName = valueName + j;
if (fragmentLength == fontNameLength && 0 == wcsnicmp(fontName, fragmentValueName, fontNameLength)) {
goto SUCCESS;
}
NEXT:
valueNameLength = valueNameSize;
valueDataLength = valueDataSize;
index ++;
continue;
SUCCESS:
if (NULL != fileNameSize && *fileNameSize < valueDataLength) {
result = FALSE;
}
else {
wcsncpy(fileName, (wchar_t*)valueData, valueDataLength);
result = TRUE;
if (NULL != fileNameSize) {
*fileNameSize = valueDataLength;
}
}
break;
}
RegCloseKey(fontsKey);
return result;
}
函数 GetFontFile
用于获取字体对应的字体文件名:
C++BOOL GetFontFile(
[in] const wchar_t* fontName,
[out] wchar_t* fileName,
[in, out] size_t* fileNameSize
);
- 参数
fontName
字体名称。 - 参数
fileName
返回字体文件名。 - 参数
fileNameSize
表示fileName
的最大长度并返回文件名实际长度。如果参数值为NULL
,则不对fileName
进行数组越界检查。
如果函数执行成功则返回 TRUE
,否则返回 FALSE
。函数执行失败可能由于读取注册表失败、字体未找到、参数 fileName
可用长度不足。