3

How can I access to the handle of a hook from his procedure ?

Example :

HHOOK hook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)hookProc, GetModuleHandle(NULL), 0);

LRESULT CALLBACK hookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    //I want my HHOOK here :O
}
Triton
  • 93
  • 6
  • Take a look here: http://stackoverflow.com/questions/214022/how-to-correctly-use-setwindowshookex-callnexthookex – Asaf Feb 11 '12 at 23:21

2 Answers2

3

You need to store the HHOOK variable in global memory. Don't declare it as a local variable of whatever function is calling SetWindowsHookEx().

Edit: Here is a class-based example for 32-bit CPUs:

class THookKeyboardLL
{
private:
    HHOOK hHook;

    void *pProxy;
    static LRESULT CALLBACK ProxyStub(THookKeyboardLL *This, int nCode, WPARAM wParam, LPARAM lParam);

    LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);

public:
    THookKeyboardLL();
    ~THookKeyboardLL();
};

.

#include <pshpack1.h>
struct sProxy
{
    unsigned char PopEax;
    unsigned char Push;
    void *ThisPtr;
    unsigned char PushEax;
    unsigned char Jmp;
    int JmpOffset;
};
#include <poppack.h>

long CalcJmpOffset(void *Src, void *Dest)
{
    return reinterpret_cast<long>(Dest) - (reinterpret_cast<long>(Src) + 5);
}

LRESULT CALLBACK THookKeyboardLL::ProxyStub(THookKeyboardLL *This, int nCode, WPARAM wParam, LPARAM lParam)
{
    return This->HookProc(nCode, wParam, lParam);
}

THookKeyboardLL::THookKeyboardLL()
    : hHook(NULL), pProxy(NULL)
{
    sProxy *Proxy = (sProxy*) VirtualAlloc(NULL, sizeof(sProxy), MEM_COMMIT, PAGE_READWRITE);

    Proxy->PopEax = 0x58;
    Proxy->Push = 0x68;
    Proxy->ThisPtr = this;
    Proxy->PushEax = 0x50;
    Proxy->Jmp = 0xE9;
    Proxy->JmpOffset = CalcJmpOffset(&(Proxy->Jmp), &ProxyStub);

    // Note: it is possible, but not in a portable manner, to
    // get the memory address of THookKeyboardLL::HookProc()
    // directly in some compilers.  If you can get that address,
    // then you can pass it to CalcJmpOffset() above and eliminate
    // THookKeyboardLL::ProxyStub() completely. The important
    // piece is that the Proxy code above injects this class
    // instance's "this" pointer into the call stack before
    // calling THookKeyboardLL::HookProc()...

    DWORD dwOldProtect;
    VirtualProtect(Proxy, sizeof(sProxy), PAGE_EXECUTE, &dwOldProtect);
    FlushInstructionCache(GetCurrentProcess(), Proxy, sizeof(sProxy));

    pProxy = Proxy;
    hHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)pProxy, GetModuleHandle(NULL), 0);
}

THookKeyboardLL::~THookKeyboardLL()
{
    if (hHook != NULL)
        UnhookWindowsHookEx(hHook);

    if (pProxy)
        VirtualFree(pProxy, 0, MEM_RELEASE);
}

LRESULT CALLBACK THookKeyboardLL::HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    // ...

    return CallNextHookEx(hHook, nCode, wParam, lParam);
    // when this method exits, it will automatically jump
    // back to the code that originally called the Proxy.
    // The Proxy massaged the call stack to ensure that...
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • But I want make a class which create a hook, so I can't use a global variable because I must be able to create several objects. – Triton Feb 11 '12 at 23:14
  • 1
    `SetWindowsHookEx()` does not support the use of classes. If you want to use a class method as the hook procedure, and use multiple class instances to set up multiple hooks, then you have to create a separate proxy thunk for each class instance, pass the proxy to `SetWindowsHookEx()`, and the proxy calls into its associated class instance as needed. You cannot do that in straight C/C++ by itself, you have to write the proxy in assembly (at least the portion that `SetWindowsHookEx()` calls into anyway). – Remy Lebeau Feb 11 '12 at 23:30
  • It is not too difficult (at least in 32bit, I don't know about 64bit), I will update my answer later with an example. – Remy Lebeau Feb 11 '12 at 23:31
1

If you look at the documentation for CallNextHookEx you see that the HHOOK parameter is optional on Windows NT, if you need to support Windows 9x then you need to store the HHOOK in a global variable.

Your example code shows that you are creating a global hook, global hooks are expensive so if you want to register more than one callback function you should abstract this so that your application only sets one hook and the callback function you register there calls your real functions (in a linked list etc).

Anders
  • 97,548
  • 12
  • 110
  • 164