[WIN32] API Hook 정리 문서

by digipine posted Oct 29, 2017
?

Shortcut

PrevPrev Article

NextNext Article

ESCClose

Larger Font Smaller Font Up Down Go comment Print

요약
이 문서는 Win32 API에서 사용하는 훅(hook)에 대해 설명하고 있다. 여기서 다룰 내용은 훅 함수, 필터 함수 그리고 다음과 같은 종류의 훅이다.

•WH_CALLWNDPROC
•WH_CBT
•WH_DEBUG
•WH_FOREGROUNDIDLE
•WH_GETMESSAGE
•WH_JOURNALPLAYBACK
•WH_JOURNALRECORD
•WH_KEYBOARD
•WH_MOUSE
•WH_MSGFILTER
•WH_SHELL
•WH_SYSMSGFILTER
용어 이 문서에서 말하는 "윈도우"라는 용어는 16 비트 윈도우, 윈도우 NT 등을 포함하는 모든 윈도우 운영 체제를 포함한다. "윈도우 3.1"이라고 말하는 것은 그 버전을 지칭하는 말이다.

소개
윈도우 운영 체제에서 훅은 이벤트(메시지, 마우스 움직임, 키보드 입력)가 응용 프로그램에 도착하기 전에 이벤트를 가로채는 방법을 제공한다. 이 방법을 통해 이벤트에 반응하여 동작하거나 이벤트를 수정 또는 삭제할 수 있다. 이벤트를 받는 함수를 필터 함수(filter function)라고 부르며 함수가 가로채는 이벤트의 종류에 따라 나뉘어진다. 예를 들어 어떤 필터 함수는 모든 종류의 키보드와 마우스 이벤트를 받을 수 있다. 윈도우가 필터 함수를 부르기 위해서는 필터 함수가 윈도우의 훅에 설치, 다른 말로 하자면 첨가되어 있어야 한다. 하나 이상의 필터 함수를 훅에 첨가하는 것을 "훅을 설정한다(setting)"고 말한다. 하나의 훅에 둘 이상의 필터 함수가 첨가되어 있는 경우, 윈도우는 일련의 필터 함수로 연결하여 관리한다. 가장 최근에 설치된 함수는 함수열(chain)의 시작 부분에 위치하고 가장 먼저 설치된 함수는 함수열의 끝에 위치한다.

훅이 하나 이상의 필터 함수를 가지고 있고 어떤 이벤트가 이 훅을 구동시킬 경우, 윈도우는 필터 함수열의 첫 번째 필터 함수를 호출한다. 이러한 과정을 훅을 호출한다(calling)고 말한다. 예를 들어 CBT 훅에 필터 함수가 설정되어 있고 이 훅을 구동하는 이벤트(예를 들면 윈도우가 생성되려고 하는 경우)가 발생하였다면 윈도우는 필터 함수열의 첫 번째 필터 함수를 호출함으로써 훅을 호출한다.

필터 함수를 첨가하거나 제거하기 위해 응용 프로그램은 SetWindowsHookEx와 UnhookWindowsHookEx 함수를 사용한다.

훅은 윈도우 기반 응용 프로그램에 놀라운 능력을 제공한다. 다음의 응용 프로그램은 훅을 사용하여 구현할 수 있다:

•응용 프로그램의 다이알로그 박스, 메시지 박스, 스크롤 바, 메뉴 등에 주어지는 모든 메시지를 처리하거나 수정한다. (WH_MSGFILTER)
 
•시스템의 다이알로그 박스, 메시지 박스, 스크롤 바, 메뉴 등에 주어지는 모든 메시지를 처리하거나 수정한다. (WH_SYSMSGFILTER)


•GetMessage나 PeekMessage 함수가 호출되는 경우 시스템의 모든 메시지를 처리하거나 수정한다. (WH_GETMESSAGE)


•SendMessage 함수가 호출되는 경우 모든 메시지를 처리하거나 수정한다. (WH_CALLWNDPROC)


•키보드와 마우스의 이벤트를 기록하거나 재생한다. (WH_JOURNALRECORD, WH_JOURNALPLAYBACK)


