windows API 统计系统字体
最近工作中遇到一个需求,需要统计当前系统中包含的所有字体。在网上逛了一圈后发现了EnumFontFamiliesEx这个API好像就可以实现这个功能。这里将自己对这个API的理解做一个记录,算是对这块知识的一个总结吧。
API介绍
这里主要介绍的API就是EnumFontFamiliesEx以及它的回调函数EnumFontFamExProc。从MSDN的官方文档中可以看出,EnumFontFamiliesEx可以枚举出当前系统中符合特定字符集的所有字体。
EnumFontFamiliesEx的函数的原型如下:
int EnumFontFamiliesEx(
_In_ HDC hdc,
_In_ LPLOGFONT lpLogfont,
_In_ FONTENUMPROC lpEnumFontFamExProc,
_In_ LPARAM lParam,
DWORD dwFlags
);
在上面的参数中,hdc对应了设备上下文,可以直接根据GetDC得到。LPLOGFONT代表指向字体逻辑的指针,在进行字体遍历时,可以将该参数设置为NULL。lpEnumFontFamExProc回调函数地址,也就是EnumFontFamExProc这个函数的地址。lParam作为附加的参数用与字体信息一起传递给回调函数,本文中并未用到这个附加参数,因此直接设为0,。最后dwFlags未被使用,需要强制设置0。因此,在调用该函数时,其实就是将它所遍历到的字体信息传递给回调函数EnumFontFamExProc进行处理。既然这样,如果要统计当前系统中包含的所有字体,那么这个统计的操作就可以放在回调函数EnumFontFamExProc中进行(因为每进入一次回调函数EnumFontFamExProc,说明EnumFontFamiliesEx给它传入了一种系统字体)。既然需要在EnumFontFamExProc中处理统计逻辑,因此需要了解EnumFontFamExProc这个函数的原型。MSDN中给出了其标准的原型定义:
int CALLBACK EnumFontFamExProc(
const LOGFONT *lpelfe,
const TEXTMETRIC *lpntme,
DWORD FontType,
LPARAM lParam
);
其中,lpelfe就对应了当前处理的字体信息,但是LOGFONT这个结构体中并不包含需要的字体名称信息。为了解决这个问题,需要进行一次转型操作。如MSDN中所说,
To obtain additional information about the font, you can cast the result as an ENUMLOGFONTEX or ENUMLOGFONTEXDV structure.
将LOGFONT* 转型为ENUMLOGFONTEX *。 而根据MSDN中对ENUMLOGFONTEX这个结构体的描述
typedef struct tagENUMLOGFONTEX {
LOGFONT elfLogFont;
TCHAR elfFullName[LF_FULLFACESIZE];
TCHAR elfStyle[LF_FACESIZE];
TCHAR elfScript[LF_FACESIZE];
} ENUMLOGFONTEX, *LPENUMLOGFONTEX;
可以由elfFullName这个成员得到当前字体的名称。因此,统计字体名称就可以直接从这个结构体中的elfFullName获取。到这里,实现这样一个功能来统计当前系统中所有的字体对应的步骤就变得十分清晰的了。
1. 调用EnumFontFamiliesEx依次遍历当前系统上的每一种字体 2. 在EnumFontFamiliesEx遍历到其中一种字体时,会将字体的信息传递给回调函EnumFontFamExProc。此时,回调函数负责处理传过来的字体,并将这部分信息解析到ENUMLOGFONTEX中。 3. 在EnumFontFamiliesEx函数中,添加字体统计逻辑(其实很简单,就是将elfFullName这个字符串放入一个容器中保存)
在了解了本文的实现机制后,就可以实际动手来验证这个方案了。
验证实例
首先定义一个通用类来进行Windows系统下字体统计功能,它的定义如下
/************************************************************************/
/* file : 设计单独的类来进行统计本机字体操作
* author : Huagang Li
* date : 2014-8-25 21:40:49
* tips : 调用EnumFontFamiliesExProc回调函数遍历当前系统的所有字体
* blogs : http://www.cnblogs.com/lhglihuagang/
*/
/************************************************************************/ifndef _SYS_FONT_H
#define _SYS_FONT_Hinclude <windows.h>
include <string>
include <set>
//////////////////////////////////////////////////////////////////////////
// CWindowHelper 提供遍历统计Windows系统中字体的接口
class CWindowHelper {
public:
static std::set<std::wstring> sysFonts; // 用于在回调函数中保存当前遍历到的字体
static void GetSystemFonts();
static void ShowSysFonts(); private:
static enum emFindFont { STOP_FIND = 0, CONTINUE_FIND = 1 };
static int CALLBACK EnumFontFamiliesExProc( ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, int FontType, LPARAM lParam );
}; #endif
对应的接口实现如下:
#include "SysFonts.h"
#include <tchar.h> std::set<std::wstring> CWindowHelper::sysFonts; int CALLBACK CWindowHelper::EnumFontFamiliesExProc( ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, int FontType, LPARAM lParam )
{
if (NULL == lpelfe)
{
return emFindFont::STOP_FIND; // 返回0停止遍历
}sysFonts.insert( lpelfe</span>->elfFullName ); <span style="color: #008000">//</span><span style="color: #008000"> 将遍历中得到的字体存入容器保存</span>
<span style="color: #0000ff">return</span> emFindFont::CONTINUE_FIND; <span style="color: #008000">//</span><span style="color: #008000"> 返回1 代表继续进行下一轮遍历</span>
}
void CWindowHelper::GetSystemFonts()
{
HDC hdc = GetDC(NULL);
LOGFONT logFont = { 0, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, L"" };
::EnumFontFamiliesEx(hdc, &logFont, (FONTENUMPROC)EnumFontFamiliesExProc, 0, 0);
::ReleaseDC(NULL, hdc);
}void CWindowHelper::ShowSysFonts()
{
std::wstring strRes;
std::set<std::wstring>::const_iterator iter = sysFonts.begin();
while (iter != sysFonts.end())
{
strRes = strRes + (*iter) + L" ";
++iter;
}
::MessageBox(NULL, strRes.c_str(), _T("当前系统所有字体"), MB_OK);
}
这个类的核心接口为GetSystemFonts。按照前文的实现逻辑:首先调用EnumFontFamiliesEx来遍历每一种字体,在定义响应的回调函数EnumFontFamiliesExProc来处理传入的每一种字体信息,同时在回调函数的实现体中添加字体统计逻辑。这里需要注意的是:回调函数返回值必须非0.如果返回值为0,那么遍历将会结束。因此为了能够遍历本系统中所有字体,应该返回一个非0值。
最后,测试程序的入口如下:
/************************************************************************/
/* file : 测试程序的主入口
* author : Huagang Li
* date : 2014-8-25 21:25:24
* blogs : http://www.cnblogs.com/lhglihuagang/
*/
/************************************************************************/include <windows.h>
include "SysFonts.h"
int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
CWindowHelper::GetSystemFonts();
CWindowHelper::ShowSysFonts();</span><span style="color: #0000ff">return</span><span style="color: #000000"> EXIT_SUCCESS;
}
这里,为了方便直接将所有的字体用MessageBox 显示出来了,并没有做可读性方面的优化。运行结果如下图1所示:

