앞의 내용 계속입니다.
========================================
필터 함수
필터 함수는 훅에 설정되는 함수이다. 필터 함수는 윈도우에 의해 호출되고 응용 프로
그램에 의해 호출되는 것이 아니다. 따라서 필터 함수는 callback functions이라고도
불린다. 일관성을 유지하기 위해 여기에서는 필터 함수라는 말을 사용한다.
필터 함수는 다음과 같은 형태를 가진다:
LRESULT CALLBACK FilterFunc( nCode, wParam, lParam )
int nCode;
WORD wParam;
DWORD lParam;
필터 함수는 LONG 형 반환값을 가지며 FilterFunc에 실제 필터 함수의 이름이 온다.
Parameters
필터 함수는 3개의 매개변수를 받는다: ncode (훅 코드), wParam, lParam. 훅 코드는
정수값으로 추가적인 데이터를 담고 있다. 예를 들어 훅 코드는 어떤 동작 또는 이벤
트가 훅을 호출했는 지에 대한 정보를 담고 있다.
3.1 버전 이전의 윈도우에서 훅 코드는 필터 함수가 그 이벤트를 처리할지 또는
DefHookProc 함수를 호출할지 결정하기 위해 사용되었다. 훅 코드가 영(zero)보다 작
은 경우 필터 함수는 그 이벤트를 처리해서는 안된고 넘겨 받은 3개의 매개변수를 수
정하지 않고 그대로 DefHookProc 함수를 호출하는데 넘겨주어야 했다. 윈도우는 음수
값의 훅 코드를 사용하여 필터 함수열을 유지하였다.
윈도우 3.1에서도 음의 훅 코드가 필터 함수로 보내지는 경우 필터 함수가
CallNextHookEx 함수를 호출하도록 하였다. 또한 필터 함수는 CallNextHookEx 함수에
서 반환된 값을 반환하여야 한다. 하지만 윈도우 3.1이 음의 훅 코드를 필터 함수로
전달하는 일은 없다.
두 번째와 세 번째 매개변수는 각각 WPARAM, LPARAM 형이다. 이들 매개변수는 필터 함
수에 필요한 정보를 전달한다. 각각의 훅은 wParam과 lParam에 각기 다른 의미를 부여
한다. 예를 들어 WH_KEYBOARD 훅에 설치된 필터 함수는 wParam에 가상 키 코드를 받
고 lParam에는 키 이벤트가 발생했을 때의 키보드 상태를 설명하는 값을 받는다.
WH_MSGFILTER 훅에 설치된 필터 함수의 경우 wParam은 NULL 값을, lParam에는
message structure에 대한 포인터를 받는다. 몇몇 훅은 wParam과 lParam에 훅을 호출
한 원인에 따라 다른 값들을 넘겨준다. 훅의 종류에 따른 매개 변수의 의미는 윈도우
NT를 위한 Win32 SDK를 참고하면 된다.
Hook
Filter function documentation
WH_CALLWNDPROC
CallWndProc
WH_CBT
CBTProc
WH_DEBUG
DebugProc
WH_GETMESSAGE
GetMsgProc
WH_JOURNALRECORD
JournalRecordProc
WH_JOURNALPLAYBACK
JournalPlaybackProc
WH_SHELL
ShellProc
WH_KEYBOARD
KeyboardProc
WH_MOUSE
MouseProc
WH_MSGFILTER
MessageProc
WH_SYSMSGFILTER
SysMsgProc
필터 함수열에서 다음 함수 호출하기
훅이 설정된 경우 윈도우는 훅의 필터 함수열에서 첫 번째 함수를 호출하고 이로써 윈
도우의 책임은 끝이 난다. 필터 함수열에서 다음 필터 함수를 호출하는 책임은 필터
함수 자체에 있다. 필터 함수열에서 다음 필터 함수를 호출하기 위해 윈도우는
CallNextHookEx 함수를 제공한다. CallNextHookEx 함수는 4개의 매개변수를 가진다.
LRESULT CallNextHookEx(
HHOOK hhk, // handle to current hook
int nCode, // hook code passed to hook procedure
WPARAM wParam, // value passed to hook procedure
LPARAM lParam // value passed to hook procedure
);
첫 번째 매개변수는 SetWindowsHookEx 함수의 결과로 반환된 값입니다. 현재 이 값은
무시되지만 이후에는 어떻게 변할지 알 수 없습니다.
다음 세 개의 매개변수 nCode, wParam, lParam은 윈도우가 필터 함수로 건네준 매개변
수들입니다.
윈도우는 필터 함수열을 내부적으로 저장하고 어느 필터 함수를 호출하는지 관리합니
다. CallNextHookEx 함수가 호출될 때 윈도우는 다음 필터 함수를 함수열에서 결정하
고 그 함수를 호출합니다.
때때로 필터 함수는 동인한 열에 있는 다른 필터 함수도 이벤트를 넘겨주지 않기를 바
랄 수도 있습니다. 훅이 필터 함수의 이벤트를 제거를 허용하고 필터 함수가 이벤트
를 제거하려고 하는 경우 필터 함수는 CallNextHookEx 함수를 호출해서는 안됩니다.
필터 함수가 메시지를 수정했을 경우, 수정한 메시지를 필터 함수열의 나머지 함수들
로는 전해주지 않을 것입니다.
필터 함수는 특정한 순서로 설치되지 않으므로 새로 설치하려는 필터 함수가 필터 함
수열에서 설치하는 바로 그 순간을 제외하고는 어디에 위치할지 알 수 없다. 따라서
새로 설치하는 필터 함수가 발생하는 모든 이벤트를 받을 것이라고 확신할 수 없다.
새로운 필터 함수를 설치하기 이전에 설치된 어떤 필터 함수가 새로 설치하는 필터 함
수로 이벤트를 보내지 않을 수도 있다.
DLL에 있는 필터 함수
시스템 범위의 필터 함수는 DLL에 있어야만 한다. 16 비트 윈도우에서는 추천되지는
않지만 시스템 훅을 응용 프로그램 내의 필터 함수에 설치하는 것이 가능했다. 하지
만 Win32에서는 이러한 방식이 동작하지 않는다. 특정한 시스템에서 동작하는 것처럼
보일지도 모르지만 DLL에 있지 않은 시스템 범위의 필터 함수를 설치해서는 안된다.
journal 훅인 WH_JOURNALRECORD와 WH_JOURNALPLAYBACK는 이 규칙의 예외이다. 윈도우
가 이들 훅은 다른 훅과 다른 방식으로 처리하기 때문에 꼭 DLL에 있어야 할 필요는
없다.
시스템 범위의 훅을 위한 필터 함수는 그 함수가 실행되는 프로세스와 다른 프로세스
에서 필요로 하는 데이터를 공유할 수 있는 방법을 마련해야 한다. DLL은 DLL을 호출
한 클라이언트 프로세스 공간에 포함된다. 전역 변수라 하더라도 공유 데이터에 있지
않으면 특정 인스턴스에서만, 즉 DLL을 호출한 클라이언트에서만 사용할 수 있다. 예
를 들어 훅 예제에 있는 HOOKSDLL.DLL 라이브러리는 두 개의 데이터를 공유한다:
메시지를 표시할 윈도우의 핸들
윈도우에 있는 문자열의 높이
이 데이터를 공유하기 위해서는 이들 데이터를 공유 데이터 섹션에 위치시켜야 한다.
HOOKSDLL이 데이터를 공유하기 위해서는 다음과 같은 순서를 따라야 한다:
pragmas를 사용하여 데이터를 named data segment에 위치시킨다. 데이터는 반드시 초
기화되어야 한다.
// Shared DATA
#pragma data_seg(".SHARDATA")
static HWND hwndMain = NULL; // Main hwnd. We will get this from the app.
static int nLineHeight = 0; // Height of lines in window.
#pragma data_seg()
DLL의 .DEF 파일에 SECTIONS 구문을 첨가한다.
SECTIONS
.SHARDATA Read Write Shared
.DEF 파일에서 .EXP 파일을 생성한다.
hooksdll.exp: hooksdll.obj hooksdll.def
$(implib) -machine:$(CPU) -def:hooks.def hooksdll.obj -out:hooksdll.lib
HOOKSDLL.EXP 파일과 연결시키다.
hooksdll.dll: hooksdll.obj hooksdll.def hooksdll.lib hooksdll.exp
$(link) $(linkdebug) -base:0x1C000000 -dll -entry:LibMain$(DLLENTRY) -out:hooksdll.dll hooksdll.exp hooksdll.obj hooksdll.rbj $(guilibsdll)
훅의 종류
WH_CALLWNDPROC
운영 체제는 윈도우의 SendMessage 함수가 호출될 때 이 훅을 호출한다. 필터 함수는
현재 쓰레드에서 이 메시지가 발생했는지를 나타내는 훅 코드와 실제 메시지를 포함하
고 있는 구조체의 포인터를 받는다.
CWPSTRUCT 구조체는 다음과 같다.
typedef struct tagCWPSTRUCT {
LPARAM lParam;
WPARAM wParam;
DWORD message;
HWND hwnd;
} CWPSTRUCT, *PCWPSTRUCT, NEAR *NPCWPSTRUCT, FAR *LPCWPSTRUCT;
필터는 메시지를 처리할 수 있지만 메시지를 수정할 수는 없다. 16 비트 윈도우에서
는 수정도 가능했따. 메시지는 원래 전해질 함수로 전달된다. 이 훅은 특히 시스템 범
위의 훅으로 설치된 경우 시스템 성능을 저해하기 때문에 개발이나 디버깅 도구로만
사용하는 것이 좋다.
WH_CBT
CBT 응용 프로그램을 작성하기 위해서 개발자는 CBT 프로그램과 그 프로그램의 대상
이 되는 프로그램을 결합시켜야 한다. 이러한 작업이 가능하도록 윈도우는 WH_CBT 훅
을 제공한다. 윈도우는 필터 함수로 훅 코드와 발생한 이벤트의 종류 그리고 이벤트
에 필요한 데이터를 넘겨준다.
WH_CBT 훅에 설치된 필터 함수는 다음의 10가지 훅 코드 처리할 수 있다.
HCBT_ACTIVATE
HCBT_CREATEWND
HCBT_DESTROYWND
HCBT_MINMAX
HCBT_MOVESIZE
HCBT_SYSCOMMAND
HCBT_CLICKSKIPPED
HCBT_KEYSKIPPED
HCBT_SETFOCUS
HCBT_QS
HCBT_ACTIVATE
운영 체제는 윈도우가 활성화되려고 할 때 이 훅 코드와 함께 WH_CBT 훅을 호출한다.
쓰레드 훅의 경우 생성되는 윈도우는 같은 쓰레드에 있어야 한다. 필터 함수가 TRUE
를 반환하면 윈도우는 활성화되지 않는다.
wParam 매개변수는 활성화되려고 하는 윈도우의 핸들을 가지고 있다. lParam 매개변수
는 구조체 CBTACTIVATESTRUCT에 대한 포인터를 가지고 있다.
typedef struct tagCBTACTIVATESTRUCT
{
BOOL fMouse; // 마우스로 클릭하여 활성화되면 TRUE,
// 그렇지 않으면 FALSE.
HWND hWndActive; // 현재 활성화되려고 하는
// 윈도우에 대한 핸들.
} CBTACTIVATESTRUCT, *LPCBTACTIVATESTRUCT;
HCBT_CREATEWND
윈도우가 생성되려고 할 때 이 훅 코드를 사용하여 WH_CBT 훅을 호출한다. 쓰레드 훅
의 경우 동일한 쓰레드에서 윈도우가 생성되는 경우이다. WH_CBT 훅은
WM_GETMINMAXINFO, WM_NCCREATE, WM_CREATE 메시지를 윈도우로 보내기 전에 호출된
다. 따라서 필터 함수는 TRUE를 반환하여 윈도우가 생성되지 않도록 할 수 있다.
wParam 매개변수는 생성되려고 하는 윈도우의 핸들을 가지고 있다. lParam 매개변수
는 구조체 CBT_CREATEWND에 대한 포인터를 가지고 있다.
struct CBT_CREATEWND
{
struct tagCREATESTRUCT *lpcs; // 새로 생성되는 윈도우의
// 생성 인자
HWND hwndInsertAfter; // Z-order 상에서
// 생성되는 윈도우의 앞에 오는 윈도우
} CBT_CREATEWND, *LPCBT_CREATEWND;
필터 함수는 구조체의 값을 변경할 수 있다.
HCBT_DESTROYWND
윈도우가 파괴되려고 할 때 이 훅 코드를 이용하여 WH_CBT를 호출한다. 쓰레드 훅의
경우 동일한 쓰레드에 있는 윈도우이어야 한다. 운영 체제는 WM_DESTROY 메시지를 보
내기 전에 WH_CBT 훅을 호출한다. 필터 함수가 TRUE를 반환하면 윈도우는 파괴되지 않
는다.
wParam 매개변수는 파괴되려고 하는 윈도우의 핸들을 가지고 있다. lParam 매개변수
는 영(zero)의 값을 갖는다.
HCBT_MINMAX
윈도우가 최소화 또는 최대화되려고 할 때 이 훅 코드를 사용하여 WH_CBT 훅을 호출한
다. 쓰레드 훅의 경우 동일한 쓰레드에 있는 윈도우이어야 한다. 필터 함수가 TRUE를
반환하면 최소화 또는 최대화가 일어나지 않는다.
wParam 매개변수는 최대화 또는 최소화되려고 하는 윈도우에 대한 핸들을 가지고 있
다. lParam 매개변수는 발생한 동작을 지시하는 값으로 WINUSER.H에 정의된 SW_* 값
들 중 하나의 값을 가진다.
HCBT_MOVESIZE
윈도우가 이동하거나 크기가 변하려고 할 때 그리고 사용자가 윈도우의 위치나 크기
변화를 끝냈을 때 이 훅 코드를 사용하여 WH_CBT를 호출한다. 쓰레드 훅의 경우 동일
한 쓰레드에 있는 윈도우이어야 한다. 필터 함수가 TRUE를 반환하면 변화가 일어나지
않는다.
wParam 매개변수는 이동되거나 크기가 변하는 윈도우에 대한 핸들을 가지고 있다.
lParam 매개변수는 끌기 직사각형(drag rectangle)에 대한 포인터로 LPRECT 형 값을
가진다.
HCBT_SYSCOMMAND
운영 체제가 시스템 명령어(system command)를 처리할 때 이 훅 코드를 사용하여
WH_CBT 훅을 호출한다. 쓰레드 훅의 경우 시스템 메뉴가 사용되는 윈도우는 같은 쓰레
드에 있어야 한다. WH_CBT 훅은 DefWindowsProc 함수에서 호출된다. 응용 프로그램이
WH_SYSCOMMAND 메시지를 DefWindowsProc 함수로 보내지 않으면 이 훅은 호출되지 않는
다. 필터 함수가 TRUE를 반환하면 시스템 명령은 처리되지 않는다.
wParam 매개변수는 수행되려고 하는 시스템 명령어(SC_TASKLIST, SC_HOTKEY 등)를 가
지고 있다. wParam의 값이 SC_HOTKEY인 경우 lParam의 LOWORD는 hotkey가 적용되는 윈
도우의 핸들을 가지고 있다. wParam의 값이 SC_HOTKEY 이외의 값이고 시스템 명령어
를 마우스로 선택한 경우 lParam의 LOWORD는 커서의 수평 위치를 HIWORD는 커서의 수
직 위치를 가지고 있다.
다음의 시스템 명령어들은 DefWindowProc 함수에서 이 훅을 호출한다. SC_CLOSE
윈도우를 닫는다.
SC_HOTKEY
응용 프로그램이 hot key에 의해 활성화된다.
SC_HSCROLL
수평 방향으로 스크롤한다.
SC_KEYMENU
키 입력에 의해 메뉴를 연다.
SC_MAXIMIZE
윈도우를 최대화한다.
SC_MINIMIZE
윈도우를 최소화한다.
SC_MOUSEMENU
마우스 입력에 의해 메뉴를 연다.
SC_MOVE
윈도우를 움직인다.
SC_NEXTWINDOW
다음 윈도우로 이동한다.
SC_PREVWINDOW
이전 윈도우로 이동한다.
SC_RESTORE
이전 위치로 복구한다.
SC_SCREENSAVE
화면 보호기를 실행한다.
SC_SIZE
윈도우의 크기를 조절한다.
SC_TASKLIST
윈도우의 작업 관리자(task manager)를 실행시키거나 활성화시키다.
SC_VSCROLL
수직 방향으로 스크롤한다.
HCBT_CLICKSKIPPED
마우스 이벤트가 쓰레드의 입력 큐에서 제거되고 마우스 훅이 설정되었을 때 이 훅 코
드를 사용하여 WH_CBT 훅을 호출한다. 운영 체제는 마우스 이벤트가 입력 큐에서 제거
되고 시스템 범위의 마우스 훅이나 현재의 쓰레드를 위한 쓰레드 훅이 설치된 경우 시
스템 범위의 훅을 호출한다. 이 훅 코드는 필터 함수가 WH_MOUSE 훅에 설치되지 않은
경우에는 발생하지 않는다. HCBT_CLICKSKIPPED는 마우스 이벤트가 버렸을 때 뿐만이
아니라 마우스 이벤트가 시스템 큐에서 제거될 때에도 호출된다. 이 값의 주요한 용도
는 마우스 이벤트에 반응하는 WH_JOURNALPLAYBACK 훅을 설치하는 것이다. (자세한 내
용은 아래 "WM_QUEUESYNC" 부분을 참고하면 된다.)
wParam 매개변수는 마우스 메시지의 메시지 ID를 가지고 있다. 예를 들면
WM_LBUTTONDOWN이나 WM_?BUTTON*고 같은 메시지들이다. lParam 매개변수는
MOUSEHOOKSTRUCT 구조체에 대한 포인터를 가지고 있다.
typedef struct tagMOUSEHOOKSTRUCT {
POINT pt; // 화면 좌표계에서의 마우스 위치
HWND hwnd; // 이 메시지를 받는 윈도우 핸들
UINT wHitTestCode; // hit-testing (HT_*) 결과
DWORD dwExtraInfo; // 현재 메시지와 관련된 부가 정보
} MOUSEHOOKSTRUCT, FAR *LPMOUSEHOOKSTRUCT, *PMOUSEHOOKSTRUCT;
HCBT_KEYSKIPPED
키보드 이벤트가 시스템 큐에서 제거되고 키보드 훅이 설치된 경우 이 훅 코드를 사용
하여 WH_CBT를 호출한다. 운영 체제는 키보드 이벤트가 입력 큐에서 제거되고 시스템
범위의 키보드 훅이나 현재의 쓰레드를 위한 쓰레드 훅이 설치된 경우 시스템 범위의
훅을 호출한다. 이 훅 코드는 필터 함수가 WH_KEYBOARD 훅에 설치되지 않은 경우에는
발생하지 않는다. HCBT_KEYSKIPPED는 키보드 이벤트가 버렸을 때 뿐만이 아니라 키보
드 이벤트가 시스템 큐에서 제거될 때에도 호출된다. 이 값의 주요한 용도는 키보드
이벤트에 반응하는 WH_JOURNALPLAYBACK 훅을 설치하는 것이다. (자세한 내용은 아
래 "WM_QUEUESYNC" 부분을 참고하면 된다.)
wParam 매개변수는 가상 키 코드를 가지고 있다. 이 값은 WM_KEY* 메시지를
GetMessage나 PeekMessage로 얻어올 때의 wParam과 같은 값이다. lParam 매개변수는
WM_KEY* 메시지를 GetMessage나 PeekMessage로 얻어올 때의 lParam과 같은 값을 가진
다.
WM_QUEUESYNC
실행 중에 CBT 응용 프로그램은 대상 프로그램의 이벤트에 반응해야 하는 경우가 종
종 있다. 보통 키보드나 마우스 이벤트가 이러한 이벤트를 발생시키다. 예를 들어 사
용자가 다이알로그 박스의 OK 버튼을 누르는 경우, CBT 응용 프로그램은 대상 프로그
램으로 일련의 키 입력을 보내려고 할 것이다. CBT 응용 프로그램은 마우스 훅을 사용
하여 OK 버튼이 눌러졌는지 결정할 수 있다. 대상 프로그램에 키 입력을 다시 재현하
고자 하는 경우 CBT 응용 프로그램은 대상 프로그램이 OK 버튼에 대한 처리를 끝내도
록 기다려야 한다. CBT 응용 프로그램이 다이알로그 박스에 키 입력을 해서는 안되는
것이다.
CBT 응용 프로그램은 WM_QUEUESYNC 메시지를 사용하여 대상 프로그램을 감시하고 언
제 동작이 끝나는지를 알아낼 수 있다. CBT 응용 프로그램은 대상 프로그램을 마우스
나 키보드 훅으로 감시하고 반응해야 하는 이벤트를 알아낸다. 대상 프로그램의 마우
스나 키보드 훅을 관찰함으로써 CBT 응용 프로그램은 언제 반응을 시작해야 하는지 알
게 된다. CBT 응용 프로그램은 이벤트 처리가 종료되고 이에 반응해야 할 때까지 기다
려야 한다.
이벤트 처리가 언제 끝나는지 결정하기 위해 CBT 응용 프로그램은 다음의 과정을 따른
다.
CBT 응용 프로그램은 운영 체제로부터 HCBT_CLICKSKIPPED이나 HCBT_KEYSKIPPED 훅 코
드를 가지는 WH_CBT 훅을 받을 때까지 기다린다. 이러한 WH_CBT 훅은 대상 프로그램
의 행동을 지시한 이벤트가 시스템 큐에서 제거될 때 발생한다.
CBT 응용 프로그램은 WH_JOURNALPLAYBACK 훅을 설치한다. CBT 응용 프로그램은
HCBT_CLICKSKIPPED이나 HCBT_KEYSKIPPED 훅 코드를 받을 때까지 WH_JOURNALPLAYBACK
훅을 설치할 수 없다. WH_JOURNALPLAYBACK 훅은 CBT 응용 프로그램에 WM_QUEUESYNC 메
시지를 재생한다. 이 메시지를 CBT 응용 프로그램이 받으면 원래의 이벤트에 CBT 응
용 프로그램이 반응할 수 있다. 예를 들어 CBT 응용 프로그램은 키 입력을 대상 프로
그램에 재현하게 된다.
HCBT_SETFOCUS
어떤 윈도우가 포커스를 받으려고 할 때 이 훅 코드로 WH_CBT를 호출한다. 쓰레드 훅
의 경우 윈도우는 동일한 쓰레드에 있어야 한다. 필터 함수가 TRUE를 반환하면 포커스
가 바뀌지 않는다.
wParam 매개변수는 포커스를 받을 윈도우의 핸들을 가지고 있다. lParam 매개변수는
포커스를 잃게 되는 윈도우의 핸들을 가지고 있다.
HCBT_QS
윈도우의 크기가 변화하거나 옮겨지는 동안 WM_QUEUESYNC 메시지가 시스템 큐에서 제
거되면 이 훅 코드로 WH_CBT를 호출한다. 다른 경우에는 호출되는 경우가 없다. 쓰레
드 훅의 경우 윈도우는 동일한 쓰레드에 있어야 한다.
wParam과 lParam 매개변수는 모두 영(zero)을 가지고 있다.
WH_DEBUG
필터 함수를 호출하려고 할 때 운영 체제가 이 훅을 호출한다. 필터는 훅의 값을 수정
할 수는 없지만, 영(zero)이 아닌 값을 반환함으로써 운영 체제가 원래의 필터 함수
를 호출하는 것을 중지시킬 수 있다.
wParam 매개변수는 호출되는 훅의 ID를 가지고 있다. lParam 매개변수는 다음 구조체
의 포인터를 가지고 있다.
typedef struct tagDEBUGHOOKINFO
{
DWORD idThread; // 현재 쓰레드의 ID
LPARAM reserved;
LPARAM lParam; // 목적지 필터 함수의 lParam
WPARAM wParam; // 목적지 필터 함수의 wParam
int code;
} DEBUGHOOKINFO, *PDEBUGHOOKINFO, NEAR *NPDEBUGHOOKINFO, FAR* LPDEBUGHOOKINFO;
WH_FOREGROUNDIDLE
현재 쓰레드에 처리할 사용자 입력이 없을 때 이 훅을 호출한다. 쓰레드 훅의 경우
그 쓰레드가 현재 쓰레드이고 쓰레드에 입력이 없을 때에만 이 훅을 호출한다. 이 훅
은 통지(notification)만 할 수 있다. 즉, 수정이나 제거는 할 수 없다. wParam과
lParam는 모두 영(zero)의 값을 갖는다.
WH_GETMESSAGE
GetMessage 함수나 PeekMessage 함수가 메시지를 반환하려고 할 때 이 훅을 호출한
다. 필터 함수는 실제 메시지에 대한 정보를 가지고 있는 구조체의 포인터를 받는다.
원본 그대로이거나 또는 수정된 경우에도 메시지는 원래의 목적지로 전달된다.
lParam 매개변수는 MSG 구조체에 대한 포인터를 가지고 있다.
typedef struct tagMSG { /* msg */
HWND hwnd; // 해당 메시지를 처리할 Winproc 함수를 가지고 있는 윈
도우
UINT message; // message number
WPARAM wParam;
LPARAM lParam;
DWORD time; // 메시지가 발생한 시간
POINT pt; // 화면 좌표계에서 메시지가 발생한 커서 위치
} MSG;
WH_HARDWARE
이 훅은 현재 Win32에서 구현되어 있지 않다.
Journal Hooks
Journal 훅은 이벤트를 기록하고 재생하기 위해 사용된다. 이들은 시스템 범위의 훅으
로만 사용되며 따라서 가능한 사용하지 않는 것이 좋다. 이들 훅은 모든 윈도우 기반
응용 프로그램에 영향을 미친다. 또 하나 journal 훅의 부작용은 모든 시스템 입력 큐
가 훅을 설치한 쓰레드에 집중된다는 점이다. 이는 모든 시스템 입력이 한 점을 통과
해야 한다는 것을 의미한다.
Win32는 이 훅이 시스템을 먹통으로 만들지 않도록 journal 훅을 취소하는 방법을 제
공한다. 운영 체제는 사용자가 CTRL+ESC, ALT+ESC, 또는 CTRL+ALT+DEL 키를 누르면 기
록이나 재생을 위한 journal 훅을 제거한다. 훅을 제거한 후에 운영 체제는
WM_CANCELJOURNAL 메시지를 보내 응용 프로그램에 훅이 제거되었다는 사실을 알린다.
Win32 takes special steps to allow a user to cancel a journal hook so that it
does not lock the system. Windows will uninstall a record or playback journal
hook when the user presses CTRL+ESC, ALT+ESC, or CTRL+ALT+DEL. Windows then
notifies the application that had a journal hook installed by posting a
WM_CANCELJOURNAL message.
WM_CANCELJOURNAL
이 메시지는 윈도우 프로시저로 전송되지 않도록 NULL 값을 갖는 윈도우 핸들과 더불
어 발생한다. 이 메시지를 알아챌 수 있는 가장 좋은 방법은 이 메시지를 감시하는
WH_GETMESSAGE 필터 함수를 설치하는 것이다. Win32 문서에 응용 프로그램이
WM_CANCELJOURNAL 메시지를 GetMessage (또는 PeekMessage) 함수와 DispatchMessage
함수를 호출하는 중간에 잡아낼 수 있다고 되어있다. 비록 이 시점에서 이 메시지를
잡아낼 수 있지만, 메시지가 보내졌을 때 응용 프로그램은 메시지를 잡아낼 수 있는
위치에 있지 않을 것이다. 예를 들어 응용 프로그램이 다이아로그 박스인 경우 main
message loop는 호출되지 않을 것이다.
CTRL+ESC, ALT+ESC, 그리고 CTRL+ALT+DEL 키 조합은 journal 훅을 중지시키기 위해 시
스템에 설치되어 있다. journal 훅을 사용하는 모든 응용 프로그램이 journaling을 중
지시키는 방법을 갖는 것은 바람직하다. journaling을 중지시키는 방법으로 권장되는
것은 VK_CANCEL (CTRL+BREAK) 키를 이용하는 방법이다.
WH_JOURNALRECORD
시스템 큐에서 이벤트를 제거할 때 이 훅을 호출한다. 따라서 필터 함수는 journal 재
생 훅에 의해 재생되는 경우를 제외하고는 모든 마우스와 키보드 이벤트에 대해 호출
된다. 필터 함수는 메시지를 처리한다. 즉 이벤트를 메모리나 디스크 또는 양 쪽 모두
에 저장할 수 있다. 하지만 메시지를 수정하거나 제거할 수는 없다. 이 훅을 위한 필
터 함수는 DLL에 있거나 .EXE 파일에 있어야 한다. HC_ACTION 훅 코드만이 Win32에서
구현되어 있다.
HC_ACTION
시스템 큐에 이벤트를 받았을 경우 이 훅 코드를 사용하여 WH_JOURNALRECORD 훅을 호
출한다. 이 훅 코드는 필터 함수에 발생한 이벤트가 정상적인 이벤트라는 것을 알린
다. [정상적이라는 말은 재생된 이벤트가 아니라는 말이다.] 필터 함수의 lParam 매개
변수는 EVENTMSG 구조체의 포인터를 가지고 있다. 보통의 이벤트 기록 방식은 훅으로
넘어온 EVENTMSG 구조체를 메모리나 디스크로 저장하는 것이다.
EVENTMSG 구조체는 WINDOWS.H에 정의되어 있다.
typedef struct tagEVENTMSG {
UINT message;
UINT paramL;
UINT paramH;
DWORD time;
HWND hwnd;
} EVENTMSG;
typedef struct tagEVENTMSG *PEVENTMSG, NEAR *NPEVENTMSG, FAR *LPEVENTMSG;
EVENTMSG 구조체에서 message는 메시지 ID로 WM_* 값을 가진다. paramL과 paramH는 발
생한 이벤트가 마우스 이벤트인지 키보드 이벤트인지에 따라 다르다. 마우스 이벤트
인 경우 이벤트가 발생한 위치의 좌표를 가지고 있다. 키보드 이벤트인 경우 paramL
은 HIBYTE에 scan code를 LOBYTE에 가상 키 코드를 가지고 있으며, paramH는 반복 횟
수를 가지고 있다. 반복 횟수의 15번째 비트는 그 이벤트가 확장 키인지를 나타낸다.
EVENTMSG 구조체의 시간 요소에는 이벤트가 발생한 시스템 시간이 GetTickCount 함수
를 사용하여 저장된다. hwnd는 이벤트가 발생한 윈도우의 핸들이다.
두 이벤트 사이의 시간은 시간 요소를 비교하여 얻을 수 있다. 이 값은 저장된 이벤트
를 재생할 때 필요하다.
WH_JOURNALPLAYBACK
이 훅은 마우스나 키보드 메시지가 실제로 발생한 것처럼 시스템 큐에 입력하기 위해
사용된다. 이 훅은 보통 WH_JOURNALRECORD 훅에 의해 저장된 이벤트를 재생하기 위해
사용되지만, 다른 응용 프로그램에 이벤트를 전달하기 위한 가장 좋은 방법이기도 하
다. 이 훅에 필터 함수가 설치되면, 운영체제는 필터 함수열에서 첫 번째 필터 함수
를 호출하여 이벤트를 얻는다. WH_JOURNALPLAYBACK 훅이 설치된 경우 마우스 움직임
은 무시된다. 키보드나 마우스 입력과 관련된 다른 메시지들은 WH_JOURNALPLAYBACK 훅
에 설치된 필터 함수가 더 이상 없을 때까지 큐에 저장된다. 이 훅을 위한 필터 함수
는 DLL이나 .EXE 파일에 있어야 한다. 이 훅에 설치된 필터 함수는 다음의 코드를 처
리할 수 있다.
HC_GETNEXT
HC_SKIP
HC_GETNEXT
운영 체제가 쓰레드의 입력 큐에 접근할 때 이 훅 코드로 WH_JOURNALPLAYBACK 훅을 호
출한다. 대부분의 경우 운영체제는 동일한 메시지에 대해 여러 번 동일한 호출을 한
다. 필터 함수의 lParam 매개변수는 EVENTMSG 구조체에 대한 포인터를 가지고 있다.
필터 함수는 EVENTMSG 구조체에서 message, paramL, paramH의 값을 설정하여야 한다.
이들 값은 보통 WH_JOURNALRECORD를 사용하여 기록한 이벤트에서 복사된다.
필터 함수는 운영 체제에게 필터 함수가 제공한 메시지를 언제 처리할지 알려 주어야
한다. 운영체제는 두 가지 값을 필요로 한다: (1) 메시지를 처리하기 전에 운영 체제
가 기다려야 하는 시간; (2) 메시지가 처리되어야 하는 시간. 기다리는 시간을 계산하
는 전형적인 방법은 EVENTMSG 구조체의 시간 요소를 사용하는 것이다. 이 방법은 이벤
트가 기록된 것과 동일한 속도로 재생할 수 있도록 해준다. 만약 메시지가 즉시 처리
되어야 한다면 영(zero)의 값을 반환할 것이다.
메시지가 처리되어야 하는 시간은 운영 체제가 메시지 처리를 위해 기다려야 하는 시
간과 GetTickCount에서 얻어진 현재 시스템 시간을 더해서 얻을 수 있다. 즉시 처리해
야 한다면 GetTickCount에서 반환된 값을 사용하면 된다.
시스템이 active하지 않으면 운영체제는 필터 함수가 이벤트 처리를 위해 제공한 값들
을 사용한다. 시스템이 active하면 운영체제는 시스템 큐를 검사한다. 각각의 경우
HC_GETNEXT 훅 코드로 동일한 이벤트를 탖느다. 필터 함수가 HC_GETNEXT를 받았을 때
에는 연속적인 호출 사이의 대기 시간을 반환해야 한다. EVENTMSG 구조체, 메시지,
paramH 값, paramL 값은 수정할 필요가 없다.
HC_SKIP
운영 체제가 WH_JOURNALPLAYBACK 훅에서 받은 메시지 처리를 끝냈을 때 이 훅 코드를
사용하여 WH_JOURNALPLAYBACK 훅을 호출한다. 만약 WH_JOURNALPLAYBACK 훅에 의해 생
성된 이벤트가 아니고 시스템 큐에 있던 이벤트라면 이 코드는 운영 체제가 시스템 큐
에서 이벤트를 제거했을 때 발생한다. 이 훅 코드는 필터 함수에게, 이전의
HC_GETNETXT 호출에서 필터 함수가 넘겨준 이벤트가 응용 프로그램에 전달되었다는 것
을 알려준다. 필터 함수는 다음 HC_GETEVENT 호출에서 다음 이벤트를 반환할 수 있는
준비를 해야 한다. 필터 함수가 더 이상 재생할 이벤트가 없는 경우에는 HC_SKIP 호출
에서 자신을 해제해야 한다.
WH_KEYBOARD
GetMessage 함수나 PeekMessage 함수가 WM_KEYUP, WM_KEYDOWN, WM_SYSKEYUP,
WM_SYSKEYDOWN, WM_CHAR 등의 메시지를 반환하려고 할 때 이 훅을 호출한다. 쓰레드
훅의 경우 이들 메시지는 쓰레드의 입력 큐에 있어야 한다. 필터 함수는 가상 키 코드
와 키보드 훅이 발생했을 때의 키보드 상태를 받는다. 이 훅에 설치된 필터 함수는 다
음 훅 코드를 처리할 수 있다.
HC_ACTION
HC_NOREMOVE
HC_ACTION
시스템 큐에서 이벤트가 제거될 때 이 훅 코드를 사용하여 WH_KEYBOARD 훅을 호출한
다.
HC_NOREMOVE
응용 프로그램이 PM_NOREMOVE 옵션을 사용하여 PeekMessage 함수를 호출하였기 때문
에 키보드 이벤트가 제거되지 않았을 때 이 훅 코드를 사용하여 WH_KEYBOARD 훅을 호
출한다. 이 훅 코드가 전달되면 키 상태 테이블(key-state table)은 이전의 키 상태
를 반영하지 않는다. 응용 프로그램은 이러한 옵션이 있다는 것을 알고 있어야 한다.
WH_MOUSE
GetMessage 함수나 PeekMessage 함수가 호출되었을 때 처리할 마우스 메시지가 있으
면 이 훅이 호출된다. WH_KEYBOARD 훅과 마찬가지로 이 필터 함수는 메시지가 제거되
었는지(HC_NOREMOVE)를 나타내는 훅 코드, 마우스 메시지 ID, 그리고 마우스의 좌표
를 받게 된다. 필터는 운영 체제에게 메시지를 버리도록 할 수 있다. 이 훅에 대한 필
터는 DLL에 있어야 한다.
WH_MSGFILTER
다이알로그 박스, 메시지 박스, 스크롤 바, 또는 메뉴가 메시지를 발생시켰을 경우 그
리고 훅을 설정한 응용 프로그램에서 사용자가 ALT+TAB이나 ALT+ESC 키를 눌렀을 때
이 훅을 호출한다. 이 훅은 쓰레드 훅으로만 사용될 수 있으므로 응용 프로그램이나
DLL에 필터 함수를 둘 수 있다. 필터 함수는 다음의 훅 코드들을 받는다.
MSGF_DIALOGBOX : 다이알로그 박스나 메시지 박스의 메시지.
MSGF_MENU : 메뉴 메시지
MSGF_SCROLLBAR : 스크롤 바 메시지
MSGF_NEXTWINDOW: 다음 윈도우러 전환하려고 할 때
MSGF_* 값으로 정의된 값들이 WINUSER.H에 보면 더 있지만 현재의 WH_MSGFILTER 훅에
는 사용되지 않는다.
lParam 매개변수는 메시지를 포함하고 있는 구조체의 포인터를 가지고 있다.
WH_SYSMSGFILTER 훅이 WH_MSGFILTER 훅 이전에 호출된다. 만약 WH_SYSMSGFILTER 훅이
TRUE를 반환하면 WH_MSGFILTER 훅은 호출되지 않을 것이다.
WH_SHELL
최상위 윈도우에서 어떤 동작이 발생했을 때 이 훅을 호출한다. 쓰레드 훅의 경우 동
일한 쓰레드에 속하는 윈도우에 대해서만 이 훅을 호출한다. 이 훅은 통지
(notification)만 할 수 있으므로 필터 함수는 이벤트를 수정하거나 제거할 수 없다.
wParam 매개변수는 윈도우의 핸들을 가지고 있고 lParam 매개변수는 사용되지 않는
다. WINUSER.H에 3가지 훅 코드가 정의되어 있다.
HSHELL_WINDOWCREATED: 최상위 윈도우가 생성되었을 때 이 훅 코드를 사용하여 호출한
다. 훅이 호출되었을 때 윈도우는 이미 화면에 보여지고 있다.
HSHELL_WINDOWDESTROYED: 최상위 윈도우가 파괴되려고 할 때 이 훅 코드를 사용하여
호출한다.
HSHELL_ACTIVATESHELLWINDOW: 이 훅 코드는 현재 사용되지 않는다.
WH_SYSMSGFILTER
이 훅은 시스템 범위의 훅이라는 점을 제외하고는 WH_MSGFILTER 훅과 동일하다. 다이
알로그 박스, 메시지 박스, 스크롤 바, 또는 메뉴가 메시지를 발생시켰을 경우 그리
고 사용자가 ALT+TAB이나 ALT+ESC 키를 눌렀을 때 이 훅을 호출한다. 필터 함수는
WH_MSGFILTER에서와 동일한 훅 코드를 받는다.
lParam 매개변수는 메시지를 포함하는 구조체의 포인터를 가지고 있다.
WH_SYSMSGFILTER 훅은 WH_MSGFILTER 훅 이전에 호출된다. WH_SYSMSGFILTER 훅의 필터
함수가 TRUE를 반환하면 WH_MSGFILTER 훅은 호출되지 않을 것이다.
첨부된 샘플 : From MSDN
출처 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=1498&ref=660
========================================
필터 함수
필터 함수는 훅에 설정되는 함수이다. 필터 함수는 윈도우에 의해 호출되고 응용 프로
그램에 의해 호출되는 것이 아니다. 따라서 필터 함수는 callback functions이라고도
불린다. 일관성을 유지하기 위해 여기에서는 필터 함수라는 말을 사용한다.
필터 함수는 다음과 같은 형태를 가진다:
LRESULT CALLBACK FilterFunc( nCode, wParam, lParam )
int nCode;
WORD wParam;
DWORD lParam;
필터 함수는 LONG 형 반환값을 가지며 FilterFunc에 실제 필터 함수의 이름이 온다.
Parameters
필터 함수는 3개의 매개변수를 받는다: ncode (훅 코드), wParam, lParam. 훅 코드는
정수값으로 추가적인 데이터를 담고 있다. 예를 들어 훅 코드는 어떤 동작 또는 이벤
트가 훅을 호출했는 지에 대한 정보를 담고 있다.
3.1 버전 이전의 윈도우에서 훅 코드는 필터 함수가 그 이벤트를 처리할지 또는
DefHookProc 함수를 호출할지 결정하기 위해 사용되었다. 훅 코드가 영(zero)보다 작
은 경우 필터 함수는 그 이벤트를 처리해서는 안된고 넘겨 받은 3개의 매개변수를 수
정하지 않고 그대로 DefHookProc 함수를 호출하는데 넘겨주어야 했다. 윈도우는 음수
값의 훅 코드를 사용하여 필터 함수열을 유지하였다.
윈도우 3.1에서도 음의 훅 코드가 필터 함수로 보내지는 경우 필터 함수가
CallNextHookEx 함수를 호출하도록 하였다. 또한 필터 함수는 CallNextHookEx 함수에
서 반환된 값을 반환하여야 한다. 하지만 윈도우 3.1이 음의 훅 코드를 필터 함수로
전달하는 일은 없다.
두 번째와 세 번째 매개변수는 각각 WPARAM, LPARAM 형이다. 이들 매개변수는 필터 함
수에 필요한 정보를 전달한다. 각각의 훅은 wParam과 lParam에 각기 다른 의미를 부여
한다. 예를 들어 WH_KEYBOARD 훅에 설치된 필터 함수는 wParam에 가상 키 코드를 받
고 lParam에는 키 이벤트가 발생했을 때의 키보드 상태를 설명하는 값을 받는다.
WH_MSGFILTER 훅에 설치된 필터 함수의 경우 wParam은 NULL 값을, lParam에는
message structure에 대한 포인터를 받는다. 몇몇 훅은 wParam과 lParam에 훅을 호출
한 원인에 따라 다른 값들을 넘겨준다. 훅의 종류에 따른 매개 변수의 의미는 윈도우
NT를 위한 Win32 SDK를 참고하면 된다.
Hook
Filter function documentation
WH_CALLWNDPROC
CallWndProc
WH_CBT
CBTProc
WH_DEBUG
DebugProc
WH_GETMESSAGE
GetMsgProc
WH_JOURNALRECORD
JournalRecordProc
WH_JOURNALPLAYBACK
JournalPlaybackProc
WH_SHELL
ShellProc
WH_KEYBOARD
KeyboardProc
WH_MOUSE
MouseProc
WH_MSGFILTER
MessageProc
WH_SYSMSGFILTER
SysMsgProc
필터 함수열에서 다음 함수 호출하기
훅이 설정된 경우 윈도우는 훅의 필터 함수열에서 첫 번째 함수를 호출하고 이로써 윈
도우의 책임은 끝이 난다. 필터 함수열에서 다음 필터 함수를 호출하는 책임은 필터
함수 자체에 있다. 필터 함수열에서 다음 필터 함수를 호출하기 위해 윈도우는
CallNextHookEx 함수를 제공한다. CallNextHookEx 함수는 4개의 매개변수를 가진다.
LRESULT CallNextHookEx(
HHOOK hhk, // handle to current hook
int nCode, // hook code passed to hook procedure
WPARAM wParam, // value passed to hook procedure
LPARAM lParam // value passed to hook procedure
);
첫 번째 매개변수는 SetWindowsHookEx 함수의 결과로 반환된 값입니다. 현재 이 값은
무시되지만 이후에는 어떻게 변할지 알 수 없습니다.
다음 세 개의 매개변수 nCode, wParam, lParam은 윈도우가 필터 함수로 건네준 매개변
수들입니다.
윈도우는 필터 함수열을 내부적으로 저장하고 어느 필터 함수를 호출하는지 관리합니
다. CallNextHookEx 함수가 호출될 때 윈도우는 다음 필터 함수를 함수열에서 결정하
고 그 함수를 호출합니다.
때때로 필터 함수는 동인한 열에 있는 다른 필터 함수도 이벤트를 넘겨주지 않기를 바
랄 수도 있습니다. 훅이 필터 함수의 이벤트를 제거를 허용하고 필터 함수가 이벤트
를 제거하려고 하는 경우 필터 함수는 CallNextHookEx 함수를 호출해서는 안됩니다.
필터 함수가 메시지를 수정했을 경우, 수정한 메시지를 필터 함수열의 나머지 함수들
로는 전해주지 않을 것입니다.
필터 함수는 특정한 순서로 설치되지 않으므로 새로 설치하려는 필터 함수가 필터 함
수열에서 설치하는 바로 그 순간을 제외하고는 어디에 위치할지 알 수 없다. 따라서
새로 설치하는 필터 함수가 발생하는 모든 이벤트를 받을 것이라고 확신할 수 없다.
새로운 필터 함수를 설치하기 이전에 설치된 어떤 필터 함수가 새로 설치하는 필터 함
수로 이벤트를 보내지 않을 수도 있다.
DLL에 있는 필터 함수
시스템 범위의 필터 함수는 DLL에 있어야만 한다. 16 비트 윈도우에서는 추천되지는
않지만 시스템 훅을 응용 프로그램 내의 필터 함수에 설치하는 것이 가능했다. 하지
만 Win32에서는 이러한 방식이 동작하지 않는다. 특정한 시스템에서 동작하는 것처럼
보일지도 모르지만 DLL에 있지 않은 시스템 범위의 필터 함수를 설치해서는 안된다.
journal 훅인 WH_JOURNALRECORD와 WH_JOURNALPLAYBACK는 이 규칙의 예외이다. 윈도우
가 이들 훅은 다른 훅과 다른 방식으로 처리하기 때문에 꼭 DLL에 있어야 할 필요는
없다.
시스템 범위의 훅을 위한 필터 함수는 그 함수가 실행되는 프로세스와 다른 프로세스
에서 필요로 하는 데이터를 공유할 수 있는 방법을 마련해야 한다. DLL은 DLL을 호출
한 클라이언트 프로세스 공간에 포함된다. 전역 변수라 하더라도 공유 데이터에 있지
않으면 특정 인스턴스에서만, 즉 DLL을 호출한 클라이언트에서만 사용할 수 있다. 예
를 들어 훅 예제에 있는 HOOKSDLL.DLL 라이브러리는 두 개의 데이터를 공유한다:
메시지를 표시할 윈도우의 핸들
윈도우에 있는 문자열의 높이
이 데이터를 공유하기 위해서는 이들 데이터를 공유 데이터 섹션에 위치시켜야 한다.
HOOKSDLL이 데이터를 공유하기 위해서는 다음과 같은 순서를 따라야 한다:
pragmas를 사용하여 데이터를 named data segment에 위치시킨다. 데이터는 반드시 초
기화되어야 한다.
// Shared DATA
#pragma data_seg(".SHARDATA")
static HWND hwndMain = NULL; // Main hwnd. We will get this from the app.
static int nLineHeight = 0; // Height of lines in window.
#pragma data_seg()
DLL의 .DEF 파일에 SECTIONS 구문을 첨가한다.
SECTIONS
.SHARDATA Read Write Shared
.DEF 파일에서 .EXP 파일을 생성한다.
hooksdll.exp: hooksdll.obj hooksdll.def
$(implib) -machine:$(CPU) -def:hooks.def hooksdll.obj -out:hooksdll.lib
HOOKSDLL.EXP 파일과 연결시키다.
hooksdll.dll: hooksdll.obj hooksdll.def hooksdll.lib hooksdll.exp
$(link) $(linkdebug) -base:0x1C000000 -dll -entry:LibMain$(DLLENTRY) -out:hooksdll.dll hooksdll.exp hooksdll.obj hooksdll.rbj $(guilibsdll)
훅의 종류
WH_CALLWNDPROC
운영 체제는 윈도우의 SendMessage 함수가 호출될 때 이 훅을 호출한다. 필터 함수는
현재 쓰레드에서 이 메시지가 발생했는지를 나타내는 훅 코드와 실제 메시지를 포함하
고 있는 구조체의 포인터를 받는다.
CWPSTRUCT 구조체는 다음과 같다.
typedef struct tagCWPSTRUCT {
LPARAM lParam;
WPARAM wParam;
DWORD message;
HWND hwnd;
} CWPSTRUCT, *PCWPSTRUCT, NEAR *NPCWPSTRUCT, FAR *LPCWPSTRUCT;
필터는 메시지를 처리할 수 있지만 메시지를 수정할 수는 없다. 16 비트 윈도우에서
는 수정도 가능했따. 메시지는 원래 전해질 함수로 전달된다. 이 훅은 특히 시스템 범
위의 훅으로 설치된 경우 시스템 성능을 저해하기 때문에 개발이나 디버깅 도구로만
사용하는 것이 좋다.
WH_CBT
CBT 응용 프로그램을 작성하기 위해서 개발자는 CBT 프로그램과 그 프로그램의 대상
이 되는 프로그램을 결합시켜야 한다. 이러한 작업이 가능하도록 윈도우는 WH_CBT 훅
을 제공한다. 윈도우는 필터 함수로 훅 코드와 발생한 이벤트의 종류 그리고 이벤트
에 필요한 데이터를 넘겨준다.
WH_CBT 훅에 설치된 필터 함수는 다음의 10가지 훅 코드 처리할 수 있다.
HCBT_ACTIVATE
HCBT_CREATEWND
HCBT_DESTROYWND
HCBT_MINMAX
HCBT_MOVESIZE
HCBT_SYSCOMMAND
HCBT_CLICKSKIPPED
HCBT_KEYSKIPPED
HCBT_SETFOCUS
HCBT_QS
HCBT_ACTIVATE
운영 체제는 윈도우가 활성화되려고 할 때 이 훅 코드와 함께 WH_CBT 훅을 호출한다.
쓰레드 훅의 경우 생성되는 윈도우는 같은 쓰레드에 있어야 한다. 필터 함수가 TRUE
를 반환하면 윈도우는 활성화되지 않는다.
wParam 매개변수는 활성화되려고 하는 윈도우의 핸들을 가지고 있다. lParam 매개변수
는 구조체 CBTACTIVATESTRUCT에 대한 포인터를 가지고 있다.
typedef struct tagCBTACTIVATESTRUCT
{
BOOL fMouse; // 마우스로 클릭하여 활성화되면 TRUE,
// 그렇지 않으면 FALSE.
HWND hWndActive; // 현재 활성화되려고 하는
// 윈도우에 대한 핸들.
} CBTACTIVATESTRUCT, *LPCBTACTIVATESTRUCT;
HCBT_CREATEWND
윈도우가 생성되려고 할 때 이 훅 코드를 사용하여 WH_CBT 훅을 호출한다. 쓰레드 훅
의 경우 동일한 쓰레드에서 윈도우가 생성되는 경우이다. WH_CBT 훅은
WM_GETMINMAXINFO, WM_NCCREATE, WM_CREATE 메시지를 윈도우로 보내기 전에 호출된
다. 따라서 필터 함수는 TRUE를 반환하여 윈도우가 생성되지 않도록 할 수 있다.
wParam 매개변수는 생성되려고 하는 윈도우의 핸들을 가지고 있다. lParam 매개변수
는 구조체 CBT_CREATEWND에 대한 포인터를 가지고 있다.
struct CBT_CREATEWND
{
struct tagCREATESTRUCT *lpcs; // 새로 생성되는 윈도우의
// 생성 인자
HWND hwndInsertAfter; // Z-order 상에서
// 생성되는 윈도우의 앞에 오는 윈도우
} CBT_CREATEWND, *LPCBT_CREATEWND;
필터 함수는 구조체의 값을 변경할 수 있다.
HCBT_DESTROYWND
윈도우가 파괴되려고 할 때 이 훅 코드를 이용하여 WH_CBT를 호출한다. 쓰레드 훅의
경우 동일한 쓰레드에 있는 윈도우이어야 한다. 운영 체제는 WM_DESTROY 메시지를 보
내기 전에 WH_CBT 훅을 호출한다. 필터 함수가 TRUE를 반환하면 윈도우는 파괴되지 않
는다.
wParam 매개변수는 파괴되려고 하는 윈도우의 핸들을 가지고 있다. lParam 매개변수
는 영(zero)의 값을 갖는다.
HCBT_MINMAX
윈도우가 최소화 또는 최대화되려고 할 때 이 훅 코드를 사용하여 WH_CBT 훅을 호출한
다. 쓰레드 훅의 경우 동일한 쓰레드에 있는 윈도우이어야 한다. 필터 함수가 TRUE를
반환하면 최소화 또는 최대화가 일어나지 않는다.
wParam 매개변수는 최대화 또는 최소화되려고 하는 윈도우에 대한 핸들을 가지고 있
다. lParam 매개변수는 발생한 동작을 지시하는 값으로 WINUSER.H에 정의된 SW_* 값
들 중 하나의 값을 가진다.
HCBT_MOVESIZE
윈도우가 이동하거나 크기가 변하려고 할 때 그리고 사용자가 윈도우의 위치나 크기
변화를 끝냈을 때 이 훅 코드를 사용하여 WH_CBT를 호출한다. 쓰레드 훅의 경우 동일
한 쓰레드에 있는 윈도우이어야 한다. 필터 함수가 TRUE를 반환하면 변화가 일어나지
않는다.
wParam 매개변수는 이동되거나 크기가 변하는 윈도우에 대한 핸들을 가지고 있다.
lParam 매개변수는 끌기 직사각형(drag rectangle)에 대한 포인터로 LPRECT 형 값을
가진다.
HCBT_SYSCOMMAND
운영 체제가 시스템 명령어(system command)를 처리할 때 이 훅 코드를 사용하여
WH_CBT 훅을 호출한다. 쓰레드 훅의 경우 시스템 메뉴가 사용되는 윈도우는 같은 쓰레
드에 있어야 한다. WH_CBT 훅은 DefWindowsProc 함수에서 호출된다. 응용 프로그램이
WH_SYSCOMMAND 메시지를 DefWindowsProc 함수로 보내지 않으면 이 훅은 호출되지 않는
다. 필터 함수가 TRUE를 반환하면 시스템 명령은 처리되지 않는다.
wParam 매개변수는 수행되려고 하는 시스템 명령어(SC_TASKLIST, SC_HOTKEY 등)를 가
지고 있다. wParam의 값이 SC_HOTKEY인 경우 lParam의 LOWORD는 hotkey가 적용되는 윈
도우의 핸들을 가지고 있다. wParam의 값이 SC_HOTKEY 이외의 값이고 시스템 명령어
를 마우스로 선택한 경우 lParam의 LOWORD는 커서의 수평 위치를 HIWORD는 커서의 수
직 위치를 가지고 있다.
다음의 시스템 명령어들은 DefWindowProc 함수에서 이 훅을 호출한다. SC_CLOSE
윈도우를 닫는다.
SC_HOTKEY
응용 프로그램이 hot key에 의해 활성화된다.
SC_HSCROLL
수평 방향으로 스크롤한다.
SC_KEYMENU
키 입력에 의해 메뉴를 연다.
SC_MAXIMIZE
윈도우를 최대화한다.
SC_MINIMIZE
윈도우를 최소화한다.
SC_MOUSEMENU
마우스 입력에 의해 메뉴를 연다.
SC_MOVE
윈도우를 움직인다.
SC_NEXTWINDOW
다음 윈도우로 이동한다.
SC_PREVWINDOW
이전 윈도우로 이동한다.
SC_RESTORE
이전 위치로 복구한다.
SC_SCREENSAVE
화면 보호기를 실행한다.
SC_SIZE
윈도우의 크기를 조절한다.
SC_TASKLIST
윈도우의 작업 관리자(task manager)를 실행시키거나 활성화시키다.
SC_VSCROLL
수직 방향으로 스크롤한다.
HCBT_CLICKSKIPPED
마우스 이벤트가 쓰레드의 입력 큐에서 제거되고 마우스 훅이 설정되었을 때 이 훅 코
드를 사용하여 WH_CBT 훅을 호출한다. 운영 체제는 마우스 이벤트가 입력 큐에서 제거
되고 시스템 범위의 마우스 훅이나 현재의 쓰레드를 위한 쓰레드 훅이 설치된 경우 시
스템 범위의 훅을 호출한다. 이 훅 코드는 필터 함수가 WH_MOUSE 훅에 설치되지 않은
경우에는 발생하지 않는다. HCBT_CLICKSKIPPED는 마우스 이벤트가 버렸을 때 뿐만이
아니라 마우스 이벤트가 시스템 큐에서 제거될 때에도 호출된다. 이 값의 주요한 용도
는 마우스 이벤트에 반응하는 WH_JOURNALPLAYBACK 훅을 설치하는 것이다. (자세한 내
용은 아래 "WM_QUEUESYNC" 부분을 참고하면 된다.)
wParam 매개변수는 마우스 메시지의 메시지 ID를 가지고 있다. 예를 들면
WM_LBUTTONDOWN이나 WM_?BUTTON*고 같은 메시지들이다. lParam 매개변수는
MOUSEHOOKSTRUCT 구조체에 대한 포인터를 가지고 있다.
typedef struct tagMOUSEHOOKSTRUCT {
POINT pt; // 화면 좌표계에서의 마우스 위치
HWND hwnd; // 이 메시지를 받는 윈도우 핸들
UINT wHitTestCode; // hit-testing (HT_*) 결과
DWORD dwExtraInfo; // 현재 메시지와 관련된 부가 정보
} MOUSEHOOKSTRUCT, FAR *LPMOUSEHOOKSTRUCT, *PMOUSEHOOKSTRUCT;
HCBT_KEYSKIPPED
키보드 이벤트가 시스템 큐에서 제거되고 키보드 훅이 설치된 경우 이 훅 코드를 사용
하여 WH_CBT를 호출한다. 운영 체제는 키보드 이벤트가 입력 큐에서 제거되고 시스템
범위의 키보드 훅이나 현재의 쓰레드를 위한 쓰레드 훅이 설치된 경우 시스템 범위의
훅을 호출한다. 이 훅 코드는 필터 함수가 WH_KEYBOARD 훅에 설치되지 않은 경우에는
발생하지 않는다. HCBT_KEYSKIPPED는 키보드 이벤트가 버렸을 때 뿐만이 아니라 키보
드 이벤트가 시스템 큐에서 제거될 때에도 호출된다. 이 값의 주요한 용도는 키보드
이벤트에 반응하는 WH_JOURNALPLAYBACK 훅을 설치하는 것이다. (자세한 내용은 아
래 "WM_QUEUESYNC" 부분을 참고하면 된다.)
wParam 매개변수는 가상 키 코드를 가지고 있다. 이 값은 WM_KEY* 메시지를
GetMessage나 PeekMessage로 얻어올 때의 wParam과 같은 값이다. lParam 매개변수는
WM_KEY* 메시지를 GetMessage나 PeekMessage로 얻어올 때의 lParam과 같은 값을 가진
다.
WM_QUEUESYNC
실행 중에 CBT 응용 프로그램은 대상 프로그램의 이벤트에 반응해야 하는 경우가 종
종 있다. 보통 키보드나 마우스 이벤트가 이러한 이벤트를 발생시키다. 예를 들어 사
용자가 다이알로그 박스의 OK 버튼을 누르는 경우, CBT 응용 프로그램은 대상 프로그
램으로 일련의 키 입력을 보내려고 할 것이다. CBT 응용 프로그램은 마우스 훅을 사용
하여 OK 버튼이 눌러졌는지 결정할 수 있다. 대상 프로그램에 키 입력을 다시 재현하
고자 하는 경우 CBT 응용 프로그램은 대상 프로그램이 OK 버튼에 대한 처리를 끝내도
록 기다려야 한다. CBT 응용 프로그램이 다이알로그 박스에 키 입력을 해서는 안되는
것이다.
CBT 응용 프로그램은 WM_QUEUESYNC 메시지를 사용하여 대상 프로그램을 감시하고 언
제 동작이 끝나는지를 알아낼 수 있다. CBT 응용 프로그램은 대상 프로그램을 마우스
나 키보드 훅으로 감시하고 반응해야 하는 이벤트를 알아낸다. 대상 프로그램의 마우
스나 키보드 훅을 관찰함으로써 CBT 응용 프로그램은 언제 반응을 시작해야 하는지 알
게 된다. CBT 응용 프로그램은 이벤트 처리가 종료되고 이에 반응해야 할 때까지 기다
려야 한다.
이벤트 처리가 언제 끝나는지 결정하기 위해 CBT 응용 프로그램은 다음의 과정을 따른
다.
CBT 응용 프로그램은 운영 체제로부터 HCBT_CLICKSKIPPED이나 HCBT_KEYSKIPPED 훅 코
드를 가지는 WH_CBT 훅을 받을 때까지 기다린다. 이러한 WH_CBT 훅은 대상 프로그램
의 행동을 지시한 이벤트가 시스템 큐에서 제거될 때 발생한다.
CBT 응용 프로그램은 WH_JOURNALPLAYBACK 훅을 설치한다. CBT 응용 프로그램은
HCBT_CLICKSKIPPED이나 HCBT_KEYSKIPPED 훅 코드를 받을 때까지 WH_JOURNALPLAYBACK
훅을 설치할 수 없다. WH_JOURNALPLAYBACK 훅은 CBT 응용 프로그램에 WM_QUEUESYNC 메
시지를 재생한다. 이 메시지를 CBT 응용 프로그램이 받으면 원래의 이벤트에 CBT 응
용 프로그램이 반응할 수 있다. 예를 들어 CBT 응용 프로그램은 키 입력을 대상 프로
그램에 재현하게 된다.
HCBT_SETFOCUS
어떤 윈도우가 포커스를 받으려고 할 때 이 훅 코드로 WH_CBT를 호출한다. 쓰레드 훅
의 경우 윈도우는 동일한 쓰레드에 있어야 한다. 필터 함수가 TRUE를 반환하면 포커스
가 바뀌지 않는다.
wParam 매개변수는 포커스를 받을 윈도우의 핸들을 가지고 있다. lParam 매개변수는
포커스를 잃게 되는 윈도우의 핸들을 가지고 있다.
HCBT_QS
윈도우의 크기가 변화하거나 옮겨지는 동안 WM_QUEUESYNC 메시지가 시스템 큐에서 제
거되면 이 훅 코드로 WH_CBT를 호출한다. 다른 경우에는 호출되는 경우가 없다. 쓰레
드 훅의 경우 윈도우는 동일한 쓰레드에 있어야 한다.
wParam과 lParam 매개변수는 모두 영(zero)을 가지고 있다.
WH_DEBUG
필터 함수를 호출하려고 할 때 운영 체제가 이 훅을 호출한다. 필터는 훅의 값을 수정
할 수는 없지만, 영(zero)이 아닌 값을 반환함으로써 운영 체제가 원래의 필터 함수
를 호출하는 것을 중지시킬 수 있다.
wParam 매개변수는 호출되는 훅의 ID를 가지고 있다. lParam 매개변수는 다음 구조체
의 포인터를 가지고 있다.
typedef struct tagDEBUGHOOKINFO
{
DWORD idThread; // 현재 쓰레드의 ID
LPARAM reserved;
LPARAM lParam; // 목적지 필터 함수의 lParam
WPARAM wParam; // 목적지 필터 함수의 wParam
int code;
} DEBUGHOOKINFO, *PDEBUGHOOKINFO, NEAR *NPDEBUGHOOKINFO, FAR* LPDEBUGHOOKINFO;
WH_FOREGROUNDIDLE
현재 쓰레드에 처리할 사용자 입력이 없을 때 이 훅을 호출한다. 쓰레드 훅의 경우
그 쓰레드가 현재 쓰레드이고 쓰레드에 입력이 없을 때에만 이 훅을 호출한다. 이 훅
은 통지(notification)만 할 수 있다. 즉, 수정이나 제거는 할 수 없다. wParam과
lParam는 모두 영(zero)의 값을 갖는다.
WH_GETMESSAGE
GetMessage 함수나 PeekMessage 함수가 메시지를 반환하려고 할 때 이 훅을 호출한
다. 필터 함수는 실제 메시지에 대한 정보를 가지고 있는 구조체의 포인터를 받는다.
원본 그대로이거나 또는 수정된 경우에도 메시지는 원래의 목적지로 전달된다.
lParam 매개변수는 MSG 구조체에 대한 포인터를 가지고 있다.
typedef struct tagMSG { /* msg */
HWND hwnd; // 해당 메시지를 처리할 Winproc 함수를 가지고 있는 윈
도우
UINT message; // message number
WPARAM wParam;
LPARAM lParam;
DWORD time; // 메시지가 발생한 시간
POINT pt; // 화면 좌표계에서 메시지가 발생한 커서 위치
} MSG;
WH_HARDWARE
이 훅은 현재 Win32에서 구현되어 있지 않다.
Journal Hooks
Journal 훅은 이벤트를 기록하고 재생하기 위해 사용된다. 이들은 시스템 범위의 훅으
로만 사용되며 따라서 가능한 사용하지 않는 것이 좋다. 이들 훅은 모든 윈도우 기반
응용 프로그램에 영향을 미친다. 또 하나 journal 훅의 부작용은 모든 시스템 입력 큐
가 훅을 설치한 쓰레드에 집중된다는 점이다. 이는 모든 시스템 입력이 한 점을 통과
해야 한다는 것을 의미한다.
Win32는 이 훅이 시스템을 먹통으로 만들지 않도록 journal 훅을 취소하는 방법을 제
공한다. 운영 체제는 사용자가 CTRL+ESC, ALT+ESC, 또는 CTRL+ALT+DEL 키를 누르면 기
록이나 재생을 위한 journal 훅을 제거한다. 훅을 제거한 후에 운영 체제는
WM_CANCELJOURNAL 메시지를 보내 응용 프로그램에 훅이 제거되었다는 사실을 알린다.
Win32 takes special steps to allow a user to cancel a journal hook so that it
does not lock the system. Windows will uninstall a record or playback journal
hook when the user presses CTRL+ESC, ALT+ESC, or CTRL+ALT+DEL. Windows then
notifies the application that had a journal hook installed by posting a
WM_CANCELJOURNAL message.
WM_CANCELJOURNAL
이 메시지는 윈도우 프로시저로 전송되지 않도록 NULL 값을 갖는 윈도우 핸들과 더불
어 발생한다. 이 메시지를 알아챌 수 있는 가장 좋은 방법은 이 메시지를 감시하는
WH_GETMESSAGE 필터 함수를 설치하는 것이다. Win32 문서에 응용 프로그램이
WM_CANCELJOURNAL 메시지를 GetMessage (또는 PeekMessage) 함수와 DispatchMessage
함수를 호출하는 중간에 잡아낼 수 있다고 되어있다. 비록 이 시점에서 이 메시지를
잡아낼 수 있지만, 메시지가 보내졌을 때 응용 프로그램은 메시지를 잡아낼 수 있는
위치에 있지 않을 것이다. 예를 들어 응용 프로그램이 다이아로그 박스인 경우 main
message loop는 호출되지 않을 것이다.
CTRL+ESC, ALT+ESC, 그리고 CTRL+ALT+DEL 키 조합은 journal 훅을 중지시키기 위해 시
스템에 설치되어 있다. journal 훅을 사용하는 모든 응용 프로그램이 journaling을 중
지시키는 방법을 갖는 것은 바람직하다. journaling을 중지시키는 방법으로 권장되는
것은 VK_CANCEL (CTRL+BREAK) 키를 이용하는 방법이다.
WH_JOURNALRECORD
시스템 큐에서 이벤트를 제거할 때 이 훅을 호출한다. 따라서 필터 함수는 journal 재
생 훅에 의해 재생되는 경우를 제외하고는 모든 마우스와 키보드 이벤트에 대해 호출
된다. 필터 함수는 메시지를 처리한다. 즉 이벤트를 메모리나 디스크 또는 양 쪽 모두
에 저장할 수 있다. 하지만 메시지를 수정하거나 제거할 수는 없다. 이 훅을 위한 필
터 함수는 DLL에 있거나 .EXE 파일에 있어야 한다. HC_ACTION 훅 코드만이 Win32에서
구현되어 있다.
HC_ACTION
시스템 큐에 이벤트를 받았을 경우 이 훅 코드를 사용하여 WH_JOURNALRECORD 훅을 호
출한다. 이 훅 코드는 필터 함수에 발생한 이벤트가 정상적인 이벤트라는 것을 알린
다. [정상적이라는 말은 재생된 이벤트가 아니라는 말이다.] 필터 함수의 lParam 매개
변수는 EVENTMSG 구조체의 포인터를 가지고 있다. 보통의 이벤트 기록 방식은 훅으로
넘어온 EVENTMSG 구조체를 메모리나 디스크로 저장하는 것이다.
EVENTMSG 구조체는 WINDOWS.H에 정의되어 있다.
typedef struct tagEVENTMSG {
UINT message;
UINT paramL;
UINT paramH;
DWORD time;
HWND hwnd;
} EVENTMSG;
typedef struct tagEVENTMSG *PEVENTMSG, NEAR *NPEVENTMSG, FAR *LPEVENTMSG;
EVENTMSG 구조체에서 message는 메시지 ID로 WM_* 값을 가진다. paramL과 paramH는 발
생한 이벤트가 마우스 이벤트인지 키보드 이벤트인지에 따라 다르다. 마우스 이벤트
인 경우 이벤트가 발생한 위치의 좌표를 가지고 있다. 키보드 이벤트인 경우 paramL
은 HIBYTE에 scan code를 LOBYTE에 가상 키 코드를 가지고 있으며, paramH는 반복 횟
수를 가지고 있다. 반복 횟수의 15번째 비트는 그 이벤트가 확장 키인지를 나타낸다.
EVENTMSG 구조체의 시간 요소에는 이벤트가 발생한 시스템 시간이 GetTickCount 함수
를 사용하여 저장된다. hwnd는 이벤트가 발생한 윈도우의 핸들이다.
두 이벤트 사이의 시간은 시간 요소를 비교하여 얻을 수 있다. 이 값은 저장된 이벤트
를 재생할 때 필요하다.
WH_JOURNALPLAYBACK
이 훅은 마우스나 키보드 메시지가 실제로 발생한 것처럼 시스템 큐에 입력하기 위해
사용된다. 이 훅은 보통 WH_JOURNALRECORD 훅에 의해 저장된 이벤트를 재생하기 위해
사용되지만, 다른 응용 프로그램에 이벤트를 전달하기 위한 가장 좋은 방법이기도 하
다. 이 훅에 필터 함수가 설치되면, 운영체제는 필터 함수열에서 첫 번째 필터 함수
를 호출하여 이벤트를 얻는다. WH_JOURNALPLAYBACK 훅이 설치된 경우 마우스 움직임
은 무시된다. 키보드나 마우스 입력과 관련된 다른 메시지들은 WH_JOURNALPLAYBACK 훅
에 설치된 필터 함수가 더 이상 없을 때까지 큐에 저장된다. 이 훅을 위한 필터 함수
는 DLL이나 .EXE 파일에 있어야 한다. 이 훅에 설치된 필터 함수는 다음의 코드를 처
리할 수 있다.
HC_GETNEXT
HC_SKIP
HC_GETNEXT
운영 체제가 쓰레드의 입력 큐에 접근할 때 이 훅 코드로 WH_JOURNALPLAYBACK 훅을 호
출한다. 대부분의 경우 운영체제는 동일한 메시지에 대해 여러 번 동일한 호출을 한
다. 필터 함수의 lParam 매개변수는 EVENTMSG 구조체에 대한 포인터를 가지고 있다.
필터 함수는 EVENTMSG 구조체에서 message, paramL, paramH의 값을 설정하여야 한다.
이들 값은 보통 WH_JOURNALRECORD를 사용하여 기록한 이벤트에서 복사된다.
필터 함수는 운영 체제에게 필터 함수가 제공한 메시지를 언제 처리할지 알려 주어야
한다. 운영체제는 두 가지 값을 필요로 한다: (1) 메시지를 처리하기 전에 운영 체제
가 기다려야 하는 시간; (2) 메시지가 처리되어야 하는 시간. 기다리는 시간을 계산하
는 전형적인 방법은 EVENTMSG 구조체의 시간 요소를 사용하는 것이다. 이 방법은 이벤
트가 기록된 것과 동일한 속도로 재생할 수 있도록 해준다. 만약 메시지가 즉시 처리
되어야 한다면 영(zero)의 값을 반환할 것이다.
메시지가 처리되어야 하는 시간은 운영 체제가 메시지 처리를 위해 기다려야 하는 시
간과 GetTickCount에서 얻어진 현재 시스템 시간을 더해서 얻을 수 있다. 즉시 처리해
야 한다면 GetTickCount에서 반환된 값을 사용하면 된다.
시스템이 active하지 않으면 운영체제는 필터 함수가 이벤트 처리를 위해 제공한 값들
을 사용한다. 시스템이 active하면 운영체제는 시스템 큐를 검사한다. 각각의 경우
HC_GETNEXT 훅 코드로 동일한 이벤트를 탖느다. 필터 함수가 HC_GETNEXT를 받았을 때
에는 연속적인 호출 사이의 대기 시간을 반환해야 한다. EVENTMSG 구조체, 메시지,
paramH 값, paramL 값은 수정할 필요가 없다.
HC_SKIP
운영 체제가 WH_JOURNALPLAYBACK 훅에서 받은 메시지 처리를 끝냈을 때 이 훅 코드를
사용하여 WH_JOURNALPLAYBACK 훅을 호출한다. 만약 WH_JOURNALPLAYBACK 훅에 의해 생
성된 이벤트가 아니고 시스템 큐에 있던 이벤트라면 이 코드는 운영 체제가 시스템 큐
에서 이벤트를 제거했을 때 발생한다. 이 훅 코드는 필터 함수에게, 이전의
HC_GETNETXT 호출에서 필터 함수가 넘겨준 이벤트가 응용 프로그램에 전달되었다는 것
을 알려준다. 필터 함수는 다음 HC_GETEVENT 호출에서 다음 이벤트를 반환할 수 있는
준비를 해야 한다. 필터 함수가 더 이상 재생할 이벤트가 없는 경우에는 HC_SKIP 호출
에서 자신을 해제해야 한다.
WH_KEYBOARD
GetMessage 함수나 PeekMessage 함수가 WM_KEYUP, WM_KEYDOWN, WM_SYSKEYUP,
WM_SYSKEYDOWN, WM_CHAR 등의 메시지를 반환하려고 할 때 이 훅을 호출한다. 쓰레드
훅의 경우 이들 메시지는 쓰레드의 입력 큐에 있어야 한다. 필터 함수는 가상 키 코드
와 키보드 훅이 발생했을 때의 키보드 상태를 받는다. 이 훅에 설치된 필터 함수는 다
음 훅 코드를 처리할 수 있다.
HC_ACTION
HC_NOREMOVE
HC_ACTION
시스템 큐에서 이벤트가 제거될 때 이 훅 코드를 사용하여 WH_KEYBOARD 훅을 호출한
다.
HC_NOREMOVE
응용 프로그램이 PM_NOREMOVE 옵션을 사용하여 PeekMessage 함수를 호출하였기 때문
에 키보드 이벤트가 제거되지 않았을 때 이 훅 코드를 사용하여 WH_KEYBOARD 훅을 호
출한다. 이 훅 코드가 전달되면 키 상태 테이블(key-state table)은 이전의 키 상태
를 반영하지 않는다. 응용 프로그램은 이러한 옵션이 있다는 것을 알고 있어야 한다.
WH_MOUSE
GetMessage 함수나 PeekMessage 함수가 호출되었을 때 처리할 마우스 메시지가 있으
면 이 훅이 호출된다. WH_KEYBOARD 훅과 마찬가지로 이 필터 함수는 메시지가 제거되
었는지(HC_NOREMOVE)를 나타내는 훅 코드, 마우스 메시지 ID, 그리고 마우스의 좌표
를 받게 된다. 필터는 운영 체제에게 메시지를 버리도록 할 수 있다. 이 훅에 대한 필
터는 DLL에 있어야 한다.
WH_MSGFILTER
다이알로그 박스, 메시지 박스, 스크롤 바, 또는 메뉴가 메시지를 발생시켰을 경우 그
리고 훅을 설정한 응용 프로그램에서 사용자가 ALT+TAB이나 ALT+ESC 키를 눌렀을 때
이 훅을 호출한다. 이 훅은 쓰레드 훅으로만 사용될 수 있으므로 응용 프로그램이나
DLL에 필터 함수를 둘 수 있다. 필터 함수는 다음의 훅 코드들을 받는다.
MSGF_DIALOGBOX : 다이알로그 박스나 메시지 박스의 메시지.
MSGF_MENU : 메뉴 메시지
MSGF_SCROLLBAR : 스크롤 바 메시지
MSGF_NEXTWINDOW: 다음 윈도우러 전환하려고 할 때
MSGF_* 값으로 정의된 값들이 WINUSER.H에 보면 더 있지만 현재의 WH_MSGFILTER 훅에
는 사용되지 않는다.
lParam 매개변수는 메시지를 포함하고 있는 구조체의 포인터를 가지고 있다.
WH_SYSMSGFILTER 훅이 WH_MSGFILTER 훅 이전에 호출된다. 만약 WH_SYSMSGFILTER 훅이
TRUE를 반환하면 WH_MSGFILTER 훅은 호출되지 않을 것이다.
WH_SHELL
최상위 윈도우에서 어떤 동작이 발생했을 때 이 훅을 호출한다. 쓰레드 훅의 경우 동
일한 쓰레드에 속하는 윈도우에 대해서만 이 훅을 호출한다. 이 훅은 통지
(notification)만 할 수 있으므로 필터 함수는 이벤트를 수정하거나 제거할 수 없다.
wParam 매개변수는 윈도우의 핸들을 가지고 있고 lParam 매개변수는 사용되지 않는
다. WINUSER.H에 3가지 훅 코드가 정의되어 있다.
HSHELL_WINDOWCREATED: 최상위 윈도우가 생성되었을 때 이 훅 코드를 사용하여 호출한
다. 훅이 호출되었을 때 윈도우는 이미 화면에 보여지고 있다.
HSHELL_WINDOWDESTROYED: 최상위 윈도우가 파괴되려고 할 때 이 훅 코드를 사용하여
호출한다.
HSHELL_ACTIVATESHELLWINDOW: 이 훅 코드는 현재 사용되지 않는다.
WH_SYSMSGFILTER
이 훅은 시스템 범위의 훅이라는 점을 제외하고는 WH_MSGFILTER 훅과 동일하다. 다이
알로그 박스, 메시지 박스, 스크롤 바, 또는 메뉴가 메시지를 발생시켰을 경우 그리
고 사용자가 ALT+TAB이나 ALT+ESC 키를 눌렀을 때 이 훅을 호출한다. 필터 함수는
WH_MSGFILTER에서와 동일한 훅 코드를 받는다.
lParam 매개변수는 메시지를 포함하는 구조체의 포인터를 가지고 있다.
WH_SYSMSGFILTER 훅은 WH_MSGFILTER 훅 이전에 호출된다. WH_SYSMSGFILTER 훅의 필터
함수가 TRUE를 반환하면 WH_MSGFILTER 훅은 호출되지 않을 것이다.
첨부된 샘플 : From MSDN
출처 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=1498&ref=660