•키보드 이벤트를 처리, 수정 또는 제거한다. (WH_KEYBOARD)


•마우스 이벤트를 처리, 수정 또는 제거한다. (WH_MOUSE)


•특정한 system action에 반응하도록 하여 응용 프로그램이 컴퓨터 기반 학습(Computer Based Training, CBT)이 가능하도록 만들어준다. (WH_CBT)


•다른 필터가 호출되지 않도록 한다. (WH_DEBUG)
응용 프로그램은 다음과 같은 경우 훅을 사용해 왔다:

•메뉴, 다이알로그 박스, 메시지 박스 등에 F1 도움말 키를 지원하도록 한다. (WH_MSGFILTER)


•마우스와 키보드의 이벤트를 기록하고 재생하는 방법을 제공한다. 이를 종종 매크로라고 한다. 예를 들어 Windows Recorder 보조 프로그램은 기록과 재생 기능을 위해 훅을 사용한다. (WH_JOURNALRECORD, WH_JOURNALPLAYBACK).


•메시지를 감시하여 어떤 메시지가 어떤 윈도우로 가는지 또는 특정 메시지가 어떤 동작을 일으키는지 감시한다. (WH_GETMESSAGE, WH_CALLWNDPROC) 윈도우 NT의 Win32 SDK에 있는 Spy 프로그램은 훅을 사용한다. Spy 프로그램의 소스는 SDK에 있다.


•마우스나 키보드 입력을 흉내 낼 수 있다. (WH_JOURNALPLAYBACK) 훅은 이러한 행동을 흉내내기를 보장해줄 수 있는 유일한 방법이다. 이러한 이벤트를 SendMessage나 PostMessage 함수를 사용하여 흉내내려고 한다면 윈도우의 내부는 키보드나 마우스의 상태를 갱신하지 않아서 예기치 않는 행동을 보여주는 경우가 있다. 키보드나 마우스 이벤트를 재생하기 위해 훅을 사용하는 경우, 이들 이벤트는 실제의 키보드나 마우스 이벤트와 동일하게 동작한다. Excel 프로그램은 SEND.KEYS 매크로 함수를 구현하기 위해 훅을 사용한다.


•윈도우 환경에서 동작하는 응용 프로그램을 위한 CBT를 제공한다. WH_CBT 훅은 CBT 응용 프로그램을 쉽게 만들 수 있는 방법을 제공한다.
훅의 사용 방법
훅을 사용하기 위해서는 다음 사항을 알아야 한다:

•훅의 필터 함수열에 필터 함수를 추가하거나 제거하기 위해 윈도우의 훅 함수를 어떻게 사용하는가?


•설치하는 필터 함수는 어떤 동작을 수행하여야 하는가?


•어떤 종류의 훅이 존재하며 이들은 어떤 일을 하는가 그리고 이들 훅은 필터 함수로 어떤 정보를 전달하는가?
윈도우 훅 함수
윈도우 기반의 응용 프로그램은 SetWindowsHookEx, UnhookWindowsHookEx, CallNextHookEx 함수를 사용하여 필터 함수열을 관리한다. 3.1 버전 이전의 윈도우는 SetWindowsHook, UnhookWindowsHook, DefHookProc 함수를 사용하여 훅 관리를 했다. 이들 함수가 Win32에서도 존재하지만 새로운 버전의 Ex 계열 함수에 비해 할 수 있는 일이 적다. 기존의 코드도 새로운 함수를 사용하도록 바꾸는 것이 좋으며 앞으로도 새로운 함수를 쓰는 것이 좋다.

SetWindowsHookEx와 UnhookWindowsHookEx 함수는 아래에 설명되어 있다. CallNextHookEx 함수에 대해서는 별도의 문서 "필터 함수열에서 다음 함수의 호출 Calling the next function in the filter function chain"을 참고하면 된다.

SetWindowsHookEx
SetWindowsHookEx 함수는 훅에 필터 함수를 추가한다. 이 함수는 4개의 인자를 가지고 있다:

HHOOK SetWindowsHookEx(
        int idHook,      // type of hook to install
        HOOKPROC lpfn,   // address of hook procedure
        HINSTANCE hMod,  // handle to application instance
        DWORD dwThreadId  // identity of thread to install hook for
);

