MFC obtains the font file path from the font name (obtained from Song Ti to simsun.ttc)

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:

 

 

Guess you like

Origin blog.csdn.net/wangningyu/article/details/126374013