Windows: Getting a window title bar's height

Viewed 5285

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?

4 Answers

Send a message WM_GETTITLEBARINFOEX to the window, and you will get the bounding rectangle of the title bar.

TITLEBARINFOEX * ptinfo = (TITLEBARINFOEX *)malloc(sizeof(TITLEBARINFOEX));
ptinfo->cbSize = sizeof(TITLEBARINFOEX);
SendMessage(hWnd, WM_GETTITLEBARINFOEX,0, (LPARAM)ptinfo);
int height = ptinfo->rcTitleBar.bottom- ptinfo->rcTitleBar.top;
int width = ptinfo->rcTitleBar.right - ptinfo->rcTitleBar.left;
free(ptinfo);

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 }; // Practicaly 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.

First, make sure your application is high DPI aware so that the system doesn't lie to you.

Options:

  1. Trust GetSystemMetrics. Nearly any top-level window that actually has a different caption size is doing custom non-client area management which is going to make it (nearly) impossible. The obvious exception is a tool window (WS_EX_TOOLWINDOW) which probably has a SM_CYSMCAPTION height if the WS_CAPTION style is also set.

  2. Get the target window rect and the target window's style. Use AdjustWindowRectEx to determine the size differences with the WS_CAPTION style toggled. I'm not sure if this will work because there may be some interaction between on whether you can have a caption without some kind of border.

  3. Get the target window rect and send WM_HITTEST messages for coordinates that move down the window. Count how many of those get HT_CAPTION in return. Bonus points if you do this with a binary search rather than a linear search. This is probably the hardest and the most reliable way to do it, assuming the window has a rectangular caption area.

If I've understood correctly, it looks like you want to take the border size of the window (which we should be able to gather from the width as there is no title bar) and subtract it from the the verticle size minus the client window...

inline int get_title_bar_thickness(const HWND window_handle)
{
    RECT window_rectangle, client_rectangle;
    int height, width;
    GetWindowRect(window_handle, &window_rectangle);
    GetClientRect(window_handle, &client_rectangle);
    height = (window_rectangle.bottom - window_rectangle.top) -
    (client_rectangle.bottom - client_rectangle.top);
    width = (window_rectangle.right - window_rectangle.left) - 
    (client_rectangle.right - client_rectangle.left);
    return height - (width/2);
}
Related