•필터 함수를 추가할 훅에 대한 정수값 코드. 코드 값은 WINUSER.H에 정의되어 있고 이후에 설명할 것이다.


•필터 함수의 주소. 필터 함수는 응용 프로그램이나 DLL의 모듈 정의 파일 EXPORTS 구문에 필터 함수를 첨가하거나 적절한 컴파일러 플래그를 써서 export시켜야 한다.


•필터 함수를 포함하는 모듈의 인스턴스 핸들. Win32에서는 (Win16과는 다르게) 특정 쓰레드에 사용되는 훅의 경우 이 값이 대부분 NULL이다. 하지만 꼭 NULL이어야 하는 것은 아니다. 시스템 훅이나 다른 프로세스에 있는 쓰레드에 대한 훅인 경우에는 필터 함수가 있는 DLL의 인스턴스 핸들을 사용하여야 한다.


•훅이 설치될 쓰레드의 ID. 쓰레드의 ID가 영(zero)이 아닌 경우, 설치된 필터 함수는 특정 쓰레드의 context에서만 호출된다. 쓰레드의 ID가 영(zero)인 경우, 설치된 필터 함수는 시스템 전체 범위에 해당되며 시스템의 모든 쓰레드 context에서 호출된다. 응용 프로그램이나 라이브러리는 훅을 설치할 쓰레드의 핸들을 얻기 위해 GetCurrentThreadId 함수를 사용할 수 있다.
몇몇 훅은 시스템 범위에서만 사용될 수 있고 몇몇 훅은 특정 쓰레드에서만 사용될 수 있다. 하지만 아래 표에서처럼 대부분이 시스템이나 쓰레드 범위에서 사용될 수 있다.

Hook
 Scope
 
WH_CALLWNDPROC
 Thread or System
 
WH_CBT
 Thread or System
 
WH_DEBUG
 Thread or System
 
WH_GETMESSAGE
 Thread or System
 
WH_JOURNALRECORD
 System Only
 
WH_JOURNALPLAYBACK
 System Only
 
WH_FOREGROUNDIDLE
 Thread or System
 
WH_SHELL
 Thread or System
 
WH_KEYBOARD
 Thread or System
 
WH_MOUSE
 Thread or System
 
WH_MSGFILTER
 Thread or System
 
WH_SYSMSGFILTER
 System Only
 

 

양 쪽 모두에 사용되는 경우 쓰레드 훅이 먼저 호출되고 시스템 훅이 다음에 호출된다.

여러 가지 이유로 시스템 훅보다는 쓰레드 훅을 사용하는 것이 좋다. 쓰레드 훅의 장점에는 다음과 같은 것들이 있다:

•훅 사용과 무관한 응용 프로그램에 오버헤드를 주지 않는다.


•훅을 위한 모든 이벤트가 직렬화되지 않아도 된다. 예를 들어, 응용 프로그램이 시스템 키보드 훅을 설치하면 모든 응용 프로그램을 위한 모든 키보드 메시지가 키보드 필터 함수로 집중되어 시스템에서 제공하는 다중 입력 큐 기능을 쓸 수 없게 된다. 만약 필터 함수가 키보드 이벤트 처리를 멈추면, 실제로는 그렇지 않다고 해도 시스템이 정지한 것처럼 보일 것이다. 사용자는 이 때에도 CTRL+ALT+DEL 키를 사용하여 log-out하면 이 문제를 해결할 수 있지만 이러한 혼란이 달가울 리는 없다. 또한 사용자가 log-out과 log-on을 통해 시스템을 원상태로 할 수 있다는 사실을 모를 수도 있다.


•필터 함수 구현을 별도의 DLL로 만들 필요가 없다. 모든 시스템 훅과 다른 응용 프로그램의 특정 쓰레드를 위한 훅은 DLL로 구현하여야 한다.


