훅 인스턴스의 생성과 해제

31437 
Created at 2007-02-06 01:36:09 
197   0   0   0  
최근 본인은 이벤트를 감시하기 위해 훅을 사용하는 어플리케이션을 개발하고 있었다. 훅은 정말로 많은 작업에 있어서 유용하지만, 델파이에서는 직접적으로 지원되지 않기 때문에, 다음과 같이 Win32 API 호출을 사용해야 한다.





    var

      ThisHook : hHook;

    .....

      ThisHook := SetWindowsHookEx (WH_CALLWNDPROC,
    HookProc, HInstance, GetCurrentThreadID);




이것은 WH_CALLWNDPORC 타입의 훅을 현재 어플리케이션의 인스턴스와 쓰레드에 걸어준다. 훅이 발생할 때 HookProc를 호출하는데, 그것의 다음과 같이 선언되어 있다.



    function HookProc (nCode: Integer; wParam, lParam:
    Longint): Longint; stdcall;


    begin

    //.... my code goes here

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


    //.... or goes in here

    end;



여러분들은 볼랜드의 FORMS.PAS내에서 사용되는 이 호출들의 예를 발견할 수 있을 것이다. 또한 SetWindowsHookEx를 WIN32.HLP 파일에서 발견할 수 있으며 사용한 가능한 훅의 타입들에 대해서 볼 수 있을 것이다. 그러나, 이 예제에서 보듯이 훅을 사용하기 위해서는 전역 변수와 독립적으로 떨어져 나와 있는 함수를 가져야 한다는 것을 알아챘을 것이다. 이것은 동일한 어플리케이션내에서 여래개의 훅을 걸 때나, FORMS.PAS내의 경우와 같이 전역변수를 사용하지 않고 클래스내의 메소드나 변수를 참조하고 싶을 경우에는 문제가 된다.


동일한 문제가 클래스의 내부에 '윈도우 메세지 프로시져'를 작성하기를 원할 때 발생한다. 그러나, 볼랜드사는 클래스내의 '메소드'가 '윈도우 메세지 프로시져' 가 될 수 있도록 MakeObjectInstance(그리고 거기에 대응하는 FreeObjectInstace)를 제공해 주었다. 그래서, 본인은 동일한 기법으로 훅 함수로 메소드를 사용할 수 있지 않을까 하고 짐작했다. 그 결과가 되는 코드는 MakeObjectInstance를 위한 볼랜드가 제공했던 코드를 사용했지만 훅에 적절하도록 손을 봤다. 볼랜드의 원래 코드(Forms.Pas내에 있는 코드)에 약간의 변경을 가한 코드를 다음과 같이 제시한다.


    unit

      HookInst;

    interface

    uses

      Windows;

    type

      THookCall = packed record

        Code   : integer;

        WParam : WPARAM;

        LParam : LPARAM;

        Result : LResult

      end;

      THookMethod = procedure (var HookCall: THookCall)
    of object;


    function  MakeHookInstance (Method: THookMethod):
    pointer;


    procedure FreeHookInstance (ObjectInstance: pointer);

    implementation

    const

      InstanceCount = 313;  // set so that
    sizeof (TInstanceBlock) < PageSize


    type

      PObjectInstance = ^TObjectInstance;

      TObjectInstance = packed record

        Code: Byte;

        Offset: Integer;

        case Integer of

          0: (Next: PObjectInstance);

          1: (Method: THookMethod);

      end;

    type

      PInstanceBlock = ^TInstanceBlock;

      TInstanceBlock = packed record

        Next: PInstanceBlock;

        Code: array[1..2] of Byte;

        WndProcPtr: Pointer;

        Instances: array[0..InstanceCount]
    of TObjectInstance;


      end;

    var

      InstBlockList : PInstanceBlock  = nil;

      InstFreeList  : PObjectInstance = nil;

    function StdHookProc (Code, WParam: WPARAM; LParam:
    LPARAM): LResult; stdcall; assembler;


    asm

            XOR    
    EAX,EAX


            PUSH   
    EAX


            PUSH   
    LParam


            PUSH   
    WParam


            PUSH   
    Code


            MOV    
    EDX,ESP


            MOV    
    EAX,[ECX].Longint[4]


            CALL   
    [ECX].Pointer


            ADD    
    ESP,12


            POP    
    EAX


    end;

    { Allocate a hook method instance }

    function CalcJmpOffset(Src, Dest: Pointer): Longint;

    begin

      Result := Longint(Dest) - (Longint(Src) +
    5);


    end;

    function MakeHookInstance(Method: THookMethod): Pointer;

    const

      BlockCode: array [1..2] of Byte = ($59, $E9);

      PageSize = 4096;

    var

      Block: PInstanceBlock;

      Instance: PObjectInstance;

    begin

      if InstFreeList = nil then

      begin

        Block := VirtualAlloc (nil, PageSize,
    MEM_COMMIT, PAGE_EXECUTE_READWRITE);


        Block^.Next := InstBlockList;

        Move(BlockCode, Block^.Code, SizeOf(BlockCode));

        Block^.WndProcPtr := Pointer(CalcJmpOffset(@Block^.Code[2],
    @StdHookProc));


        Instance := @Block^.Instances;

        repeat

          Instance^.Code :=
    $E8;


          Instance^.Offset :=
    CalcJmpOffset(Instance, @Block^.Code);


          Instance^.Next :=
    InstFreeList;


          InstFreeList := Instance;

          Inc(Longint(Instance),
    SizeOf(TObjectInstance));


        until Longint(Instance) - Longint(Block)
    >= SizeOf(TInstanceBlock);


        InstBlockList := Block

      end;

      Result := InstFreeList;

      Instance := InstFreeList;

      InstFreeList := Instance^.Next;

      Instance^.Method := Method

    end;

    { Free a hook method instance }

    procedure FreeHookInstance (ObjectInstance: Pointer);

    begin

      if ObjectInstance <> nil then

      begin

        PObjectInstance(ObjectInstance)^.Next
    := InstFreeList;


        InstFreeList := ObjectInstance

      end

    end;

    end.




