// XFont.cpp Version 1.1 // // Author: Philip Patrick (GetFontProperties) // // Version 1.0 - Initial release of GetFontProperties() // // Modified by: Hans Dietrich // hdietrich2@hotmail.com // // Version 1.1: - Removed MFC dependency from GetFontProperties() // - Converted CFile file I/O to memory mapped file // - Added Unicode support // - Combined with my GetFontFile() routine // /////////////////////////////////////////////////////////////////////////////// #include "XTrace.h" #include "XFont.h" #include #include /////////////////////////////////////////////////////////////////////////////// // // If you do not want TRACE output you can // uncomment the following lines: // #undef TRACE #if _MSC_VER > 1300 #define TRACE __noop #else #define TRACE ((void)0) #endif // /////////////////////////////////////////////////////////////////////////////// #pragma warning(disable : 4127) // conditional expression is constant /////////////////////////////////////////////////////////////////////////////// // private routines static LONG GetNextNameValue(HKEY key, LPCTSTR subkey, LPTSTR szName, LPTSTR szData); /////////////////////////////////////////////////////////////////////////////// // defines used by GetWinVer() #define WUNKNOWNSTR _T("unknown Windows version") #define W2KSTR _T("Windows 2000") #define WXPSTR _T("Windows XP") #define W2003STR _T("Windows Server 2003") #define WVISTASTR _T("Windows Vista") #define W2008STR _T("Windows Server 2008") #define W2008R2STR _T("Windows Server 2008 R2") #define W7STR _T("Windows 7") #define W2012STR _T("Windows Server 2012") #define W8STR _T("Windows 8") #define W10STR _T("Windows 10") #define W2016STR _T("Windows Server 2016") #define WUNKNOWN 0 #define W9XFIRST 1 #define W95 1 #define W95SP1 2 #define W95OSR2 3 #define W98 4 #define W98SP1 5 #define W98SE 6 #define WME 7 #define W9XLAST 99 #define WNTFIRST 101 #define WNT351 101 #define WNT4 102 #define W2K 103 #define WXP 104 #define W2003 105 #define WVISTA 106 #define W2008 107 #define W2008R2 108 #define W7 109 #define W2012 110 #define W8 111 #define W10 112 #define W2016 103 #define WNTLAST 199 #define WCEFIRST 201 #define WCE 201 #define WCELAST 299 /////////////////////////////////////////////////////////////////////////////// // // structs used by GetFontProperties() // typedef struct _tagFONT_PROPERTIES_ANSI { char csName[1024]; char csCopyright[1024]; char csTrademark[1024]; char csFamily[1024]; } FONT_PROPERTIES_ANSI; typedef struct _tagTT_OFFSET_TABLE { USHORT uMajorVersion; USHORT uMinorVersion; USHORT uNumOfTables; USHORT uSearchRange; USHORT uEntrySelector; USHORT uRangeShift; } TT_OFFSET_TABLE; typedef struct _tagTT_TABLE_DIRECTORY { char szTag[4]; //table name ULONG uCheckSum; //Check sum ULONG uOffset; //Offset from beginning of file ULONG uLength; //length of the table in bytes } TT_TABLE_DIRECTORY; typedef struct _tagTT_NAME_TABLE_HEADER { USHORT uFSelector; //format selector. Always 0 USHORT uNRCount; //Name Records count USHORT uStorageOffset; //Offset for strings storage, from start of the table } TT_NAME_TABLE_HEADER; typedef struct _tagTT_NAME_RECORD { USHORT uPlatformID; USHORT uEncodingID; USHORT uLanguageID; USHORT uNameID; USHORT uStringLength; USHORT uStringOffset; //from start of storage area } TT_NAME_RECORD; #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x))) /////////////////////////////////////////////////////////////////////////////// // // GetFontFile() // // Purpose: Find the name of font file from the font name // // Parameters: lpszFontName - name of font // lpszDisplayName - pointer to buffer where font display name // will be copied // nDisplayNameSize - size of display name buffer in TCHARs // lpszFontFile - pointer to buffer where font file name // will be copied // nFontFileSize - size of font file buffer in TCHARs // // Returns: BOOL - TRUE = success // // Notes: This is *not* a foolproof method for finding the name of a // font file. If a font has been installed in a normal manner, // and if it is in the Windows "Font" directory, then this method // will probably work. It will probably work for most screen // fonts and TrueType fonts. However, this method might not work // for fonts that are created or installed dynamically, or that // are specific to a particular device, or that are not installed // into the font directory. // BOOL GetFontFile(LPCTSTR lpszFontName, LPTSTR lpszDisplayName, int nDisplayNameSize, LPTSTR lpszFontFile, int nFontFileSize) { _ASSERTE(lpszFontName && lpszFontName[0] != 0); if (!lpszFontName || lpszFontName[0] == 0) return FALSE; _ASSERTE(lpszDisplayName); if (!lpszDisplayName) return FALSE; _ASSERTE(lpszFontFile); if (!lpszFontFile) return FALSE; lpszDisplayName[0] = _T('\0'); lpszFontFile[0] = _T('\0'); TCHAR szName[2 * MAX_PATH]; TCHAR szData[2 * MAX_PATH]; int nVersion; TCHAR szVersion[100]; GetWinVer(szVersion, sizeof(szVersion)/sizeof(TCHAR)-1, &nVersion); LPCTSTR szFontPath = NULL; if ((nVersion >= WNTFIRST) && (nVersion <= WNTLAST)) szFontPath = _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"); else szFontPath = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Fonts"); BOOL bResult = FALSE; while (GetNextNameValue(HKEY_LOCAL_MACHINE, szFontPath, szName, szData) == ERROR_SUCCESS) { if (_tcsnicmp(lpszFontName, szName, _tcslen(lpszFontName)) == 0) { TRACE(_T("found font\n")); _tcsncpy(lpszDisplayName, szName, nDisplayNameSize-1); _tcsncpy(lpszFontFile, szData, nFontFileSize-1); bResult = TRUE; break; } szFontPath = _T(""); // this will get next value, same key } GetNextNameValue(HKEY_LOCAL_MACHINE, NULL, NULL, NULL); // close the registry key return bResult; } bool GetFontsFolder(LPTSTR lpszFontPath, int nFontPathSize) { _ASSERTE(nFontPathSize >= _MAX_PATH); *lpszFontPath = '\0'; SHGetFolderPath(NULL, CSIDL_FONTS, NULL, 0, lpszFontPath); return *lpszFontPath != '\0'; } /////////////////////////////////////////////////////////////////////////////// // // GetFontProperties() // // Purpose: Get font name from font file // // Parameters: lpszFilePath - file path of font file // lpFontPropsX - pointer to font properties struct // // Returns: BOOL - TRUE = success // BOOL GetFontProperties(LPCTSTR lpszFilePath, FONT_PROPERTIES * lpFontPropsX) { FONT_PROPERTIES_ANSI fp; FONT_PROPERTIES_ANSI * lpFontProps = &fp; memset(lpFontProps, 0, sizeof(FONT_PROPERTIES_ANSI)); HANDLE hFile = INVALID_HANDLE_VALUE; hFile = ::CreateFile(lpszFilePath, GENERIC_READ,// | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hFile == INVALID_HANDLE_VALUE) { TRACE(_T("ERROR: failed to open '%s'\n"), lpszFilePath); TRACE(_T("ERROR: %s failed\n"), _T("CreateFile")); return FALSE; } // get the file size DWORD dwFileSize = ::GetFileSize(hFile, NULL); if (dwFileSize == INVALID_FILE_SIZE) { TRACE(_T("ERROR: %s failed\n"), _T("GetFileSize")); ::CloseHandle(hFile); return FALSE; } TRACE(_T("dwFileSize = %d\n"), dwFileSize); // Create a file mapping object that is the current size of the file HANDLE hMappedFile = NULL; hMappedFile = ::CreateFileMapping(hFile, NULL, PAGE_READONLY, //PAGE_READWRITE, 0, dwFileSize, NULL); if (hMappedFile == NULL) { TRACE(_T("ERROR: %s failed\n"), _T("CreateFileMapping")); ::CloseHandle(hFile); return FALSE; } LPBYTE lpMapAddress = (LPBYTE) ::MapViewOfFile(hMappedFile, // handle to file-mapping object FILE_MAP_READ,//FILE_MAP_WRITE, // access mode 0, // high-order DWORD of offset 0, // low-order DWORD of offset 0); // number of bytes to map if (lpMapAddress == NULL) { TRACE(_T("ERROR: %s failed\n"), _T("MapViewOfFile")); ::CloseHandle(hMappedFile); ::CloseHandle(hFile); return FALSE; } BOOL bRetVal = FALSE; int index = 0; TT_OFFSET_TABLE ttOffsetTable; memcpy(&ttOffsetTable, &lpMapAddress[index], sizeof(TT_OFFSET_TABLE)); index += sizeof(TT_OFFSET_TABLE); ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables); ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion); ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion); //check is this is a true type font and the version is 1.0 if (ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0) return bRetVal; TT_TABLE_DIRECTORY tblDir; memset(&tblDir, 0, sizeof(TT_TABLE_DIRECTORY)); BOOL bFound = FALSE; char szTemp[4096]; memset(szTemp, 0, sizeof(szTemp)); for (int i = 0; i< ttOffsetTable.uNumOfTables; i++) { //f.Read(&tblDir, sizeof(TT_TABLE_DIRECTORY)); memcpy(&tblDir, &lpMapAddress[index], sizeof(TT_TABLE_DIRECTORY)); index += sizeof(TT_TABLE_DIRECTORY); strncpy(szTemp, tblDir.szTag, 4); if (_stricmp(szTemp, "name") == 0) { bFound = TRUE; tblDir.uLength = SWAPLONG(tblDir.uLength); tblDir.uOffset = SWAPLONG(tblDir.uOffset); break; } else if (szTemp[0] == 0) { break; } } if (bFound) { index = tblDir.uOffset; TT_NAME_TABLE_HEADER ttNTHeader; memcpy(&ttNTHeader, &lpMapAddress[index], sizeof(TT_NAME_TABLE_HEADER)); index += sizeof(TT_NAME_TABLE_HEADER); ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount); ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset); TT_NAME_RECORD ttRecord; bFound = FALSE; for (int i = 0; i < ttNTHeader.uNRCount && (lpFontProps->csCopyright[0] == 0 || lpFontProps->csName[0] == 0 || lpFontProps->csTrademark[0] == 0 || lpFontProps->csFamily[0] == 0); i++) { memcpy(&ttRecord, &lpMapAddress[index], sizeof(TT_NAME_RECORD)); index += sizeof(TT_NAME_RECORD); ttRecord.uNameID = SWAPWORD(ttRecord.uNameID); ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength); ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset); if (ttRecord.uNameID == 1 || ttRecord.uNameID == 0 || ttRecord.uNameID == 7) { int nPos = index; //f.GetPosition(); index = tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset; memset(szTemp, 0, sizeof(szTemp)); memcpy(szTemp, &lpMapAddress[index], ttRecord.uStringLength); index += ttRecord.uStringLength; if (szTemp[0] != 0) { _ASSERTE(strlen(szTemp) < sizeof(lpFontProps->csName)); switch (ttRecord.uNameID) { case 0: if (lpFontProps->csCopyright[0] == 0) strncpy(lpFontProps->csCopyright, szTemp, sizeof(lpFontProps->csCopyright)-1); break; case 1: if (lpFontProps->csFamily[0] == 0) strncpy(lpFontProps->csFamily, szTemp, sizeof(lpFontProps->csFamily)-1); bRetVal = TRUE; break; case 4: if (lpFontProps->csName[0] == 0) strncpy(lpFontProps->csName, szTemp, sizeof(lpFontProps->csName)-1); break; case 7: if (lpFontProps->csTrademark[0] == 0) strncpy(lpFontProps->csTrademark, szTemp, sizeof(lpFontProps->csTrademark)-1); break; default: break; } } index = nPos; } } } ::UnmapViewOfFile(lpMapAddress); ::CloseHandle(hMappedFile); ::CloseHandle(hFile); if (lpFontProps->csName[0] == 0) strcpy(lpFontProps->csName, lpFontProps->csFamily); memset(lpFontPropsX, 0, sizeof(FONT_PROPERTIES)); #ifdef _UNICODE ::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csName, -1, lpFontPropsX->csName, sizeof(lpFontPropsX->csName)/sizeof(TCHAR)-1); ::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csCopyright, -1, lpFontPropsX->csCopyright, sizeof(lpFontPropsX->csCopyright)/sizeof(TCHAR)-1); ::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csTrademark, -1, lpFontPropsX->csTrademark, sizeof(lpFontPropsX->csTrademark)/sizeof(TCHAR)-1); ::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csFamily, -1, lpFontPropsX->csFamily, sizeof(lpFontPropsX->csFamily)/sizeof(TCHAR)-1); #else strcpy(lpFontPropsX->csName, lpFontProps->csName); strcpy(lpFontPropsX->csCopyright, lpFontProps->csCopyright); strcpy(lpFontPropsX->csTrademark, lpFontProps->csTrademark); strcpy(lpFontPropsX->csFamily, lpFontProps->csFamily); #endif return bRetVal; } /////////////////////////////////////////////////////////////////////////////// // // GetNextNameValue() // // Purpose: Get first/next name/value pair from registry // // Parameters: key - handle to open key, or predefined key // pszSubkey - subkey name // pszName - pointer to buffer that receives the value string // pszData - pointer to buffer that receives the data string // // Returns: LONG - return code from registry function; ERROR_SUCCESS = success // // Notes: If pszSubkey, pszName, and pszData are all NULL, then the open // handle will be closed. // // The first time GetNextNameValue is called, pszSubkey should be // specified. On subsequent calls, pszSubkey should be NULL or // an empty string. // static LONG GetNextNameValue(HKEY key, LPCTSTR pszSubkey, LPTSTR pszName, LPTSTR pszData) { static HKEY hkey = NULL; // registry handle, kept open between calls static DWORD dwIndex = 0; // count of values returned LONG retval = ERROR_SUCCESS; // if all parameters are NULL then close key if (pszSubkey == NULL && pszName == NULL && pszData == NULL) { TRACE(_T("closing key\n")); if (hkey) ::RegCloseKey(hkey); hkey = NULL; return ERROR_SUCCESS; } // if subkey is specified then open key (first time) if (pszSubkey && *pszSubkey) { // retval = ::RegOpenKeyEx(key, pszSubkey, 0, KEY_ALL_ACCESS, &hkey); // Incapace... retval = ::RegOpenKeyEx(key, pszSubkey, 0, KEY_READ, &hkey); // ... devi solo leggere! if (retval != ERROR_SUCCESS) { TRACE(_T("ERROR: RegOpenKeyEx failed\n")); return retval; } else { TRACE(_T("RegOpenKeyEx ok\n")); } dwIndex = 0; } else { dwIndex++; } _ASSERTE(pszName != NULL && pszData != NULL); *pszName = 0; *pszData = 0; TCHAR szValueName[MAX_PATH]; DWORD dwValueNameSize = sizeof(szValueName)-1; BYTE szValueData[MAX_PATH]; DWORD dwValueDataSize = sizeof(szValueData)-1; DWORD dwType = 0; retval = ::RegEnumValue(hkey, dwIndex, szValueName, &dwValueNameSize, NULL, &dwType, szValueData, &dwValueDataSize); if (retval == ERROR_SUCCESS) { TRACE(_T("szValueName=<%s> szValueData=<%s>\n"), szValueName, szValueData); lstrcpy(pszName, (LPTSTR)szValueName); lstrcpy(pszData, (LPTSTR)szValueData); } else { TRACE(_T("RegEnumKey failed\n")); } return retval; } // from winbase.h #ifndef VER_PLATFORM_WIN32s #define VER_PLATFORM_WIN32s 0 #endif #ifndef VER_PLATFORM_WIN32_WINDOWS #define VER_PLATFORM_WIN32_WINDOWS 1 #endif #ifndef VER_PLATFORM_WIN32_NT #define VER_PLATFORM_WIN32_NT 2 #endif #ifndef VER_PLATFORM_WIN32_CE #define VER_PLATFORM_WIN32_CE 3 #endif /* This table has been assembled from Usenet postings, personal observations, and reading other people's code. Please feel free to add to it or correct it. dwPlatFormID dwMajorVersion dwMinorVersion dwBuildNumber 95 1 4 0 950 95 SP1 1 4 0 >950 && <=1080 95 OSR2 1 4 <10 >1080 98 1 4 10 1998 98 SP1 1 4 10 >1998 && <2183 98 SE 1 4 10 >=2183 ME 1 4 90 3000 NT 3.51 2 3 51 NT 4 2 4 0 1381 2000 2 5 0 2195 XP 2 5 1 2600 2003 2 5 2 Vista 2 6 0 2008 2 6 0 2008 R2 2 6 1 Win7 2 6 1 3600 Win8 2 6 2 Win8.1 2 6 3 Win10 2 6 4 Win10 2 10 0 CE 3 */ /////////////////////////////////////////////////////////////////////////////// // // GetWinVer() // // Purpose: Get Windows version info // // Parameters: lpszVersion - pointer to buffer that receives the version // string // nVersionSize - size of the version buffer in TCHARs // pnVersion - pointer to int that receives the version code // // Returns: BOOL - TRUE = success // /////////////////////////////////////////////////////////////////////////////// // GetWinVer bool GetWinVer(LPTSTR lpszVersion, int nVersionSize, int *pnVersion) { int nVersion = WUNKNOWN; LPCTSTR cp = WUNKNOWNSTR; OSVERSIONINFOEX osinfo; memset(&osinfo, 0, sizeof(osinfo)); osinfo.dwOSVersionInfoSize = sizeof(osinfo); if (::GetVersionEx((OSVERSIONINFO*)&osinfo)) { DWORD dwPlatformId = osinfo.dwPlatformId; DWORD dwMinorVersion = osinfo.dwMinorVersion; DWORD dwMajorVersion = osinfo.dwMajorVersion; DWORD dwBuildNumber = osinfo.dwBuildNumber & 0xFFFF; // Win 95 needs this const bool bServer = osinfo.wProductType != VER_NT_WORKSTATION; if (dwPlatformId == VER_PLATFORM_WIN32_NT) { if (dwMajorVersion <= 5) { switch (dwMinorVersion) { case 0: cp = W2KSTR; nVersion = W2K; break; case 1: cp = WXPSTR; nVersion = WXP; break; case 2: default: cp = W2003STR; nVersion = W2003; break; } } else if (dwMajorVersion == 6) { switch (dwMinorVersion) { case 0: if (bServer) { cp = W2008STR; nVersion = W2008; } else { cp = WVISTASTR; nVersion = WVISTA; } break; case 1: if (bServer) { cp = W2008R2STR; nVersion = W2008R2; } else { cp = W7STR; nVersion = W7; } break; case 2: case 3: if (bServer) { cp = W2012STR; nVersion = W2012; } else { cp = W8STR; nVersion = W8; } break; default: if (bServer) { cp = W2016STR; nVersion = W2016; } else { cp = W10STR; nVersion = W10; } break; } } else if (dwMajorVersion >= 10) { if (bServer) { cp = W2016STR; nVersion = W2016; } else { cp = W10STR; nVersion = W10; } } } } if (lpszVersion != NULL && nVersionSize > 0) _tcsncpy(lpszVersion, cp, nVersionSize-1); if (pnVersion != NULL) *pnVersion = nVersion; return nVersion == WUNKNOWN; }