Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why MS doesn't have in its win32api a function that returns the font file name, given the font handle?

This is the first time, in years of experience using the Windows API, that I confront a situation where I need to do something, that I can't, with Windows' current programming interface.

According to my research, the font "Arial Black" uses the file arialblk.ttf and there's no file for the font "Arial Black Italic", neither for the font "Arial Black Bold", at least in my computer with a Windows 7.

I inserted below a program to show a few lines of text using the font "Arial Black", by itself, and then with italic and bold. To my surprise the italic text was rendered normally and the bold text was rendered as if it was just "Arial Black". Then I realized that the same thing happens with MS Word. I've also inserted a screenshot of a Word document, superimposed by the output from the code below. What's happening here ? Do I have to guess, which font file is being used in each case ? Apparently the Windows API does not give me the possibility of an answer. Why the mistery ?

#include <Windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, UINT, LONG);


int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, int nCmdShow)
{
    WNDCLASSEX  wndclassx;

    wndclassx.cbSize        = sizeof(WNDCLASSEX);
    wndclassx.style         = CS_HREDRAW | CS_VREDRAW;
    wndclassx.lpfnWndProc   = WndProc;
    wndclassx.cbClsExtra    = 0;
    wndclassx.cbWndExtra    = 0;
    wndclassx.hInstance     = hInstance;
    wndclassx.hIcon         = nullptr;
    wndclassx.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wndclassx.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wndclassx.lpszMenuName  = nullptr;
    wndclassx.lpszClassName = L"WndProc";
    wndclassx.hIconSm       = nullptr;

    if( !RegisterClassEx(&wndclassx) ) return 0;

    HWND hWnd = CreateWindow(L"WndProc", nullptr, WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL, CW_USEDEFAULT,
                             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);

    ShowWindow(hWnd, SW_MAXIMIZE);
    UpdateWindow(hWnd);

    MSG msg;
    while( GetMessage(&msg, nullptr, 0, 0) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}


LRESULT CALLBACK WndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
    static HFONT s_hArialBlack, s_hArialBlackItalic, s_hArialBlackBold;

    switch ( message )
    {
        case WM_CREATE:
        {
            LOGFONT lf;
            memset(&lf, 0, sizeof(LOGFONT));
            lf.lfHeight = -MulDiv(20, 96, 72);
            wcscpy_s(lf.lfFaceName, LF_FACESIZE, L"Arial Black");


            if( !(s_hArialBlack = CreateFontIndirect(&lf)) ) return -1;

            lf.lfItalic = true;

            if( !(s_hArialBlackItalic = CreateFontIndirect(&lf)) )
            {
                DeleteObject(s_hArialBlack);
                return -1;
            }

            lf.lfWeight = FW_BOLD;
            lf.lfItalic = false;

            if( !(s_hArialBlackBold = CreateFontIndirect(&lf)) )
            {
                DeleteObject(s_hArialBlackItalic);
                DeleteObject(s_hArialBlack);
                return -1;
            }
        }
        break;

        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            BeginPaint(hwnd, &ps);
            HFONT hFont = (HFONT)SelectObject(ps.hdc, s_hArialBlack);
            TextOut(ps.hdc, 20, 10, L"Font Arial Black", 16);
            SelectObject(ps.hdc, s_hArialBlackItalic);
            TextOut(ps.hdc, 20, 50, L"Font Arial Black Italic", 23);
            SelectObject(ps.hdc, s_hArialBlackBold);
            TextOut(ps.hdc, 20, 90, L"Font Arial Black Bold", 21);
            SelectObject(ps.hdc, hFont);
            EndPaint(hwnd, &ps);
        }
        break;

        case WM_DESTROY:
        DeleteObject(s_hArialBlackBold);
        DeleteObject(s_hArialBlackItalic);
        DeleteObject(s_hArialBlack);
        PostQuitMessage(0);
        break;

        default:

        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
} 

This is the screen shot I referred to above :

enter image description here

like image 831
WaldB Avatar asked Jun 18 '12 17:06

WaldB


1 Answers

The function doesn't exist simply because there is no one-to-one mapping from logical fonts to physical fonts. You already found that out partially by discovering the you don't have a dedicated set of outlines for italic. Windows synthesizes missing styles by applying a transform on the outline. That same synthesis didn't do anything special with the bold style, the font is already bold.

It gets much more convoluted when you display text that uses glyphs for which the font doesn't have an outline. Like Chinese characters. Then Windows completely substitutes another font that has the requested glyph. Clearly that makes implementing the kind of function you want impossible.

Consider the Uniscribe api if you want better control over this process.

like image 59
Hans Passant Avatar answered Oct 03 '22 09:10

Hans Passant