图1 运行后显示的所有字体
从图中可以看出,该程序统计了当前系统的字体。有一个奇怪的点是:统计的一部分字体前面带有@符号,如宋体和@宋体。至于这个@出现的原因,好像是和windows 7隐藏字体相关,具体可以参见http://stackoverflow.com/questions/11253827/too-many-fonts-when-enumerating-with-enumfontfamiliesex-function
结论
1. 通过EnumFontFamiliesEx和EnumFontFamExProc配合可以遍历系统中所有字体。
2. 上述方法得到的字体中会有重复,实现程序了为了显示单一的字体所以用Set进行了保存
3. 上述方法得到的字体部分存在@,对应了windows 7中的隐藏字体
参考链接
[1] http://msdn.microsoft.com/ZH-CN/library/windows/desktop/dd162620(v=vs.85).aspx
[2] http://msdn.microsoft.com/ZH-CN/library/windows/desktop/dd162618(v=vs.85).aspx
版权声明
声明:未作说明,则本文为年糕原创。转载务必注明出处。
注意:转载须保留全文,如需修改请 联系作者。
windows API 统计系统字体的更多相关文章
- C/C++ Windows API——获取系统指定目录(转)
原文地址:C/C++ Windows API——获取系统指定目录 经测试,在win10 VS2017中用wprintf()输出正常,SHGetSpecialFolderPath函数也正常运行 但是用M ...
- 使用Windows api 获得系统时间并生成文件夹
// 使用window api 获得系统时间 // 生成 #include "stdafx.h" #include <Windows.h> #include <d ...
- windows API 创建系统托盘图标
系统托盘在我们使用的程序中很普遍,下面我们来看一个很不错的例子,使用Win32 API实现,对理解系统托盘有些帮助. [cpp] view plaincopy #include <windows ...
- Windows API获取系统配置文件的配置参数
在Windows平台下获取系统配置文件(如:System.ini)的配置参数. 系统配置文件System.ini的内容如下: [SYSTEM] ServiceIP = 10.128.11.99:600 ...
- 调用windows api 获取系统分辨率
c++中: int cxScreen,cyScreen; cxScreen=GetSystemMetrics(SM_CXSCREEN); cyScreen=GetSystemMetrics(SM_CY ...
- windows API 开发飞机订票系统 图形化界面 (二)
首先,用到的数据结构的定义.以及全局变量和函数的声明如下: // Flight.c : 定义应用程序的入口点. // #include "stdafx.h" //订单 typede ...
- Windows系统字体与文件对照表
源:Windows系统字体与文件对照表 宋体 (TrueType) = SIMSUN.TTF 黑体 (TrueType) = simhei.ttf 楷体_GB2312 (TrueType) = sim ...
- windows API 开发飞机订票系统 图形化界面 (一)
去年数据结构课程设计的作品,c语言实现,图形化界面使用windows API实现. 首发在我csdn博客:http://blog.csdn.net/u013805360/article/details ...
- Windows API 函数列表 附帮助手册
所有Windows API函数列表,为了方便查询,也为了大家查找,所以整理一下贡献出来了. 帮助手册:700多个Windows API的函数手册 免费下载 API之网络函数 API之消息函数 API之 ...
随机推荐
- SDK Manager无法启动
首先cmd切换到android-sdk-windows\tools\lib,找到find_java.bat 打开回显:rem @echo off,再运行find_java.bat,若输出的set ja ...
- HDU 4727 The Number Off of FFF 2013年四川省赛题
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4727 题目大意:队列里所有人进行报数,要找出报错的那个人 思路:,只要找出序列中与钱一个人的数字差不是 ...
- COM初体验
以前在我学校里培训过一段时间C++,我敬爱的吴老师略有提及.那个时候觉得COM遥不可及,觉得,哇塞好神圣.我觉得自己啥都没学好,我不应该这么早去涉及这片过于光荣的领地.既没有觉悟也没有动力去迎接这样一 ...
- hdu 4411 arrest 最小费用流
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #i ...
- java对文件拷贝的简单操作
package fileInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNot ...
- Magento网站迁移指南
"Magento网站迁移指南":关键词:magento 网站 迁移 指南 上周五,为mkt同事迁移了一个从本机到godaddy的magento系统. 中间出了不少状况, 现在写个迁 ...
- php中传值与传引用的区别。什么时候传值什么时候传引用?
值传递: 函数范围内对值的任何改变在函数外部都会被忽略; 引用传递: 函数范围内对值的任何改变在函数外部也能反映出这些修改: 优缺点:按值传递时,php必须复制值.特别是对于大型的字符串和对象来说 ...
- Hibernate自定义数据库查询(排序、输出条数)
Hibernate数据库操作类(eg:TexDAO.java) /* * queryString HQL语句,first开始条数, max输出条数 ,norder排序 * 例: List lis = ...
- 10881 - Piotr's Ants(排序)
题目链接:10881 - Piotr's Ants 题目大意:在一个长为L的木棒上有n只蚂蚁,给出蚂蚁的初始位置以及方向,问说移动T秒后各个蚂蚁的位置以及状态,如果两只蚂蚁在移动的过程中相撞,则会同时 ...
- 基于TCP的socket通信过程及例子
Socket也叫套接字,用来实现网络通讯,通过调用系统提供的API,可以和远程的机子传输数据.Socket有很多种协议,而这篇文章主要讨论TCP部分的内容,也就是说后面说的内容主要是指TCP Sock ...