[cpp] 윈도우 찾기

@codemaru · June 16, 2015 · 10 min read

HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName);

FindWindow 함수는 탑레벨 윈도우 중에서 원하는 윈도우를 찾는 기능을 한다. 탑레벨 윈도우란 desktop 윈도우를 부모로 갖는 윈도우를 말한다. 첫 번째 인자에는 찾고자 하는 윈도우의 클래스 이름을 넣어주면 된다. NULL을 지정할 경우에는 윈도우를 찾을 때 클래스 이름은 무시하고 찾는다. 두 번째 인자로 찾고자 하는 윈도우의 윈도우 이름을 넣어준다. 첫 번째 인자와 마찬가지로 NULL을 넣을 경우 이 항목은 무시된다. 윈도우의 핸들이 리턴 된다. 윈도우가 없다면 NULL이 리턴 된다. FindWindow(“#32770″, “TEST”)와 같이 사용할 경우 클래스 이름이 #32770이고 캡션이 TEST인 윈도우를 찾는다. FindWindow(“#32770″, NULL)과 같이 사용할 경우엔 캡션에 관계없이 클래스 이름이 #32770인 윈도우를 찾는다.

HWND FindWindowEx(HWND hwndParent
                  , HWND hwndChildAfter
                  , LPCTSTR lpszClass
                  , LPCTSTR lpszWindow);

FindWindowEx는 특정 윈도우의 자식 윈도우 중에서 원하는 윈도우를 찾아준다. 첫 번째 인자로 찾고자 하는 윈도우의 부모 핸들을 넣어준다. 만약 NULL을 넣게 되면 FindWindow와 마찬가지로 Top 윈도우를 찾는다. 두 번째 인자로 검색 시작이 될 자식 윈도우를 넣어준다. 일반적으로 윈도우는 많은 자식 윈도우를 가지고 있다. 그 중에서 특정 자식 윈도우 다음부터 검사하고 싶은 경우 이 인자를 사용하면 된다. NULL을 지정할 경우 처음부터 검사한다. 세 번째, 네 번째 인자는 FindWindow의 인자와 같은 의미를 가진다. 리턴 값도 FindWindow와 동일하다. 아래 코드는 위에서 찾은 다이알로그의 자식 중에 확인 버튼을 찾는 것을 보여준다.

HWND hwnd = FindWindow("32770", "TEST")
HWND button = FindWindowEx(hwnd, NULL, "BUTTON", "확인");

위의 두 함수 외에도 직접적으로 윈도우를 찾는 함수는 아니지만 도움이 되는 함수가 있다. GetNextWindow와 GetWindow가 그것이다.

HWND GetNextWindow(HWND hWnd, UINT wCmd);

GetNextWindow는 z-order 상에서 다음에 있는 윈도우나 이전에 있는 윈도우를 찾는 기능을 한다. 첫 번째 인자로 검색 대상이 될 윈도우를 넣어주면 된다. 두 번째 인자는 GW_HWNDNEXT나 GW_HWNDPREV중에 하나를 넣으면 된다. GW_HWNDNEXT를 넣을 경우 z-order 상에서 다음에 존재하는 윈도우를 리턴 하고, GW_HWNDPREV를 넣을 경우 z-order 상에서 이전에 존재하는 윈도우를 리턴 한다.

HWND GetWindow(HWND hWnd, UINT uCmd);

GetWindow는 대상 윈도우로부터 특정한 관계에 있는 윈도우를 찾는 기능을 한다. GetNextWindow의 일반화된 버전이라고 생각할 수 있다. 첫 번째 인자로는 대상이 되는 윈도우를 넣으면 된다. 두 번째 인자로는 다음 목록에 있는 것 중에 하나를 넣어주면 된다.

  • GW_CHILD
    대상 윈도우의 자식 중에서 z-order가 가장 위에 있는 윈도우를 리턴 한다. 만약 대상 윈도우의 자식이 없다면 NULL을 리턴 한다.

  • GW_ENABLEDPOPUP
    Windows 2000/XP이상에 적용되는 값이다. 대상 윈도우 다음윈도우 중에서 팝업 윈도우를 찾아서 리턴 한다. 팝업 윈도우가 없는 경우엔 NULL을 리턴 한다.

  • GW_HWNDFIRST
    같은 계층의 윈도우 중에서 가장 높은 z-order를 가지는 윈도우를 리턴 한다. 만약 대상 윈도우가 Top 레벨 윈도우라면 Top 레벨 윈도우 중에서 가장 높은 z-order를 가지는 윈도우를 리턴 한다. 만약 대상 윈도우가 자식 윈도우라면 형제 윈도우 중에서 가장 높은 z-order를 가지는 윈도우를 리턴 한다.

  • GW_HWNDLAST
    같은 계층의 윈도우 중에서 가장 낮은 z-order를 가지는 윈도우를 리턴 한다. 만약 대상 윈도우가 Top 레벨 윈도우라면 Top 레벨 윈도우 중에서 가장 낮은 z-order를 가지는 윈도우를 리턴 한다. 만약 대상 윈도우가 자식 윈도우라면 형제 윈도우 중에서 가장 낮은 z-order를 가지는 윈도우를 리턴 한다.

  • GW_HWNDNEXT
    대상 윈도우의 다음 z-order를 가지는 윈도우를 리턴 한다. GetNextWindow의 두 번째 인자에 사용되는 의미와 동일하다.

  • GW_HWNDPREV
    대상 윈도우의 이전 z-order를 가지는 윈도우를 리턴 한다. GetNextWindow의 두 번째 인자에 사용되는 의미와 동일하다.

  • GW_OWNER
    대상 윈도우의 소유자 윈도우를 리턴 한다.

HWND GetDesktopWindow(VOID);

Desktop 윈도우를 구하는 함수다. 모든 Top 레벨 윈도우는 이 윈도우의 자식이다. 또한 Spy++에서 가장 위에 표시되는 윈도우 이기도 하다. 인자는 없고 리턴 값이 Desktop 윈도우 핸들이다.

HWND GetShellWindow(VOID);

Shell 윈도우를 구하는 함수다. Shell 윈도우는 작업 표시줄 윈도우를 말한다. 인자는 없고 리턴 값은 Shell 윈도우 핸들이다.

HWND GetForegroundWindow(VOID);

Foreground 윈도우 핸들을 구하는 함수다. Foreground 윈도우란 사용자와 상호 작용을 하고 있는 윈도우를 말한다. Windows가 멀티태스킹 시스템 이지만 사용자와 상호 작용을 하는 윈도우는 하나밖에 없다. 인자는 없고 리턴 값이 foreground 윈도우 핸들이다. Foreground 윈도우가 없는 경우 NULL을 리턴 한다.

HWND GetParent(HWND hWnd);

부모 윈도우를 구해주는 함수다. 인자로 대상 윈도우 핸들을 넣어주면 부모 윈도우 핸들을 리턴 한다. 만약 대상 윈도우가 top 레벨 윈도우 이거나 함수 수행에 실패한 경우 NULL을 리턴 한다.

HWND GetTopWindow(HWND hWnd);

첫 번째 자식 윈도우(자식 윈도우 중에서 z-order가 가장 높은 것)를 구하는 함수다. 인자로 윈도우 핸들을 넣어주면 첫 번째 자식 윈도우를 리턴 한다. 자식이 없거나 동작이 실패한 경우 NULL을 리턴 한다.

HWND GetAncestor(HWND hwnd, UINT gaFlags);

조상 윈도우를 구하는 함수다. 첫 번째 인자로 윈도우 핸들을, 두 번째 인자로 다음 목록에 있는 값 중에 하나를 넣어주면 된다. 리턴 값은 첫 번째 인자로 전달된 윈도우에 대한 조상 윈도우 핸들이다. 전달된 윈도우가 탑 레벨 윈도우일 경우 NULL이 리턴 된다.

  • GA_PARENT

부모 윈도우를 리턴 한다.

  • GA_ROOT

최 상단 부모 윈도우를 리턴 한다.

  • GA_ROOTOWNER

최 상단 부모 윈도우를 소유한 윈도우를 리턴 한다.

끝으로 앞서 배운 함수를 통해서 특정 윈도우의 하위에 존재하는 모든 윈도우를 열거하는 방법을 알아보자. GetWindow 함수와 재귀 호출 함수를 사용하면 손쉽게 구현할 수 있다. 아래 이렇게 구현해 본 ScrabWindow 함수가 있으니 참고해 보도록 하자.

모든 자식 윈도우를 수집하는 ScrabWindow 함수 소스 코드 다운로드

typedef BOOL (CALLBACK *ScrabWindowCallback)(HWND hwnd);

BOOL
ScrabWindow(HWND hwnd, ScrabWindowCallback cb)
{

	try
	{
		if(!cb(hwnd))
			return FALSE;
	}
	catch(...)
	{
		return FALSE;
	}

	HWND c = GetWindow(hwnd, GW_CHILD);
	if(!c)
		return TRUE;

	for( ; c; c = GetWindow(c, GW_HWNDNEXT))
	{
		if(!ScrabWindow(c, cb))
			return FALSE;
	}

	return TRUE;
}

BOOL
CALLBACK
PrintWindow(HWND hwnd)
{
	printf("%08x\n", hwnd);
	return TRUE;
}

int main()
{
	ScrabWindow(GetDesktopWindow(), PrintWindow);

    return 0;
}
@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중