Calculating dialog units on lfMessageFont - Buttons too big, Segoe UI 1pt too large

Viewed 65

I'm trying to create pushbuttons matching the style of those in default message boxes and I've been told that using SystemParametersInfo I can retrieve lfMessagefont which should correspond to the font I'm looking for. Unfortunately, that doesn't seem to be the case and I don't know what I'm doing wrong. Here are the functions used to retrieve the font and to create the buttons:

HFONT CreateDefaultUIFont() 
{
    NONCLIENTMETRICS ncInfo;
    ncInfo.cbSize = sizeof(NONCLIENTMETRICS);
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncInfo, 0);
    return CreateFontIndirect(&ncInfo.lfMessageFont);
}

SIZE GetBaseUnits(HWND hWnd, HFONT hFont) 
{
    TCHAR szText[] = TEXT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
    HDC   hDC;
    HFONT hFt;
    SIZE  size;
    hDC = GetDC(hWnd);
    hFt = SelectObject(hDC, hFont);
    GetTextExtentPoint32(hDC, szText, 52, &size);
    SelectObject(hDC, hFt);
    ReleaseDC(hWnd, hDC);
    size.cx = (size.cx / 26 + 1) / 2;
    return size;
}

HWND CreateButton(HINSTANCE hInstance, HWND hParent, HFONT hFont, PTSTR szText, int xPos, int yPos)
{
    HWND hWnd;
    SIZE size;
    hWnd = CreateWindow(TEXT("Button"), szText, WS_CHILD | BS_PUSHBUTTON, 0, 0, 0, 0, hParent, NULL, hInstance, NULL);
    SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, FALSE);
    size = GetBaseUnits(hWnd, hFont);
    MoveWindow(hWnd, xPos, yPos, MulDiv(50, size.cx, 4), MulDiv(14, size.cy, 8), TRUE);
    ShowWindow(hWnd, SW_SHOW);
    return hWnd;
}

And here's the rest of the code:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{
    static HINSTANCE   hInstance;
    static HWND        hCtl[2];
    static HFONT       hFont;
    static HDC         hDC;
    static PAINTSTRUCT paint;
    static RECT        rect;

    switch (message) {
    case WM_CREATE:
        hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
        // hFont = GetStockObject(DEFAULT_GUI_FONT);
        hFont = CreateDefaultUIFont();
        // hFont = GetStockObject(DEVICE_DEFAULT_FONT);
        hCtl[0] = CreateButton(hInstance, hWnd, hFont, TEXT("OK"), 15, 15);
        hCtl[1] = CreateButton(hInstance, hWnd, hFont, TEXT("Cancel"), 15, 50);
        return 0;
    case WM_DESTROY:
        DeleteObject(hFont);
        PostQuitMessage(0);
        return 0;
    case WM_PAINT:
        hDC = BeginPaint(hWnd, &paint);
        SaveDC(hDC);
        GetClientRect(hWnd, &rect);
        SelectObject(hDC, hFont);
        DrawText(hDC, TEXT("Failed to register the window class"), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
        RestoreDC(hDC, -1);
        EndPaint(hWnd, &paint);
        return 0;
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) 
{
    const TCHAR szAppName[] = TEXT("Window");
    HWND        hwnd;
    MSG         msg;
    WNDCLASS    wndclass;
    RECT        rect;
    DWORD       dwStyle;
    LONG        nWidth, nHeight;

    wndclass.style         = CS_OWNDC;
    wndclass.lpfnWndProc   = WndProc;
    wndclass.cbClsExtra    = 0;
    wndclass.cbWndExtra    = 0;
    wndclass.hInstance     = hInstance;
    wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName  = NULL;
    wndclass.lpszClassName = szAppName;

    if (!RegisterClass(&wndclass)) {
        MessageBox(NULL, TEXT("Failed to register the window class"), TEXT("Error"), MB_OK | MB_ICONERROR);
        return 1;
    }

    rect.left   = 0;
    rect.top    = 0;
    rect.right  = 480 - 1;
    rect.bottom = 360 - 1;
    dwStyle     = WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MAXIMIZEBOX);

    AdjustWindowRect(&rect, dwStyle, FALSE);

    nWidth  = rect.right - rect.left + 1;
    nHeight = rect.bottom - rect.top + 1;

    hwnd = CreateWindow(szAppName, szAppName, dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, 
        nWidth, nHeight, NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    MessageBox(NULL, TEXT("Failed to register the window class"), TEXT("Error"), MB_OKCANCEL | MB_ICONERROR);

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int)msg.wParam;
}

This is how it looks on Windows 10 19043. The font is Segoe UI as it should be except 1pt too big

1 2

Here's how it looks when I use DEFAULT_GUI_FONT. The size of the buttons is correct but they use Tahoma at 8pt

4 3

Is there any way to obtain the fonts used in message boxes that would work across different Windows versions?

0 Answers
Related