콘텐츠로 건너뛰기

윈도우가 다른 윈도우에 가려졌는지 확인하는 방법 – CombineRgn

윈도우 화면을 제어하는 프로그램을 개발할 때, 내가 만든 윈도우 또는 제어 대상 윈도우가 다른 윈도우에 가려졌는지 확인하는 상황이 발생할 수 있습니다. 사용자 관점에서는 다른 윈도우에 완전히 가려진 윈도우는 보이지 않기 때문에, 이런 경우 해당 윈도우를 없는 것처럼 처리하는 것이 좋습니다. 이번 포스팅에서는 CombineRgn과 GetNextWindow Win32 API를 활용하여 윈도우가 다른 윈도우에 가려졌는지 확인하는 방법을 살펴보겠습니다.

윈도우가 겹치는 유형

Win32API에서 윈도우 핸들(HWND) 기반으로 윈도우가 최소화 되었는지, 또는 현재 화면에 보여지고 있는 윈도우인지 여부를 쉽게 파악할 수 있습니다. 그러나 윈도우가 다른 윈도우에 의해 가려졌는지 여부를 직접적으로 확인하는 기능은 제공되지 않습니다.

일반적으로 윈도우가 겹치는 경우는 다음 그림과 같이 4개 유형으로 나누어 살펴볼 수 있습니다

  • Case #1: 다른 윈도우와 겹치는 않는 경우
  • Case #2: 다른 윈도우에 일부 겹친 경우
  • Case #3: 다른 윈도우에 가려져 보이지 않는 경우
  • Case #4: 다른 윈도우에 가려졌으나 윈도우가 투명도가 존재하여 화면이어서 보이는 경우

윈도우가 다른 윈도우에 가려졌는지 확인하는 방법

윈도우가 다른 윈도우에 가려졌는지 확인하려면, 대상 윈도우의 영역(Region)에서 상위 윈도우의 영역을 빼는 방식으로 계산할 수 있습니다. 이때, 투명 속성을 가진 윈도우는 계산에서 제외해야 합니다. 이를 통해 대상 윈도우 영역에서 남은 영역이 없으면, 해당 윈도우가 다른 윈도우에 완전히 가려진 것으로 판단할 수 있습니다.

이렇게 Region을 계산을 할 경우 아래 그림과 같이 표현할 수 있습니다.

예시 코드 ( CombineRgn 활용 )

아래 소스코드는 윈도우가 다른 윈도우에 의해 가려졌는지 확인하는 소스 코드입니다.

BOOL IsObscuredWindow(HWND hwnd)
{
    if (hwnd == NULL) return FALSE;

    BOOL is_obscured = FALSE;
    HWND current_window = hwnd;

    // 대상 윈도우의 영역 가져오기
    RECT target_rect;
    if (!GetWindowRect(hwnd, &target_rect)) return FALSE;
    HRGN target_region = CreateRectRgnIndirect(&target_rect);
    if (target_region == NULL) return FALSE;

    // 상위 윈도우를 탐색하면서 영역 비교
    while ((current_window = GetNextWindow(current_window, GW_HWNDPREV)) != NULL)
    {
        // 상위 윈도우가 보이지 않으면 건너뛴다
        if (!IsWindowVisible(current_window)) continue;

        // 상위 윈도우의 확장 스타일 가져오기
        LONG_PTR style = GetWindowLongPtrW(current_window, GWL_EXSTYLE);

        // 투명 또는 레이어된 윈도우는 무시
        if (style & (WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP | WS_EX_TRANSPARENT)) continue;

        // 상위 윈도우의 영역 가져오기
        RECT current_rect;
        if (!GetWindowRect(current_window, current_rect)) continue;

        // 영역 생성 및 비교
        HRGN current_region = CreateRectRgnIndirect(current_rect);
        if (current_region == NULL) continue;

        // 두 윈도우 영역 비교
        int combine_result = CombineRgn(target_region, target_region, current_region, RGN_DIFF);
        DeleteObject(current_region);

        // 대상 윈도우가 완전히 가려졌을 때
        if (combine_result == NULLREGION)
        {
            is_obscured = TRUE;
            break;
        }
    }

    // 메모리 해제
    DeleteObject(target_region);

    return is_obscured;
}

참고 자료

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

목차 보기