유닛의 문서화가 잘되지 못해 유감이다. 본인도 어떤 원리로 작동하고 있는지는 이해했지만, 이 코드를 완벽하게 이해하지는 못했다. 하지만 제대로 동작을 한다.


어떻게 사용할 것인가?

여러분이 클래스내에서 WH_CALLWNDPROC를 사용하기를 원한다고 하자. 여러분의 훅 함수, 포인터 변수(메소드에 대한 포인터가 될 것임), 그리고 훅 핸들(훅 이벤트를 올바르게 연결할 수 있기 위해서임)을 선언하라.

    type

      TMyClass = class (TWhat)

    ....

      private

        ThisHook : hHook;

        HookProc : pointer;

    ....

       function MyHookProc (var HookCall: THookCall);

    ....

      end;


그리고, 클래스의 생성자에서 클래스 메소드에 대한 포인터를 만들고, API 함수를 호출하여 훅을 구동시킨다.

      HookProc := MakeHookInstance (MyHookProc);

      ThisHook := SetWindowsHookEx (WH_CALLWNDPROC, HookProc, HInstance, GetCurrentThreadID);


그리고, 다음단계로 훅 함수를 선언해야 하는데, 요것은 클래스의 메소드가 된다. :)

    function TMyClass.MyHookProc (var HookCall: THookCall);

    begin

    ....

      with HookCall do

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


    ....

    end;


마지막으로 소멸자에서 훅에 대한 해제 작업을 한다.

      UnhookWindowsHookEx (ThisHook);

      FreeHookInstance (HookProc);




그래서, 결론을 내리면...

전역 변수는 없다! 독립적으로 떨어져 나와 있는 훅 함수도 없다! 훅 함수는 쉽게 클래스 메소드를 참조할 수 있다.



Tags: 윈도우즈 Share on Facebook Share on X

◀ PREVIOUS
virtual와 override 문의 사용법에 대해서
▶ NEXT
Apple iPod Remote Control Protocol
  Comments 0
Login for comment
SIMILAR POSTS

