화면을 제어하는 프로그램에서 내가 만든 윈도우 또는 제어해야 하는 윈도우가 다른 윈도우에 가려졌는지 확인해야 하는 경우가 있습니다. 다른 화면에 완전히 가려진 경우 사용자 관점에서는 보이지 않는 윈도우이므로 없는 것 처럼 처리해야 합니다. 윈도우가 다른 윈도우에 가려졌는지 확인 방법에 대해 알아보도록 하겠습니다.
윈도우가 겹치는 케이스 유형
Win32API에서 Window Handle(HWND) 기반으로 최소화 되었는지 실제 보여지는 윈도우 인지 쉽게 파악할 수 있으나 다른 윈도우에 가려진 여부는 Win32API만 가지고 쉽게 파악할 수 없습니다.
일반적으로 윈도우가 겹치는 경우는 다음 그림과 같이 4개 유형으로 나누어 살펴볼 수 있습니다.
- Case #1: 다른 윈도우와 겹치는 않는 경우
- Case #2: 다른 윈도우에 일부 겹친 경우
- Case #3: 다른 윈도우에 가려져 보이지 않는 경우
- Case #4: 다른 윈도우에 가려졌으나 윈도우가 투명도가 존재하여 화면이어서 보이는 경우
윈도우가 다른 윈도우에 가려졌는지 확인하기
대상 윈도우 Region에서 상위 윈도우 Region을 빼고 남은 영역이 없으면 다른 윈도우에 가려졌다고 판단할 수 있습니다. 단, 상위 윈도우에 투명 속성이 있을 경우는 계산에서 제외합니다
이렇게 Region을 계산을 할 경우 아래 그림과 같이 표현할 수 있습니다.
소스 코드
Window Handle이 겹쳐 있는지 확인하는 코드는 다음과 같습니다.
BOOL IsObscuredWindow(HWND hwnd)
{
BOOL ret = FALSE;
HWND window_handle = hwnd;
RECT target_rect = { 0, };
GetWindowRect(hwnd, &target_rect);
HRGN target_region = CreateRectRgnIndirect(&target_rect);
if ( NULL == target_region )
{
return FALSE;
}
RECT current_rect = { 0, };
HRGN current_region = NULL;
LONG_PTR style = 0L;
while ( (window_handle = GetNextWindow(window_handle, GW_HWNDPREV)) != NULL )
{
if ( !IsWindowVisible(window_handle) )
{
continue;
}
style = GetWindowLongPtrW(window_handle, GWL_EXSTYLE);
if ((style & WS_EX_LAYERED) || (style & WS_EX_NOREDIRECTIONBITMAP) || (style & WS_EX_TRANSPARENT))
{
continue;
}
GetWindowRect(window_handle, ¤t_rect);
current_region = CreateRectRgnIndirect(¤t_rect);
if ( NULL == current_region )
{
continue;
}
if ( NULLREGION == CombineRgn(target_region, target_region, current_region, RGN_DIFF) )
{
ret = TRUE;
break;
}
DeleteObject(current_region);
}
DeleteObject(target_region);
return ret;
}