Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get a font filepath from name and style in C++/Windows

I'm currently implementing FreeType 2 in a project of mine and thus need the filepaths for Fonts on my system. I need a solution that only takes the fonts name and the desired font style (eg. bold or italic) and then returns the filepath for the font.

I already tried the answer from this Stack Overflow question, but it doesn't work on Windows 7 (and probably neither on Vista), but obviously I need a solution that works on these systems and future systems as well.

like image 326
Marian Frische Avatar asked Jul 08 '12 23:07

Marian Frische


2 Answers

I once wrote code for Windows platform to find a font file based on "Arial Bold" or such name. The code is posted below. It is scanning the Registry and trying to find a match for the font face name to a file in Windows fonts directory. It may not be bulletproof, but it did kind of work. Once you have the file name you can pass it to FreeType.

// Get system font file path
std::string GetSystemFontFile(const std::string &faceName) {

  static const LPWSTR fontRegistryPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
  HKEY hKey;
  LONG result;
  std::wstring 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 "";
  }

  DWORD maxValueNameSize, maxValueDataSize;
  result = RegQueryInfoKey(hKey, 0, 0, 0, 0, 0, 0, 0, &maxValueNameSize, &maxValueDataSize, 0, 0);
  if (result != ERROR_SUCCESS) {
    return "";
  }

  DWORD valueIndex = 0;
  LPWSTR valueName = new WCHAR[maxValueNameSize];
  LPBYTE valueData = new BYTE[maxValueDataSize];
  DWORD valueNameSize, valueDataSize, valueType;
  std::wstring wsFontFile;

  // Look for a matching font name
  do {

    wsFontFile.clear();
    valueDataSize = maxValueDataSize;
    valueNameSize = maxValueNameSize;

    result = RegEnumValue(hKey, valueIndex, valueName, &valueNameSize, 0, &valueType, valueData, &valueDataSize);

    valueIndex++;

    if (result != ERROR_SUCCESS || valueType != REG_SZ) {
      continue;
    }

    std::wstring wsValueName(valueName, valueNameSize);

    // Found a match
    if (_wcsnicmp(wsFaceName.c_str(), wsValueName.c_str(), wsFaceName.length()) == 0) {

      wsFontFile.assign((LPWSTR)valueData, valueDataSize);
      break;
    }
  }
  while (result != ERROR_NO_MORE_ITEMS);

  delete[] valueName;
  delete[] valueData;

  RegCloseKey(hKey);

  if (wsFontFile.empty()) {
    return "";
  }

  // Build full font file path
  WCHAR winDir[MAX_PATH];
  GetWindowsDirectory(winDir, MAX_PATH);

  std::wstringstream ss;
  ss << winDir << "\\Fonts\\" << wsFontFile;
  wsFontFile = ss.str();

  return std::string(wsFontFile.begin(), wsFontFile.end());
}
like image 194
Sim Avatar answered Sep 19 '22 06:09

Sim


May I ask why do you need the path to a physical file?

  • If you just need the binary data of the font, you can use GetFontData.
  • If need the metrics of the font, you can create an HFONT, select the HFONT into an font holder HDC, and use GetOutlineTextMetrics.
  • If you need information about font linking, take a look at my project: font_link.cpp.
  • All above are pure GDI functions. If you really need the font path, and not mind using DirectWrite, take look at IDWriteFontFile::GetReferenceKey and IDWriteLocalFontFileLoader::GetFilePathFromKey. This would give you more future insurance than GDI.
like image 45
Crend King Avatar answered Sep 22 '22 06:09

Crend King