KeyBoard Hook

 

Programok írásánál gyakran van szükségünk arra, hogy minden billentyű leütésekor egy adott kódrészlet fusson le. DOS alatt anno ezt egyszerűen meg lehetett oldani a 9-es megszakítási vektor átírásával. Védett módban azonban megszakítási leírótábla van, amihez egy egyszerű, user módban futó program nem férhet hozzá. Ebben a cikkben elsősorban a KeyBoard hook-ot fogjuk megismerni a gyakorlati oldaláról. A hook-oknak 2 fajtája van, Local és Remote. Az első csak a saját processzünkre vonatkozik, a második pedig az összesre. Az események hook-olása hatással van az egész operációsrendszerre, annak sebességére, így amint nincs szükségünk rá unhook-olni kell az eseményt. Ha remote hook-ot használunk akkor fontos hogy a hook procedure dll-ben legyen.

 

A hook installálásához a SetWindowsHookEx() függvényt használhatjuk, uninstallálásához pedig a UnhookWindowsHookEx()–et.

 

HHOOK SetWindowsHookEx(

    int idHook,   // type of hook to install

    HOOKPROC lpfn,  // address of hook procedure

    HINSTANCE hMod,          // handle of application instance

    DWORD dwThreadId         // identity of thread to install hook for

   );

 

BOOL UnhookWindowsHookEx(

    HHOOK hhk          // handle of hook procedure to remove

   );      

 

Paraméterek:

 

 idHook: A hook típusa pl. a mi esetünkben WH_KEYBOARD.

 Lpfn : A hook eljárás címe, ami meghívódik az esemény bekövetkeztekor.

 hMod: A dll handle-je, amit pl. a LoadLibrary() függvénnyel kaphatunk meg.

dwThreadId: ha ez a paraméter NULL, az azt jelenti hogy a hook remote, minden processzre vonatkozik.

 

A függvény visszaad egy HHOOK típusú változót, amit Unhook-oláskor az UnhookWindowsHookEx() függvénynek adhatunk meg.

 

A Hook procedure pedig a következőképpen néz ki:

 

LRESULT CALLBACK KeyboardProc(

    int code,       // hook code

    WPARAM wParam,           // virtual-key code

    LPARAM lParam    // keystroke-message information

   );

 

Most pedig jöjjön a gyakorlati rész. A következő egyszerű példaprogram a KeyBoard hook használatát fogja bemutatni. Biztosan sokan ismerik a népszerű chat programot, az ICQ-t, nekem nagyon szokatlan hogy ALT+S billentyűkombinációra lehet elküldeni az üzenetet. Egy olyan programot fogok bemutatni ami a hook segítségével, ENTER leütésére, nyomja meg az ICQ Send gombját.

A fejlesztőkörnyezet amiben megvalósítjuk: Borland C++ Builder.

 

Készítsünk új projectet, és válasszuk a DLL Wizardot.

 

A következő függvényre lesz szükségünk:

 

extern "C" __declspec(dllexport) LRESULT __stdcall CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)

{

   if (wParam==VK_RETURN) {

     char caption[256];

     HWND h =  GetForegroundWindow();

     if (h) {

      SendMessage( h, WM_GETTEXT, 256, (int)caption);

      char temp [50];

      if (sscanf(caption, "%sMessage Session", temp)==1) {

        ICQSend(caption);

      }

     }

   }

   return CallNextHookEx(hKeyhook, nCode, wParam, lParam);

}

 

A wParam paraméter tartalmazza a leütött billentyű VirtualKey kódját. Ha Enter-t ütöttek le, akkor először is megnézzük, az előtérben futó program címsorát. ICQ-nál mindig “Nick Message Session” a címsor. Ekkor hívjuk meg az ICQSend() függvényt.

 

boolean ICQSend(char *header) {

 HWND h, b;

 if (!(h = FindWindowEx(0, 0, 0, header))) return false;

 if (!(b = FindWindowEx(h, 0, 0, "&Send"))) return false;

 SendMessage(b, WM_LBUTTONDOWN, 0, 0);

 SendMessage(b, WM_LBUTTONUP, 0, 0) ;

 return true;

}

 

Ami a megadott ablakon belül megkeresi a Send gombot, mivel az S a gyorsbillentyű, ezért alá van húzva, ezt jelöli az & jel.

Ha megvan a gomb, akkor szimulál egy egérkattintást rajta.

 

Először is be kell tölteni a dll-t, erre szolgál a LoadLibrary() függvény, aminek a dll nevét kell megadnunk.

 

char dllname[]  = “hook.dll”

HWND dllhand = LoadLibrary(dllname);

 if (!dllhand) {

   ShowMessage("Hook.dll not found");

   exit(0);

 }

 

Meg kell még határoznunk a dll-ben lévő KeyboardProc() címét.

 

typedef LRESULT (__stdcall CALLBACK *TKeyboardProc) (int nCode,WPARAM wParam,LPARAM lParam);

TKeyboardProc kp;

kp = (TKeyboardProc) GetProcAddress(dllhand, "KeyboardProc");

 

Ezután beállíthatjuk a Hook-ot.

 

HHOOK hKeyhook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, dllhand, 0);

 

Így minden billentyű leütésekor és felengedésekor meg fog hívódni a dll-ben található KeyboardProc függvény.

 

Az Unhook pedig :

UnhookWindowsHookEx(hKeyhook)

 

Remélem ezek után mindenki fel tudja használni a keyboard hook-ot a céljának megfelelően.

 

Magyar Attila - m.magyar3@chello.hu