본문 바로가기
Delphi/프로시저-함수

Hook(훅) SetWindowsHookEx

by MonoSoft 2023. 7. 7.
728x90
반응형

Hook(훅) SetWindowsHookEx 

 

 

 

 

SetWindowsHookEx 함수는 Windows 운영 체제에서

훅(Hook)을 설치하기 위해 사용되는 함수입니다.

 

훅은 시스템 내에서 발생하는 이벤트를 감지하고

해당 이벤트에 대한 처리를 수행하는 데 사용됩니다.

 

예를 들어, 키보드 이벤트, 마우스 이벤트, 윈도우 메시지 등을 감지하고

원하는 동작을 수행할 수 있습니다.

 

SetWindowsHookEx 함수는 다음과 같은 매개변수를 가지고 있습니다

 

idHook: 설치할 훅의 유형을 지정하는 매개변수로, 훅의 종류에 따라 다른 상수 값을 사용합니다.

예를 들어, WH_KEYBOARD는 키보드 이벤트를 감지하는 훅을 설치하는 상수입니다.

 

lpfn: 훅 프로시저(Hook Procedure)로서 호출될 함수의 포인터입니다.

훅 이벤트가 발생할 때마다 해당 함수가 호출됩니다.

 

hMod: 훅 프로시저가 포함된 DLL의 핸들입니다.

일반적으로 자신의 DLL을 만들고 해당 DLL의 핸들을 전달합니다.

그러나 현재 프로세스 내에서 훅을 설치하는 경우 NULL 값을 사용할 수도 있습니다.

 

dwThreadId: 훅 프로시저를 연결할 스레드의 식별자입니다.

 

0을 전달하면 시스템 전체에 대해 훅을 설치합니다.

 

SetWindowsHookEx 함수는 설치된 훅에 대한 핸들을 반환하며,

이 핸들은 후속 작업에서 훅을 제거할 때 사용됩니다.

 

다음은 Delphi에서 SetWindowsHookEx 함수를 사용하여

키보드 이벤트를 감지하는 예제 코드입니다

 

unit Unit1;

 

interface

 

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;

 

type

  TForm1 = class(TForm)

    procedure FormCreate(Sender: TObject);

    procedure FormDestroy(Sender: TObject);

  private

    { Private declarations }

    FHookHandle: HHOOK;

    procedure KeyboardHookProc(var Msg: TMessage);

  public

    { Public declarations }

  end;

 

var

Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

