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.