•서로 다른 프로세스에서 사용되고 있는 동일한 DLL들이 데이터를 공유하지 않아도 된다. 시스템 범위의 필터 함수는 DLL로 구현하여야 하고 따라서 당여히 다른 프로세스와 공유할 필요가 있는 데이터는 공유하여야 한다. 하지만 DLL은 기본적으로 데이터를 공유하지 않으므로 시스템 범위의 필터 함수를 작성할 때는 주의가 필요하다. 데이터 공유를 잘못한 경우에는 프로세스가 파괴될 수 있다.
SetWindowsHookEx 함수는 설치된 훅에 대한 핸들(HHOOK 형)을 반환한다. 응용 프로그램이나 라이브러리는 이 핸들을 UnhookWindowsHookEx 함수를 사용하여 훅을 해제할 때 사용한다. 훅에 필터 함수를 추가할 수 없는 경우 SetWindowsHookEx 함수는 NULL을 반환한다. 또한 SetWindowsHookEx 함수는 수행에 실패한 원인을 나타내기 위해 아래의 값들 중 하나로 last error를 설정한다. 이들 정보를 얻기 위해서는 GetLastError 함수를 사용하면 된다.

•ERROR_INVALID_HOOK_FILTER: 훅 코드가 유효하지 않다.
 
•ERROR_INVALID_FILTER_PROC: 필터 함수가 유효하지 않다.
 
•ERROR_HOOK_NEEDS_HMOD: 전역적인 즉, 시스템 범위의 훅이 hInstance 인수를 NULL로 하여 설정되었거나, 쓰레드 훅이 훅을 설치하는 응용 프로그램과 동일한 쓰레드에 있지 않다.


•ERROR_GLOBAL_ONLY_HOOK: 시스템 훅으로만 사용할 수 있는 훅을 쓰레드 훅으로 설치하였다.


•ERROR_INVALID_PARAMETER: 쓰레드 ID가 유효하지 않다.


•ERROR_JOURNAL_HOOK_SET: journal 훅 형식으로 이미 설치된 필터 함수가 있다. journal record나 journal playback 훅은 한 번에 하나만 설치될 수 있다. 화면 보호기가 동작하고 있는 경우 응용 프로그램이 journal 훅을 설치하고자 하는 경우 이런 에러가 발생할 수도 있다.


•ERROR_MOD_NOT_FOUND: 전역 훅을 위한 hInstance 인수가 라이브러리가 아니다. (실제로 이 값은 모듈 핸들을 찾을 수 없을 경우에 해당한다.)


•Any other value: 보안 문제로 훅이 설치될 수 없거나 시스템의 메모리가 부족하다.
윈도우는 필터 함수열을 내부적으로 유지하고 다음 필터 함수를 찾기 위해 필터 함수에 의존하지 않는다. 윈도우 3.1 이전 버전에서는 필터 함수들 자체가 연결되어 있었다. 따라서 훅은 윈도우 3.1 버전보다 훨씬 견고해졌다. 또한 필터 함수열이 내부적으로 관리됨으로써 성능도 향상되었다.

 

윈도우 3.1에서의 필터 함수열

UnhookWindowsHookEx
훅의 함수열에서 필터 함수를 제거하기 위해서는 UnhookWindowsHookEx 함수를 사용한다. 이 함수는 SetWindowsHookEx 함수에서 반환된 훅의 핸들을 사용하고 훅이 제거되었는 지의 여부를 반환한다. 영(zero)을 반환하는 경우 제거에 실패한 것으로 GetLastError 함수를 사용하여 자세한 정보를 얻을 수 있다.

필터 함수
필터 함수는 훅에 설정되는 함수이다. 필터 함수는 윈도우에 의해 호출되고 응용 프로그램에 의해 호출되는 것이 아니다. 따라서 필터 함수는 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 응용 프로그램은 다음의 과정을 따른다.

1.CBT 응용 프로그램은 운영 체제로부터 HCBT_CLICKSKIPPED이나 HCBT_KEYSKIPPED 훅 코드를 가지는 WH_CBT 훅을 받을 때까지 기다린다. 이러한 WH_CBT 훅은 대상 프로그램의 행동을 지시한 이벤트가 시스템 큐에서 제거될 때 발생한다.


2.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 훅은 호출되지 않을 것이다.

TAG •

Articles

1 2 3