본문

P/Invoke로 다이얼로그 창 제어하기 #2. SetWindowsHookEx() 소개

이전글(P/Invoke로 다이얼로그 창 제어하기 #1. 현재 프로세스 제어)에 이어서 계속 진행됩니다.

이 기술의 핵심은 SetWindowsHookEx() WINAPI를 사용하는 것입니다. 이에 대한 설명은 MSDN 페이지(SetWindowsHookEx function)에 잘 나와있으며, 이를 번역, 요약하여 가져오자면 다음과 같습니다.

SetWindowsHookEx()는 훅 체인(hook chain)에 특정 어플리케이션을 위한 훅 프로시져를 추가합니다. 훅 프로시져를 설치함으로서 (특정 스레드에 한정되거나 혹은 전역적인)특정한 이벤트를 검출해낼 수 있습니다. 원형은 다음과 같습니다.

HHOOK WINAPI SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);

  • idHook : 추가될 훅 프로시져의 종류이며, WH_CALLWNDPROC, WH_CBT 등의 값을 가집니다.
  • lpfn : 훅 프로시져의 포인터를 가리킵니다. 만약 dwThreadId가 0이거나, 현재 프로세스와는 다른 프로세스에서 만들어진 스레드의 식별자를 가리킨다면, lpfn은 DLL에 들어있는 훅 프로시져를 가리켜야 합니다. 혹은, lpfn은 현재 프로세스내에 위치한 훅 프로세스를 가리킬 수도 있습니다.
  • hMod : lpfn에서 가리켜진 훅 프로시저를 포함하는 DLL에 대한 핸들입니다. dwThreadId가 현재 프로세스에 의해 생성된 스레드를 가리키고, 훅 프로시저가 현재 프로세스내에 위치한경우, hMod는 NULL으로 설정되어야 합니다.
  • dwThreadId : 훅 프로시저가 연결될 스레드의 식별자입니다. 만약 이 값이 0으로 설정이 되어있다면, 훅 프로시져는 모든 스레드에 연결되게 됩니다(전역적)

* 참고사항
반환값으로 성공시 훅 프로시져에 대한 핸들을(lpfn), 실패시 NULL을 반환합니다. 프로세스와 DLL이 서로 다른 비트체계를 가질경우 동작하지 않으며, 32비트와 64비트 DLL은 서로 다른 이름을 가져야 합니다. 또한, hMod가 NULL이고 dwThreadId가 0 혹은 다른 프로세스에 의해 만들어진 스레드의 식별자를 갖는다면 오류가 발생할 것입니다.

훅 프로시저 뒤에 CallNextHookEx()를 실행하는것은 강제적이지는 않지만, 매우 권장하는 사항입니다. 이를 수행하지 않을 경우, 마찬가지로 훅을 추가한 다른 어플리케이션이 훅 이벤트를 받지 못할것이며 따라서 원하는 기능을 수행하지 못하기 떄문입니다. 다른 어플리케이션이 메시지를 받지 못하게 하려는 목적이 아닌이상 CallNextHookEx를 수행해야 합니다. 또한 종료전에 UnhookWindowsHookEx()를 실행함으로서 훅과 관련한 자원들을 해제시켜야 합니다.


=======================
너무 페이지를 잘게 쪼개 놓아도 불편하지만(많은 외국사이트가 이래놔서 귀찮음), 그래도 기술적인 소개를 할때 스크롤의 압박이 생긱면 괜시리 어려운 글인것처럼 느껴져서 읽기 싫어지는 경우가 있다. 딱 아래의 '요약글' 기능처럼 클릭하나로 다른 게시물의 내용을 보이고 감출 수 있으면 좋겠다. 비동기적으로 글내용만 추가하면 되니.. 한번 건의해볼만 한 기능인것 같다.

아무튼 SetWindowsHookEx()에서 인자값들이 중요하기에 정리해서 올려본다. 정리하자면, 만약 현재 프로세스에 한정해서 후킹을 하고 싶다.. 하면 lpfn은 함수포인터를 가리키고 nMode는 NULL, dwThreadId는 GetCurrentThreadId()으로 처리하면 된다는것이고(이전 게시물에서 적용되었던 내용), 그 이외는 DLL을 등록해서 사용해야 한다. 특히 .net에서는 전역후킹(global hook, dwThreadId=0 인경우)은 키보드와 마우스만으로 한정되기 때문에 이를 위해서 native DLL을 작성해야 한다.(다른 방법들도 있는것 같다)




댓글

Holic Spirit :: Tistory Edition

design by tokiidesu. powerd by kakao.