Windows判断某窗口是否被其他窗口完全覆盖

bool IsCompletelyCovered(HWND hWnd)
{
    // 1. 基本有效性检查
    if (!IsWindow(hWnd))
        return true;

    // 2. 如果窗口不可见或最小化,认为被覆盖
    if (!IsWindowVisible(hWnd) || IsIconic(hWnd))
        return true;

    // 3. 获取窗口矩形
    RECT rect;
    if (!GetWindowRect(hWnd, &rect))
        return true;

    LONG width = rect.right - rect.left;
    LONG height = rect.bottom - rect.top;
    if (width <= 0 || height <= 0)
        return true;

    // 4. 定义采样点(13个)
    POINT points[] = { 
        { rect.left, rect.top },                                    // 左上
        { rect.right - 1, rect.top },                               // 右上
        { rect.left, rect.bottom - 1 },                             // 左下
        { rect.right - 1, rect.bottom - 1 },                        // 右下
        { rect.left + width / 2, rect.top },                        // 上中
        { rect.left + width / 2, rect.bottom - 1 },                 // 下中
        { rect.left, rect.top + height / 2 },                       // 左中
        { rect.right - 1, rect.top + height / 2 },                  // 右中
        { rect.left + width / 2, rect.top + height / 2 },           // 中心
        { rect.left + width / 4, rect.top + height / 4 },           // 左上区域中心
        { rect.left + 3 * width / 4, rect.top + height / 4 },       // 右上区域中心
        { rect.left + width / 4, rect.top + 3 * height / 4 },       // 左下区域中心
        { rect.left + 3 * width / 4, rect.top + 3 * height / 4 }    // 右下区域中心
    }; 
#ifdef _DEBUG
    std::set<HWND> coveringWindows;   // 用于去重保存遮挡窗口句柄
#endif // _DEBUG

    // 5. 检查每个采样点
    for (const auto& pt : points) 
    {
        HWND hWndAtPt = WindowFromPoint(pt);
        // 如果获取失败,视为该点不可达(可能被系统级窗口覆盖)
        if (hWndAtPt == NULL)
        {
            continue;
        }

        // 如果点所在窗口是目标窗口本身或其子窗口,则属于目标窗口区域
        if ((hWndAtPt == hWnd) || IsChild(hWnd, hWndAtPt))
        {
            return false;
        }
#ifdef _DEBUG
        coveringWindows.insert(hWndAtPt);
#endif // _DEBUG
    }

#ifdef _DEBUG
    // 所有采样点都被其他窗口覆盖
    if (!coveringWindows.empty())
    {
        //输出目标窗口信息
        TCHAR targetTitle[256] = { 0 };
        TCHAR targetClass[256] = { 0 };
        GetWindowText(hWnd, targetTitle, _countof(targetTitle));
        GetClassName(hWnd, targetClass, _countof(targetClass));
        TCHAR wndBuf[1024] = { 0 };
        LOG(INFO) << u8"------------------------------------------------------";
        _stprintf_s(wndBuf, _T("目标窗口:句柄=\"0x%p\",标题=\"%s\",类名=\"%s\""), hWnd, targetTitle, targetClass);
        LOG(INFO) << wndBuf;
        LOG(INFO) << u8"遮挡窗口个数:" << coveringWindows.size();
        int i = 1;
        for (HWND hCover : coveringWindows)
        {
            TCHAR coverTitle[256] = { 0 };
            TCHAR coverClass[256] = { 0 };
            GetWindowText(hCover, coverTitle, _countof(coverTitle));
            GetClassName(hCover, coverClass, _countof(coverClass));
            TCHAR coverBuf[1024] = { 0 };
            _stprintf_s(coverBuf, _T("遮挡窗口%d:句柄=\"0x%p\",标题=\"%s\",类名=\"%s\""), i++, hCover, coverTitle, coverClass);
            LOG(INFO) << coverBuf;
        }
    }    
#endif // _DEBUG

    return true;
}

  

说明:

1.如果子窗口遮挡了父窗口,该方法不认为被遮挡,因为子属于父的一部分。如果不需要这样处理,可将IsChild条件去掉。

2.该函数增加了打印信息,如果不需要,可将Debug宏包围的代码全部删除。

posted @ 2026-03-12 18:37  快雪  阅读(1)  评论(0)    收藏  举报