You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 05:39:04