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之 ...
随机推荐
- Node.js权威指南 (10) - Node.js中的错误处理与断言处理
10.1 使用domain模块处理错误 / 272 10.1.1 domain模块概述 / 272 10.1.2 创建并使用Domain对象 / 274 10.1.3 隐式绑定与显式绑定 / 276 ...
- 【转】微信Android SDK示例代码及运行方法
原文网址:http://blog.csdn.net/icyfox_bupt/article/details/23742217 最近在研究微信SDK,无奈网上好使的教程太少,对于程序员来说最好的东西,一 ...
- 【Javascript&Jquery基础归纳】- 加载相关
1.window.onload 必须等到Dom所有元素.包括图片加载完毕后加载,只能编写一个. 2.$(document).ready() DOM结构加载完毕后马上执行,并且可以编写多个. ...
- 在word 2013中输入latex公式
注意:版权所有,转载请注明出处 向word输入LaTeX公式,插件有很多,前面在使用的是一个叫做Aurora的插件,结果不是免费的,用了一段时间就要收费是,所以就不用了,从网上找到别人的介绍,可以使用 ...
- 《A First Course in Probability》-chaper4-离散型随机变量-随机变量和或积的期望
基于随机变量一系列最基本的概念,我们便会开始探讨一些随机变量函数的期望.多个随机变量和的期望.多个随机变量乘积的期望. 这里我们就简单的讨论后两个期望. 这两个问题可以基于如下的一个现实模型: 同时掷 ...
- Ubuntu 下安装opencv 编译后执行找不到库
在ubuntu下编译opencv程序后,执行报下面到错误:error while loading shared libraries: libopencv_core.so.2.4: cannot ope ...
- LogMiner学习笔记
本文是个实战,没有讲太多理论的东西,如需详细理解Oracle LogMiner,请移步:LogMiner详细讲解 首先介绍一下我的oracle环境: 第一步: 确定LogMiner已经安装. 安装Lo ...
- jquery中字符串类型转换成整形的方法
jQuery有一个自带的函数为parseInt():这个函数可以把字符型的数字转换成整形例如: parseInt("1234"); //返回1234 parseInt(" ...
- bzoj3675: [Apio2014]序列分割
留坑 为什么别人家的斜率优化跟我一点都不一样! 为什么斜率都要变成正的... 为什么要那么推式子 为什么不能直接做啊..... 为什么不把0去掉去秒WA啊 为什么叉积去了0也过不了啊 woc啊 #in ...
- JUnit-4.11使用报java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing错误
今天尝试使用JUnit,下载了最新的JUnit版本,是4.11,结果尝试使用发现总是报java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribi ...