Windows:获取窗口标题栏的高度

时间:2019-06-11 18:35:48

标签: c++ windows winapi

我试图获取Windows上特定窗口标题栏的高度。您可以使用Notepad复制它。我正在使用C++,但在网上找到的所有代码均未产生正确的结果。使用例如Screenpresso我为窗口栏高度测量了31个像素。

我尝试过的功能如下:

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;
}

结果:

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

使用GetSystemMetrics()获取系统指标不起作用,因为窗口显然具有不同的标题栏高度,并且窗口句柄没有参数。

我怎样才能真正得到31的结果?

4 个答案:

答案 0 :(得分:2)

假设您没有菜单栏,则可以将客户端坐标系中的点映射到屏幕上

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

获得8、8、8和31像素(96DPI,也就是100%缩放比例设置)

您还应该考虑DPI感知模式。特别是GetSystemMetrics棘手,因为它会在启动应用程序时记住系统DPI的状态。

答案 1 :(得分:1)

如果我正确理解,则好像您要获取窗口的边框大小(由于没有标题栏,我们应该能够从宽度中收集它)并从垂直大小减去中减去客户窗口...

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);
}

答案 2 :(得分:1)

首先,请确保您的应用程序具有较高的DPI意识,以免系统对您说谎。

选项:

  1. 信任GetSystemMetrics。几乎所有实际上具有不同字幕大小的顶级窗口都在执行自定义非客户区域管理,这将使其(几乎)成为不可能。一个明显的例外是工具窗口(WS_EX_TOOLWINDOW),如果还设置了WS_CAPTION样式,则该窗口可能具有SM_CYSMCAPTION高度。

  2. 获取目标窗口rect和目标窗口的样式。使用AdjustWindowRectEx通过切换WS_CAPTION样式来确定大小差异。我不确定这是否行得通,因为您是否可以在没有某种边框的情况下进行字幕之间可能存在一些互动。

  3. 获取目标窗口rect并发送WM_HITTEST消息以获取在窗口中向下移动的坐标。计算其中有多少人获得HT_CAPTION作为回报。如果您通过二进制搜索而不是线性搜索执行此操作,则可获得加分。假设窗口具有矩形标题区域,这可能是最困难,最可靠的方法。

答案 3 :(得分:1)

向窗口发送消息WM_GETTITLEBARINFOEX,您将获得标题栏的边界矩形。

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);