Thread View: borland.public.cppbuilder.nativeapi
1 messages
1 total messages
Started by Anders Johansen
Sat, 01 Mar 2008 09:54
Hooks, once again
Author: Anders Johansen
Date: Sat, 01 Mar 2008 09:54
Date: Sat, 01 Mar 2008 09:54
174 lines
5991 bytes
5991 bytes
Hi all.
I have so far been using the "old fashioned" approach to
keyboard and mouse hooking, meaning putting the hook procedures
in a DLL, and using the SetWindowsHookEx with WH_KEYBOARD and
WH_MOUSE. Now Vista arrives, and this approach is apparently
blocked for some applications (notable IE) when not running as
Administrator. I understand the rationale is that this allows
for code injection, which I guess is fair enough.
This is my alternate approach, submitted for comments and
inspiration.
I understand that the _LL versions of the hooks will work. They
have the disadvantage of not being available on systems older
than NT4 SP3. On the other hand, the callback does not have to
be in a DLL, which seems to work - can anybody confirm that this
is correct, e.g. that a DLL is NOT needed when using the _LL
hooks?
If, as my testing seems to validate, the hooking does not have
to happen in a DLL, this allows for a much nicer implementation
than the usual approach. Here's my first attempt, in case
anybody wants to comment or inspect...
Header:
#ifndef HookMasterH
#define HookMasterH
//---------------------------------------------------------------------------
#include <windows.h>
#include <map>
#include <set>
class HookObserver {
public:
virtual void keyDown(const UINT vkey, const bool altDown, const int keyDownNumber) = 0;
};
/*
The HookMaster uses hooks to monitor keyboard and mouse, and MSAA to
monitor focus change and window move/resize.
*/
class HookMaster {
private:
static HHOOK LLKeyHook;
static HHOOK LLMouseHook;
static int keyDownNumber;
static std::set<HookObserver*> observers;
static LRESULT CALLBACK LLKeyHookProc(int nCode, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK LLMouseHookProc(int nCode, WPARAM wParam, LPARAM lParam);
static void notifyKeyDown(const UINT vkey, const bool altDown);
public:
static void addObserver(HookObserver *o);
static void removeObserver(HookObserver *o);
static int getKeyDownNumber();
static bool setHooks();
static bool removeHooks();
};
CPP file:
//---------------------------------------------------------------------------
#pragma hdrstop
#include "HookMaster.h"
#include <SysInit.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
HHOOK HookMaster::LLKeyHook = NULL;
HHOOK HookMaster::LLMouseHook = NULL;
int HookMaster::keyDownNumber = 0;
std::set<HookObserver*> HookMaster::observers;
LRESULT CALLBACK HookMaster::LLKeyHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
try {
if (nCode<0 || nCode==HC_NOREMOVE )
return CallNextHookEx(LLKeyHook, nCode, wParam, lParam);
KBDLLHOOKSTRUCT * pData = ( KBDLLHOOKSTRUCT *) lParam;
bool Down = (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN);
bool Alt=(pData->flags & LLKHF_ALTDOWN); // Alt is down
UINT vkey = pData->vkCode;
if (Down) {
if (GetKeyState(VK_CONTROL)>=0 ) {
notifyKeyDown(vkey, Alt);
}
}
} catch (...) {
}
return CallNextHookEx(LLKeyHook, nCode, wParam, lParam);
}
LRESULT CALLBACK HookMaster::LLMouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
try {
if (nCode==HC_ACTION) {
switch (wParam) {
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
notifyKeyDown(VK_RBUTTON, false);
break;
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
notifyKeyDown(VK_LBUTTON, false);
break;
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
notifyKeyDown(VK_MBUTTON, false);
break;
}
}
} catch (...) {
}
return CallNextHookEx(LLMouseHook, nCode, wParam, lParam);
}
void HookMaster::addObserver(HookObserver *o) {
observers.insert(o);
}
void HookMaster::removeObserver(HookObserver *o) {
observers.erase(o);
}
int HookMaster::getKeyDownNumber() {
return keyDownNumber;
}
bool HookMaster::setHooks() {
if (LLKeyHook == NULL) {
LLKeyHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)LLKeyHookProc, HInstance, 0);
}
if (LLMouseHook == NULL) {
LLMouseHook = SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)LLMouseHookProc, HInstance, 0);
}
return (LLKeyHook != NULL && LLMouseHook != NULL);
}
bool HookMaster::removeHooks() {
if (LLKeyHook != NULL) {
if (UnhookWindowsHookEx(LLKeyHook)) {
LLKeyHook = NULL;
}
}
if (LLMouseHook != NULL) {
if (UnhookWindowsHookEx(LLMouseHook)) {
LLMouseHook = NULL;
}
}
return (LLKeyHook == NULL && LLMouseHook == NULL);
}
void HookMaster::notifyKeyDown(const UINT vkey, const bool altDown) {
for (std::set<HookObserver*>::iterator i = observers.begin(); i != observers.end(); ++i) {
try {
HookObserver *obs = *i;
obs->keyDown(vkey, altDown, keyDownNumber);
} catch (...) {
// Something bad happened with the observer
}
}
++keyDownNumber;
}
Yes, it needs a little clean-up in sethooks, as it may return
false and leave a keyboard hook dangling if setting the mouse
hook fails...
A
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads