如何使用Windows API判断窗口内指定RECT区域是否被其他窗口遮挡
Windows API 实现窗口指定区域可见性判断函数
实现逻辑
通过区域裁剪的方式完成校验:先将目标客户端区域转换为屏幕坐标,生成初始可见区域,再依次裁剪所有Z序位于当前窗口上方的可见窗口的区域,最终判断剩余区域是否为空,即可得出指定区域是否可见。
完整代码实现
#include <windows.h> bool isWindowPartVisible(HWND handle, RECT rect) { // 窗口本身不可见直接返回false if (!IsWindowVisible(handle)) { return false; } // 将传入的客户端RECT转换为屏幕坐标RECT POINT topLeft = { rect.left, rect.top }; POINT bottomRight = { rect.right, rect.bottom }; ClientToScreen(handle, &topLeft); ClientToScreen(handle, &bottomRight); RECT screenRect = { topLeft.x, topLeft.y, bottomRight.x, bottomRight.y }; // 目标区域为空直接返回false if (screenRect.left >= screenRect.right || screenRect.top >= screenRect.bottom) { return false; } // 初始化可见区域为目标屏幕区域 HRGN visibleRgn = CreateRectRgnIndirect(&screenRect); if (!visibleRgn) { return false; } // 遍历所有Z序在当前窗口上方的顶层窗口 HWND hWndAbove = GetWindow(handle, GW_HWNDPREV); while (hWndAbove) { if (IsWindowVisible(hWndAbove)) { RECT aboveWndRect; if (GetWindowRect(hWndAbove, &aboveWndRect)) { // 仅处理和目标区域有交集的上层窗口,提升效率 if (RectInRegion(visibleRgn, &aboveWndRect)) { HRGN aboveRgn = CreateRectRgnIndirect(&aboveWndRect); if (aboveRgn) { HRGN tempRgn = CreateRectRgn(0, 0, 0, 0); // 从可见区域中减去上层窗口的遮挡区域 CombineRgn(tempRgn, visibleRgn, aboveRgn, RGN_DIFF); DeleteObject(visibleRgn); visibleRgn = tempRgn; DeleteObject(aboveRgn); } } } } hWndAbove = GetWindow(hWndAbove, GW_HWNDPREV); } // 判断最终可见区域是否为空 int rgnType = GetRgnBox(visibleRgn, nullptr); DeleteObject(visibleRgn); return rgnType != NULLREGION; }
注意事项
- 上述实现默认仅判断顶层窗口的遮挡,如果需要排除当前窗口自身子窗口的遮挡,可额外调用
EnumChildWindows遍历当前窗口的子窗口,重复上述区域裁剪逻辑即可。 - 半透明、异形窗口也会被判定为遮挡,如果需要跳过完全透明的分层窗口,可增加
GetLayeredWindowAttributes调用判断窗口透明度,透明度为0的窗口跳过裁剪。 - 所有GDI区域对象使用完成后必须调用
DeleteObject释放,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Ehsan Sharifi Esfahani
相关产品推荐
相关产品推荐

