정보공간_1

[4기 신촌 김형진] 다른 윈도우의 핸들을 얻고 제어하기 본문

IT 놀이터/Elite Member Tech & Talk

[4기 신촌 김형진] 다른 윈도우의 핸들을 얻고 제어하기

알 수 없는 사용자 2013. 12. 5. 11:22

안녕하세요.

신촌멤버십 22-2기 김형진입니다.

이번에는 Windows API를 이용하여 다른 윈도우의 정보를 읽어오는 방법을 소개하겠습니다.

C++ 기준으로 작성하였으며, C# Windows API를 사용 가능한 언어에서도 같은 방법으로 적용 가능합니다.

 

윈도우를 제어하기 위해서는 HWND 형식의 윈도우를 구별하는 고유한 핸들 값을 알고 있어야 합니다. 내가 만든 프로그램의 HWND값은 CreateWindow 함수의 리턴값이 됩니다.

하지만, 내가 만든 프로그램이 아닌, 다른 프로그램의 윈도우의 핸들을 얻어오기 위해서는 원하는 윈도우의 타이틀 혹은 프로그램의 클래스 이름을 알고 있어야 합니다. 이를 FindWindow라고 하는 함수에 넘겨주면 해당 윈도우의 HWND를 얻을 수 있습니다.

FindWindow 함수의 원형은 다음과 같습니다. LPCTSTR은 문자열을 의미합니다.

HWND WINAPI FindWindow(
_In_opt_ LPCTSTR lpClassName,
_In_opt_ LPCTSTR lpWindowName
);

이 함수의 기능은 검색조건에 맞는 윈도우 중에서 가장 최상위에 있는 윈도우를 찾는 것입니다. 둘 중 하나의 조건만 지정하면 찾을 수 있습니다.

첫 번째 인자는 RegisterClass를 통해 등록된 클래스 이름을 통해 찾도록 하는 것인데, 이를 통해 찾으면 정확하게 찾을 수 있지만, 일반적으로 내가 만들지 않은 프로그램의 클래스 이름을 알기는 쉽지 않으므로, 두 번째 인자를 자주 사용하게 됩니다.

두 번째 인자는 창 이름을 통해 찾도록 지정하는 것입니다. 이를 통해 원하는 프로그램의 핸들을 얻어올 수 있습니다. 예를 들어 그림판을 찾는 경우는 다음과 같이 지정하면 얻을 수 있습니다. 윈도우를 찾을 수 없다면 NULL을 리턴합니다.

HWND hwndPaint = FindWindow(NULL, "제목 없음 - 그림판");

 

물론, 일부 프로그램의 경우는 창 이름을 지정하더라도 잘 찾아지지 않는 경우가 있습니다. 바로 위의 그림판의 사례만 해도 저장한 파일 이름이 바뀌면 찾을 수 없습니다.

하지만 이런 프로그램을 찾는 방법이 없는 것은 아닙니다. 바로 EnumWindows라는 함수입니다. EnumWindows는 현재 실행중인 모든 윈도우를 찾는 함수로, 눈에 보이지 않는 모든 윈도우까지 찾아낼 수 있습니다. EnumWindows 함수의 원형은 다음과 같습니다.

BOOL WINAPI EnumWindows(
_In_ WNDENUMPROC lpEnumFunc,
_In_ LPARAM lParam
);

여기서 WNDENUMPROC는 다음과 같은 형식을 갖는 함수의 포인터입니다. 즉 다음과 같은 모양의 함수를 하나 만들고 이 함수 이름을 넘겨주면 됩니다.

BOOL CALLBACK EnumCallback(HWND hWnd, LPARAM lParam) {

}

이 함수의 역할은 EnumWindows가 윈도우를 찾을 때마다 호출하는 콜백 함수로, 찾은 윈도우의 핸들을 이 함수에 인자로 넘겨주게 되어 있습니다. 따라서 이 함수에서 각 윈도우에 대해 반복할 작업, 예를 들어 윈도우의 제목을 받아 리스트에 넣는다든지 하는 작업을 해 주면 됩니다.

EnumWindows의 두 번째 인자는 EnumCallBack 함수에 그대로 lParam값으로 받을 수 있습니다.

 

찾은 윈도우의 제목은 다음과 같이 GetWindowText라는 함수를 이용하면 얻을 수 있습니다.

char title[255];
GetWindowText(hWnd, title, 255);

255라는 숫자는 값을 저장할 문자열의 최대 크기입니다. title배열의 크기보다 GetWindowText의 세 번째 인자를 같거나 작게 써야 정상적으로 동작할 수 있습니다.

 

EnumWindows를 통해 윈도우를 찾고 이를 리스트에 추가하는 것을 간략하게 코드로 표현하면 다음과 같이 구현할 수 있습니다.

먼저 Windows형식의 프로젝트를 만들고 API의 기본 코드를 작성합니다.

전역변수로 변수와 매크로 상수를 선언합니다.

 

HWND hList;

#define ID_LISTBOX 100


WndProc 함수에 다음과 같은 case를 추가합니다.


case WM_CREATE:

hList=CreateWindow("listbox",NULL,WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT,

10,10,350,600,hWnd,(HMENU)ID_LISTBOX,g_hInst,NULL);

SendMessage(hList,LB_RESETCONTENT,0,0);

EnumWindows(EnumCallback, NULL);

break;


마지막으로 EnumCallback 함수를 다음과 같이 구현합니다.

 

BOOL CALLBACK EnumCallback(HWND hWnd, LPARAM lParam)

{

char title[255];

GetWindowText(hWnd, title, 255);

if(strlen(title)>0) {

SendMessage(hList,LB_ADDSTRING,0,(LPARAM)title);

}

return TRUE;

}


이를 실행하면 다음과 같은 결과를 볼 수 있습니다.

 



얻어온 윈도우의 핸들을 SetWindowText, SetWindowPos, SetWindowLong 등의 함수에 넘겨주는 등의 동작을 통해 윈도우의 제목을 임의로 바꾸거나, 위치, 크기 등을 조절하는 동작을 할 수 있습니다. 다음은 그림판의 제목을 임의로 바꾼 결과입니다.