The previous article talked about the path to get text from the font name in QT . This is the MFC version:
#QT从字体名获取字库文件路径
#include <string>
using namespace std;
void wcharTochar(const wchar_t *wchar, char *chr, int length)
{
memset(chr,0x00,length * sizeof(char));
WideCharToMultiByte( CP_ACP, 0, wchar, -1, chr, length, NULL, NULL );
}
void charTowchar(const char *chr, wchar_t *wchar, int size)
{
memset(wchar,0x00,size * sizeof(wchar_t));
MultiByteToWideChar( CP_ACP, 0, chr, strlen(chr)+1, wchar, size/sizeof(wchar[0]) );
}
// Get system font file path
int GetSystemFontFile(const std::string &faceName, char *pszFontPath) {
static const char fontRegistryPath[] = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
HKEY hKey;
LONG result;
std::string wsFaceName(faceName.begin(), faceName.end());
// Open Windows font registry key
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, fontRegistryPath, 0, KEY_READ, &hKey);
if (result != ERROR_SUCCESS) {
return 0;
}
DWORD maxValueNameSize, maxValueDataSize;
result = RegQueryInfoKey(hKey, 0, 0, 0, 0, 0, 0, 0, &maxValueNameSize, &maxValueDataSize, 0, 0);
if (result != ERROR_SUCCESS) {
return 0;
}
DWORD valueIndex = 0;
char *valueName = new char[maxValueNameSize];
LPBYTE valueData = new BYTE[maxValueDataSize];
DWORD valueNameSize, valueDataSize, valueType;
char szFontFile[MAX_PATH] = {0x00};
// Look for a matching font name
do {
memset(szFontFile, 0x00, sizeof(szFontFile));
valueDataSize = maxValueDataSize;
valueNameSize = maxValueNameSize;
result = RegEnumValue(hKey, valueIndex, valueName, &valueNameSize, 0, &valueType, valueData, &valueDataSize);
valueIndex++;
if (result != ERROR_SUCCESS || valueType != REG_SZ) {
continue;
}
std::string wsValueName(valueName, valueNameSize);
// Found a match
if (_tcsncicmp(wsFaceName.c_str(), wsValueName.c_str(), wsFaceName.length()) == 0) {
wsprintf(szFontFile, "%s", valueData);
break;
}
}
while (result != ERROR_NO_MORE_ITEMS);
delete[] valueName;
delete[] valueData;
RegCloseKey(hKey);
if (strlen(szFontFile) == 0)
{
return 0;
}
// Build full font file path
char winDir[MAX_PATH] = {0x00};
GetWindowsDirectory(winDir, MAX_PATH);
wsprintf(pszFontPath, "%s\\Fonts\\%s", winDir, szFontFile);
return strlen(pszFontPath);
}
#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
(((UINT)(ch4)) << 24) | \
(((UINT)(ch3)) << 16) | \
(((UINT)(ch2)) << 8) | \
((UINT)(ch1)) \
)
static inline USHORT getUShort(const unsigned char *p)
{
USHORT val;
val = *p++ << 8;
val |= *p;
return val;
}
static char * getEnglishName(const UCHAR *table, UINT bytes)
{
static char szEnName[MAX_PATH] = {0x00};
static wchar_t i18n_name[MAX_PATH] = {0x00};
enum {
NameRecordSize = 12,
FamilyId = 1,
MS_LangIdEnglish = 0x009
};
// get the name table
USHORT count;
USHORT string_offset;
const unsigned char *names;
int microsoft_id = -1;
int apple_id = -1;
int unicode_id = -1;
if(getUShort(table) != 0)
goto error;
count = getUShort(table+2);
string_offset = getUShort(table+4);
names = table + 6;
if(string_offset >= bytes || 6 + count*NameRecordSize > string_offset)
goto error;
for(int i = 0; i < count; ++i) {
// search for the correct name entry
USHORT platform_id = getUShort(names + i*NameRecordSize);
USHORT encoding_id = getUShort(names + 2 + i*NameRecordSize);
USHORT language_id = getUShort(names + 4 + i*NameRecordSize);
USHORT name_id = getUShort(names + 6 + i*NameRecordSize);
if(name_id != FamilyId)
continue;
enum {
PlatformId_Unicode = 0,
PlatformId_Apple = 1,
PlatformId_Microsoft = 3
};
USHORT length = getUShort(names + 8 + i*NameRecordSize);
USHORT offset = getUShort(names + 10 + i*NameRecordSize);
if(DWORD(string_offset + offset + length) >= bytes)
continue;
if ((platform_id == PlatformId_Microsoft
&& (encoding_id == 0 || encoding_id == 1))
&& (language_id & 0x3ff) == MS_LangIdEnglish
&& microsoft_id == -1)
microsoft_id = i;
// not sure if encoding id 4 for Unicode is utf16 or ucs4...
else if(platform_id == PlatformId_Unicode && encoding_id < 4 && unicode_id == -1)
unicode_id = i;
else if(platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0)
apple_id = i;
}
{
bool unicode = false;
int id = -1;
if(microsoft_id != -1) {
id = microsoft_id;
unicode = true;
} else if(apple_id != -1) {
id = apple_id;
unicode = false;
} else if (unicode_id != -1) {
id = unicode_id;
unicode = true;
}
if(id != -1) {
USHORT length = getUShort(names + 8 + id*NameRecordSize);
USHORT offset = getUShort(names + 10 + id*NameRecordSize);
if(unicode) {
// utf16
length /= 2;
//i18n_name.resize(length);
wchar_t *uc = (wchar_t *) i18n_name;
const unsigned char *string = table + string_offset + offset;
for(int i = 0; i < length; ++i)
uc[i] = getUShort(string + 2*i);
memset(szEnName, 0x00, sizeof(szEnName));
wcharTochar(i18n_name, szEnName, MAX_PATH);
} else {
// Apple Roman
char *uc = (char *) i18n_name;
const unsigned char *string = table + string_offset + offset;
for(int i = 0; i < length; ++i)
uc[i] = string[i];
memset(szEnName, 0x00, sizeof(szEnName));
memcpy(szEnName, uc, strlen(uc));
}
}
}
error:
//qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
return szEnName;
}
char * getEnglishName(const char *familyName)
{
char *i18n_name = 0x00;
HDC hdc = GetDC( 0 );
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
memcpy(lf.lfFaceName, familyName, strlen(familyName));
lf.lfCharSet = DEFAULT_CHARSET;
HFONT hfont = CreateFontIndirect(&lf);
if(!hfont) {
ReleaseDC(0, hdc);
return i18n_name;
}
HGDIOBJ oldobj = SelectObject( hdc, hfont );
const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
// get the name table
unsigned char *table = 0;
DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 );
if ( bytes == GDI_ERROR ) {
// ### Unused variable
/* int err = GetLastError(); */
goto error;
}
table = new unsigned char[bytes];
GetFontData(hdc, name_tag, 0, table, bytes);
if ( bytes == GDI_ERROR )
goto error;
i18n_name = getEnglishName(table, bytes);
error:
delete [] table;
SelectObject( hdc, oldobj );
DeleteObject( hfont );
ReleaseDC( 0, hdc );
//qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
return i18n_name;
}
Iterate over all fonts available on the system:
BOOL CALLBACK EnumFontFamEx(LPLOGFONT lplf,LPTEXTMETRIC lptm,int iType,LPARAM lpData)
{
// m_cList.AddString(lplf->lfFaceName);
return 1;
}
void main()
{
// 遍历系统所有字体
HDC hdc = ::GetDC(NULL);
LOGFONT lf;
memset(&lf,0,sizeof(LOGFONT));
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfFaceName[0] = NULL;
m_cList.ResetContent();
::EnumFontFamiliesEx(hdc,&lf,(FONTENUMPROC)EnumFontFamEx,0,0);
::ReleaseDC(NULL,hdc);
}
Get the font ttc file name according to faceName:
void CEnumFontDlg::OnDblclkList1()
{
// TODO: 在此添加控件通知处理程序代码
char szName[MAX_PATH] = {0x00};
int nSel = CB_ERR;
char szPath[MAX_PATH] = {0x00};
char *pPath = NULL;
nSel = m_cList.GetCurSel();
if(nSel == CB_ERR)
return;
// 获取到ListBox中双击选中的字体
// 例如:宋体、微软雅黑
m_cList.GetText(nSel, szName);
pPath = getEnglishName(szName);
if(pPath)
{
GetSystemFontFile(pPath, szPath);
AfxMessageBox(szPath);
}
}
The running effect is as follows: