coral
coral

Reputation: 191

How can I get a list of installed fonts on Windows including font style using c++

I have been trying to get a list of installed fonts on Windows including font style.

After investigation, I found out that I need to use: EnumFontFamiliesEx. I use it BUT I get only the font name and not all the styles of this font.

for example: for font: "Verdana"

enter image description here

There are four different styles, But I get only one - the regular. My question is: how can I get the fonts list including all the styles?

My code:

void getFonts()
{
    LOGFONT lf;
    memset(&lf, 0, sizeof(lf));
    lf.lfCharSet = DEFAULT_CHARSET;
    HDC hDC = GetDC(NULL);
    EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)(EnumFontFamExProc), NULL, 0);
}

int CALLBACK EnumFontFamExProc(
    ENUMLOGFONTEX *lpelfe,
    NEWTEXTMETRICEX *lpntme,
    DWORD FontType,
    LPARAM lParam
)
{
    UTF8String fontName = (lpelfe->elfFullName);
    return 1;
}

ENUMLOGFONTEX *lpelfe - contains the font. but I don't get all the different styles

after more investigation, I found out that if I change the lfFaceName to a specific font the method returns all styles.

// To enumerate all styles of all fonts for the ANSI character set 
lf.lfFaceName[0] = '\0';
lf.lfCharSet = ANSI_CHARSET;

// To enumerate all styles of Arial font that cover the ANSI charset 
hr = StringCchCopy( (LPSTR)lf.lfFaceName, LF_FACESIZE, "Arial" );

So I'm not sure what I should do, I need to get all the styles for all the installed fonts.

Thank you in advance

Upvotes: 3

Views: 3164

Answers (2)

Peter Constable
Peter Constable

Reputation: 3560

See the details for EnumFontFamiliesEx, specifically for the lfFaceName parameter:

If set to an empty string, the function enumerates one font in each available typeface name. If set to a valid typeface name, the function enumerates all fonts with the specified name.

The most common scenario is to get a list of families to display in a font-selection UI (e.g., dropdown), not all of the individual faces. For that reason, if you call with lfFacename set to "", that's what you'll get: the list of families. If you really want to get all of the individual faces—with multiple faces per family—then you need to call recursively within the EnumFontFamiliesExProc call back, passing the family name as lfFaceName on the inner loop — you can just use the LOGFONT passed to the call back as the argument into the inner-loop call to EnumFontFamiliesEx:

int CALLBACK GdiFontEnumeration::EnumFontFamiliesExCallback(
    _In_ const ENUMLOGFONTEX    *lpelfe,
    _In_ const NEWTEXTMETRICEX *lpntme,
    _In_       DWORD      dwFontType,
    _In_       LPARAM     lParam
    )
{
    // If no facename parameter was passed in the command line, then
    // lParam will be 0 the first time the callback is called for a
    // given family. We'll call EnumFontFamiliesEx again passing the 
    // LOGFONT, and that way we'll get callbacks for the variations 
    // within the given family. When making the inner-loop call, set 
    // lParam = 1 so that we don't keep recursing.

    if (lParam == 0)
    {
        LOGFONT lf = lpelfe->elfLogFont;
        HDC hdc = CreateDC(L"DISPLAY", NULL, NULL, NULL);
        int result = EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC)EnumFontFamiliesExCallback, 1, 0);
    }
    else
...

Upvotes: 3

cdecompilador
cdecompilador

Reputation: 190

This little program will list all the fonts installed on your system. You can separate them by the style just looking for the suffix. It uses C++17 features so remember to compile it with the correct standard.

i = Italic
b = Bold
bi = Bold and Italic
...
#include <string>
#include <iostream>
#include <filesystem>

int main()
{
    std::string path = "C:\\Windows\\Fonts";
    for (const auto& entry : std::filesystem::directory_iterator(path))
        std::cout << entry.path() << std::endl;
}

Upvotes: 0

Related Questions