virtual와 override 문의 사용법에 대해서 (created at 2007-02-06)

델파이로 긁어오는 HTML 페이지 (created at 2007-02-06)

Apple iPod Remote Control Protocol (created at 2007-02-06)

대문자, 소문자 변환 함수 (created at 2007-02-14)

PC에서 동영상 삭제가 안될때. (created at 2007-02-14)

마우스 커서 모양바꾸기 (created at 2007-01-28)

Windows95/98 암호 알아내기 (created at 2007-01-28)

작업관리자에서 윈도우 감추기 (created at 2007-01-26)

여러가지 시스템 종료 기법 (created at 2007-01-26)

키보드로 마우스 커서 움직이기 (created at 2007-01-26)

파일 등록정보 보여주기 (created at 2007-01-26)

대화상자에 비트맵 올리기 (created at 2007-01-26)

다이얼로그 리소스대로 폼뷰 크기 설정하기 (created at 2007-01-26)

CD, 플로피등의 디스크 삽입 자동 판단루틴 (created at 2007-01-26)

리스트박스 엔터처리 (created at 2007-01-26)

뷰의 배경색 바꾸기 (created at 2007-01-26)

버튼으로 해당 윈도우 종료하기 (created at 2007-01-26)

태스크 바를 없애버리고 싶다 (created at 2007-01-26)

태스크 바에서 프로그램(윈도우) 제목 숨기기 (created at 2007-01-26)

네임드 커널 오브젝트를 사용한 중복 실행 방지법 (created at 2007-01-26)

MSN Live Messenger가 동작이 안되요 (created at 2007-01-26)

WinGate 깔았더니 블루스크린이 떠요 (created at 2007-01-25)

mdb 파일의 암호깨기 (created at 2007-01-25)

윈도우 버전 알아내는 함수 (created at 2007-01-25)

DEP 기능 비활성화 (created at 2007-01-24)

버퍼 오버 플로우 공격과 DEP (created at 2007-01-24)

Internet Explorer가 자주 비정상 종료 할때 (created at 2006-12-29)

VC 에서 자동으로 빌드 넘버 증가하기 (created at 2006-12-28)

GetDC()의 메모리 누수 막기 (created at 2006-12-27)

모달리스 다이얼로그 와 메모리 리크(Leaks) (created at 2006-12-27)

OTHER POSTS IN THE SAME CATEGORY

폴더 창 실행 속도 끌어올리기 (created at 2007-05-18)

윈도의 묵묵부답! '무응답 시간' 단축하기 (created at 2007-05-18)

리아(RIA)가 온다...리아를 주목하라... (created at 2007-05-16)

WindowsXP 부팅시 부팅 로고 안나오게 하는 방법 (created at 2007-05-14)

노턴 고스트 2005 (9.0) 설치 및 사용방법 (created at 2007-05-13)

php로 년,월,일 요일 구하기 (created at 2007-05-11)

매번 rand결과가 같게 나오지 않게 하려면 (created at 2007-05-08)

PHP, 정규분포 난수 생성, 가우스 분포 랜덤 발생 함수; Normal Distribution (created at 2007-05-08)

오늘 날짜를 문자열로 변환 (created at 2007-05-08)

특정 폴더의 특정 파일만 파일명으로 지우기 (created at 2007-05-07)

ShellExecuteEx를 이용한 커맨드라인 기반 어플리케이션 실행 (created at 2007-05-07)

PC에서 동영상 삭제가 안될때. (created at 2007-02-14)

대문자, 소문자 변환 함수 (created at 2007-02-14)

HTML Color Table (created at 2007-02-08)

Apple iPod Remote Control Protocol (created at 2007-02-06)

virtual와 override 문의 사용법에 대해서 (created at 2007-02-06)

델파이로 긁어오는 HTML 페이지 (created at 2007-02-06)

Apache rewrite 사용 방법 (created at 2007-02-02)

태터툴즈에서 게시물을 id가 아닌 제목으로 뿌리는 방법 (created at 2007-02-02)

애드센스 기록기, Mysense! (created at 2007-02-02)

소켓으로 메일보내기 (created at 2007-01-30)

