c++windowswinapi

Windows: Getting a window title bar's height


I was trying to get the height of the title bar of a specific window on Windows. You can replicate it with Notepad. I'm using C++ and none of the codes I found online yielded the correct result. Using e.g. Screenpresso I measured 31 pixels for my window bar height.

The functions I tried are the following:

TitleBarHeight.h:

#pragma once

#include <windows.h>

inline int get_title_bar_thickness_1(const HWND window_handle)
{
    RECT window_rectangle, client_rectangle;
    GetWindowRect(window_handle, &window_rectangle);
    GetClientRect(window_handle, &client_rectangle);
    return window_rectangle.bottom - window_rectangle.top -
        (client_rectangle.bottom - client_rectangle.top);
}

inline int get_title_bar_thickness_2(const HWND window_handle)
{
    RECT window_rectangle, client_rectangle;
    GetWindowRect(window_handle, &window_rectangle);
    GetClientRect(window_handle, &client_rectangle);
    return (window_rectangle.right - window_rectangle.left - client_rectangle.right) / 2;
}

Results:

auto window_handle = FindWindow("Notepad", nullptr);
auto a = get_title_bar_thickness_1(window_handle); // 59
auto b = get_title_bar_thickness_2(window_handle); // 8
auto c = GetSystemMetrics(SM_CXSIZEFRAME); // 4
auto d = GetSystemMetrics(SM_CYCAPTION); // 23

Getting the system metrics with GetSystemMetrics() does not work because windows can have different title bar heights obviously and there is no argument for the window handle.

How can I really get the result of 31?


Solution

  • Assuming that you don't have menu bar, you can map points from client coordinate system to screen one.

    RECT wrect;
    GetWindowRect( hwnd, &wrect );
    RECT crect;
    GetClientRect( hwnd, &crect );
    POINT lefttop = { crect.left, crect.top }; // Practically both are 0
    ClientToScreen( hwnd, &lefttop );
    POINT rightbottom = { crect.right, crect.bottom };
    ClientToScreen( hwnd, &rightbottom );
    
    int left_border = lefttop.x - wrect.left; // Windows 10: includes transparent part
    int right_border = wrect.right - rightbottom.x; // As above
    int bottom_border = wrect.bottom - rightbottom.y; // As above
    int top_border_with_title_bar = lefttop.y - wrect.top; // There is no transparent part
    

    Got 8, 8, 8 and 31 pixels (96DPI aka 100% scaling setting)

    You should also take into account DPI awareness mode. Especially GetSystemMetrics is tricky because it remembers state for System DPI when your application was launched.