function HookCallback(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;

begin

  if nCode = HC_ACTION then

  begin

    // 키보드 이벤트 처리

    // wParam: 이벤트 유형 (WM_KEYDOWN, WM_KEYUP 등)

    // lParam: 이벤트 정보 (키 코드 등)

    // 원하는 동작을 수행하면 됩니다.

  end;

 

  Result := CallNextHookEx(0, nCode, wParam, lParam);

end;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  FHookHandle := SetWindowsHookEx(WH_KEYBOARD, @HookCallback, HInstance, 0);

  if FHookHandle = 0 then ShowMessage('Hook installation failed.');

end;

 

procedure TForm1.FormDestroy(Sender: TObject);

begin

  if FHookHandle <> 0 then UnhookWindowsHookEx(FHookHandle);

end;

 

end.

 

 

이 예제는 Delphi 폼 애플리케이션에서 키보드 이벤트를 감지하기 위해

SetWindowsHookEx 함수를 사용하는 방법을 보여줍니다.

 

FormCreate 이벤트 핸들러에서 훅을 설치하고,

FormDestroy 이벤트 핸들러에서 훅을 제거합니다.

 

KeyboardHookProc 함수는 훅 이벤트가 발생할 때 호출되며,

원하는 동작을 수행하는 코드를 해당 함수 내에 작성하면 됩니다.

 

 

 

-----추가내용----

 

후킹의 강력함을 모두 이용하려면 시스템에 있는 모든 윈도우에 대해서

훅을 걸어서 써야겠지만 간혹 자신의 윈도우 안에서만

후킹을 해야 할 경우가 있습니다.

 

( 'KeyPreView := true'로는 해결이 안되고 모든 키에 대해서

처리를 해야 할 경우라든지, 폼위에서(Caption이나 Menu위에서) 움직이는

마우스의 모든상태를 처리해야 한다든지 하는 경우이겠지요.. )

두 경우의 차이라면 시스템 전반에 훅을 걸 경우에는 DLL에서 걸어야 하지만

후자의 경우에는 DLL이 필요없이 프로젝트 내에서

간단하게 훅을 설치할수 있다는 것입니다.

 

이때 SetWindowsHookEx에 넣어주어야 할 매개변수가 달라지게 되지요..

가령 후자의 경우에는 ( 내 윈도우 안에만 훅을 설치할때 )

 

hMouseHook := SetWindowsHookEx( WH_MOUSE, @MouseHookProc, 0, <--GetCurrentThreadID <-);

 

세번째 인자와 네번째 인자가 DLL에서와 달라지게 됩니다.

 

위의 경우는 마우스 훅을 걸때의 상황이지요..

 

가령 키보드 훅을 걸어야 할경우에는

WH_MOUSE대신 WH_KEYBOARD이 들어가게 되구 물론 키보드 훅용 콜백함수를 쓰셔야 할겁니다.

 

SetWindowsHookEx의 두번째 인자로 들어가는 콜백함수의 형태는 어떤 후킹이든 동일합니다.

 

즉 한가지 후킹에 성공하셨다면 다른 종류의 훅도 얼마든지 설치할 수 있습니다.

 

다만 사용하려는 훅에대해 완전히 알고 있어야 사용할 수 있다는게 문제이지만...

 

대부분의 문제는 lParam을 어떻게 이용하느냐 하는것인데,

windows.pas를 보시면 어느정도 감이 잡힐것 같습니다.

 

11495 line부터 각종 훅에 대한 lParam의 구조체 타입이 나와있습니다.

 

물론 각각의 쓰임새는 공부를 하셔야 겠지요 DLL내부에서

즉 시스템 전역에 훅을 설치하실때는 세번째와 네번째 인자를

hMouseHook := SetWindowsHookEx( WH_MOUSE, @MouseHookProc, HInstance, <-0 <--);

 

로 바꾸고 DLL로 컴파일 하면 됩니다.

 

결국 내 어플리케이션 안에서 후킹을 걸어서 성공했다면

그 소스를 그대로 DLL로 컴파일 하면 시스템 전반에 걸쳐서

훅을 설치하는 것은 쉽게 이루어 진다는 얘깁니다.

 

다음은 하나의 윈도우(폼)에 마우스 훅을 걸어서 그 결과를 Caption에 표시하는 예제입니다.

 

정말로 간단하지요?

 

다른 훅의 이용도 크게 다르지 않답니다.

 

다만 헬프가 넘 어렵게 되어있구, 주위에서 참고로 할 자료를 찾기가 쉽지 않고,

* 참고로 MSDN에서 Hooking으로 검색을 하면

목록의 제목만 하나씩 보는데만도 2시간이 넘게 걸릴만큼

Hooking에 대한 자료가 많더군요 Hooking이라는 것에 대한

내면 깊숙한 곳에서 우러나오는 일종의 공포심이 결합하여 시도하기도 전에 포기하는 것 같습니다.

 

Message Hooking은 윈도우 프로그래밍에서 가장 강력한 테크닉 중하나입니다.

 

그러나 Hooking의 구현은 전혀 어렵지 않습니다.

 

여담으로 API Hooking이라는 테크닉이 있죠..

 

Message-Hooking이 시스템에 떠도는 메시지들을 가로채는 것이라면

API-Hooking은 시스템에서 어떤 API함수가 불려지면 그걸 가로채는 것이랍니다.

 

요즘 영한사전류에서 마우스만 갖다대도 글자를 인식하는데

쓰이는고급기법이죠 API-Hooking의 강력함에 비하면

Message-Hooking은 새발의피라고 할 정도입니다.

 

unit unit1 .......

.......

implementation

 

{$R *.DFM}

 

var

  hMouseHook : integer = -1;

 

function MouseHookProc(Code: Integer; wParam: WPARAM; lParam: LPARAM): Longint; stdcall;

Begin

  If (Code >= 0) Then

  Begin

    with PMouseHookStruct( lParam )^ do

      Form1.Caption := Format( '[X : %d, Y : %d] [HitTestCode : %d]', [ pt.x, pt.y, wHitTestCode ] );

    Form1.Caption := Form1.Caption + Format( ' [ wParam : %d]', [ wParam ] );

  End;

 

Result := CallNextHookEx(hMouseHook, Code, wParam, lParam);

End;

 

procedure SetMouseHook( flag : boolean );

Begin

  if not flag then begin

  if hMouseHook < 0 then

    exit;

  UnHookWindowsHookEx(hMouseHook);

  hMouseHook := -1;

  end

  else

    hMouseHook := SetWindowsHookEx( WH_Mouse, @MouseHookProc,0,GetCurrentThreadID);

End;

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  SetMouseHook( hMouseHook < 0 );

end;

 

end.

728x90
반응형

'Delphi > 프로시저-함수' 카테고리의 다른 글

태스크바 (taskbar) 에서 숨기기  (0) 2023.08.01
시스템 날짜바꾸기  (0) 2023.07.27
메모(TMemo) 팁  (0) 2023.06.14
StringGrid의 Cell에 입력 값 제한  (0) 2023.06.02
초를 시간 분 초 형식으로 리턴  (0) 2021.07.22

댓글