3

This is my C++ code:

#include <iostream>
#include <windows.h>

HHOOK hook;

LRESULT CALLBACK keyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    std::cout << "Hook callback" << std::endl;
    return CallNextHookEx(hook, nCode, wParam, lParam);
}

int main(int argc, char **argv)
{
    hook = SetWindowsHookEx(WH_KEYBOARD, keyboardHook, NULL, NULL);
    if (hook == NULL) {
        std::cout << "Error " << GetLastError() << std::endl;
        return 1;
    }
    std::cout << "Hook set" << std::endl;
}

I compile it using Visual Studio like this:

cl /D_WIN32_WINNT=0x0401 foo.cc /link user32.lib

When I run it, I get error 1428.

C:\>foo.exe
Error 1428

This is the meaning of error 1428.

C:\nocaps>net helpmsg 1428

Cannot set nonlocal hook without a module handle.

Could you please help me to understand this error and get this code working? It would be great if you could provide me a working code that works and invokes the callback?

I see that if I use WH_KEYBOARD_LL hook instead, it works fine. But I need to understand how WH_KEYBOARD hook can be made to work.

5
  • It says right in the documentation you need to put the hook procedure in a DLL, which is injected. Commented Jan 3, 2014 at 4:46
  • @chris If I understand it correctly, it means that my keyboardHook function cannot be in the same EXE as the main function because the keyboardHook function needs to be in a separate DLL. Have I understood it correctly? Commented Jan 3, 2014 at 4:58
  • Yes, because you're doing it globally, and the low level keyboard and mouse hooks are special. Anyway, it also says that NULL and 0 as the last two arguments to SetWindowsHookEx might result in an error. NULL is not the current module. GetModuleHandle(NULL) is. Commented Jan 3, 2014 at 5:04
  • @LoneLearner Do you need more help? Commented Jan 4, 2014 at 20:12
  • @manuell I am all set with this one. Thank you for your answer and detailed explanation. In fact, your answer helped me to understand another problem I was facing: stackoverflow.com/a/20911720/1175080 Commented Jan 5, 2014 at 7:00

1 Answer 1

6

WH_KEYBOARD_LL hooks are always run in the context of the thread that installed the hook. The hook function doesn't need to be in a DLL, and the hook may catch events from applications, irrespective of their bitness. The trick is: the OS does some sort of special "SendMessage" to your thread message queue. That is why you'll have to install an active message loop in your hooking thread.

WH_KEYBOARD hooks may be run in the context of the thread that installed the hook. That means that they also may be run in the context of the hooked threads. That imposes a hook function located in a DLL. I believe (but not sure about that) that the hook function will be executed "in place" (in the context of the hooked threads) if the bitness is the same, and that the fallback for a bitness mismatch relies on the same technique used for WH_KEYBOARD_LL. That means you also have to install an active message loop in your hooking thread (and if you don't, you'll miss all the events from applications with another bitness)

Note: a hook function being excecuted in the context of the hooked threads renders all cout << "Hello\n" useless. You'll have to use file(s) (or IPC).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.