실수로 삭제한 mysql DB 복구방법 (created at 2007-01-30)

MySQL root 패스워드 분실했을 경우 (created at 2007-01-30)

컴퓨터 활용팁 100가지 (created at 2007-01-30)

마우스 커서 모양바꾸기 (created at 2007-01-28)

이미지가 많아서 로딩할때 시간이 많이걸릴 경우 (created at 2007-01-28)

스크롤바에 붙어다니는 이미지 (created at 2007-01-28)

이미지의 다운로드를 막아주는 스크립트 (created at 2007-01-28)

큰 이미지를 화면크기에 맞게 자동으로 사이즈 조절 (created at 2007-01-28)

랜덤 이미지 로딩시키기 (created at 2007-01-28)

UPDATES

글루코사민 vs. 콘드로이친: 무엇이 더 나은 관절 건강 보조제일까? (created at 2024-04-22)

광주 5·18 민주화운동 알린 테리 앤더슨 前 AP 기자 (created at 2024-04-22)

햄과 소세지가 우리 몸에 일으키는 부작용 (updated at 2024-04-22)

콘드로이친의 염증 감소효과 (updated at 2024-04-22)

코사민 DS - 글루코사민+콘드로이친 복합물이 함유된 퇴행성 관절 건강보조제 (updated at 2024-04-22)

삼겹살 먹을때 환상조합 (created at 2024-04-22)

일본 여중생의 특이한 취향 (created at 2024-04-22)

우리가 먹는 약물이 바꿔버린 생태계 (created at 2024-04-21)

일본에서 그린 상상속의 사무직과 현실속의 사무직 (updated at 2024-04-21)

북한 미대생들이 그린 북한 최고존엄 김정은 (created at 2024-04-21)

입사 후 1년도 되지 않은 회사에서 구조조정에 의한 퇴직 불응에 따른 해고 처리시 대응 가능한 방법 (updated at 2024-04-20)

한고은님의 옛날 사진 (updated at 2024-04-20)

소녀대 - Bye Bye Girl (updated at 2024-04-13)

대한민국 날씨 근황 (created at 2024-04-13)

성일종 인재육성 강조하며 이토 히로부미 언급 - 인재 키운 선례? (updated at 2024-04-13)

일제강점기가 더 살기 좋았을지도 모른다는 조수연 국민의힘 후보 - 친일파? (updated at 2024-04-13)

Marshall Ha님의 샤오미 SU7 시승기 - 테슬라의 일론 머스크님이 긴장할만한 느낌 (updated at 2024-04-09)

윙크하는 귀염둥이 반려견들 (created at 2024-04-08)

달콤 살벌한 고백 (created at 2024-04-08)

북한 최정예 공수부대 훈련 모습 (updated at 2024-04-02)

맛있었던 친구 어머니의 주먹밥이 먹고 싶어요 (created at 2024-04-02)

자리 마음에 안든다고 6급 공무원 패는 농협 조합장 (created at 2024-03-26)

85세 딸 짜장면 사주는 102세 어머니 (created at 2024-03-26)

1990년대 감각파 도둑 (created at 2024-03-26)

치매에 걸린 69살의 브루스 윌리스가 전부인 데미무어를 보고 한 말 (updated at 2024-03-22)

경제는 대통령이 살리는 것이 아닙니다 라던 윤석열대통령 - 상황 안좋아지자 여러 전략을 펼쳤지만, 부작용 속출했던 2024년의 봄 (updated at 2024-03-13)

극빈의 생활을 하고 배운것이 없는 사람은 자유가 뭔지도 모를 뿐 아니라 왜 개인에게 필요한지에 대한 필요성을 못느낀다는 윤석열 대통령 (updated at 2024-03-08)

조선일보를 안본다는 사람들이 말하는 그 이유 - 천황폐하, 전두환 각하, 김일성 장군 만세? (created at 2024-03-07)

광폭타이어를 장착하면 성능이 좋아질거라는 착각 (updated at 2024-03-03)

면허시험장에서 면허갱신하면 하루만에 끝나나? (updated at 2024-03-03)