For educational purposes/fun I’ve been messing around with some Windows work. I’m working with hooks (a keyboard hook to be specific), and I want it to work on a global level. According to this MSDN article the hook procedure has to be in a seperate dll. I’ve done this, and then called SetWindowsHookEx() as instructed here. idHook is set to WH_KEYBOARD, lpfn is set to the pointer to the hook procedure (loaded from the dll using LoadLibrary() and GetProcAddress() ), hMod is the handle to the dll, and dwThreadId is set to 0 (as is required to make the hook global according to the site). However, when I run it (and I’ve confirmed this using breakpoints), the hook only catches keyboard messages to the window that launched it. It works only on the thread level, and not globally. Any help would be greatly appreciated, as I don’t know where I’ve went wrong. Everything else works perfectly. Attached is the code.
keyhook_dll.c (901 Bytes)
main.cpp (5.17 KB)
keyhook_dll.c (901 Bytes)
main.cpp (5.17 KB)
It’s been a couple years since I’ve even looked at Win32 code, so I’m not sure how much help I can be, but…
Any reason why you are torturing yourself and not using .NET? Or at least MFC?
I started in .NET and did a lot with it back in the day. I did some freeware apps online and a lot of people complained about the .NET framework. I wanted to learn native a) for the fun of it, and b) so I could build faster programs.
I’ve only done a little with low level hooks, and mostly in C# (see attached). The most blatant thing I noticed when comparing my code to yours is I’m using WH_KEYBOARD_LL and you’re using WH_KEYBOARD. Does the behavior change if you use WH_KEYBOARD_LL? (I assume you’re not using Win95 or something so you might as well use WH_KEYBOARD_LL)
–Ryan
globalKeyboardHook.cs.txt (6.99 KB)
globalKeyboardHook.cs.txt (6.99 KB)
I’m running Vista. Anyways, WH_KEYBOARD_LL apparently catches messages when “a new keyboard input event is about to be posted into a thread input queue” and WH_KEYBOARD catches messages “whenever an application calls the GetMessage or PeekMessage function and there is a keyboard message (WM_KEYUP or WM_KEYDOWN) to be processed”. For my purposes, I thought WH_KEYBOARD would be fine. And according to the MSDN explanation of SetWindowsHookEx(), WH_KEYBOARD should be able to run globally.
EDIT: Using WH_KEYBOARD_LL, the hook works globally. However I cannot do what I wanted to (which is change the keystroke en-route to programs). WH_KEYBOARD_LL passes a pointer to a struct containing they key data (such as key code, etc.) as it’s lParam, but i have found that changing the data in the struct does not affect the output (even If I change the keycode the key remains the same). Can’t I change the data in the message using the hook?
You should be able to do this by modifying the vkCode in the lParam struct before calling CallNextHookEx. This function passes on the key on to the next handler in the hook chain, so passing a modified lParam will mean that all handlers that were registered before your (including the default windows handler) will see the modified value. At least that’s how it works in theory.
Let me know if that works.
–Ryan
P.S. I’m not sure why WH_KEYBOARD_LL works and WH_KEYBOARD doesn’t. I think I remember running into the same issue with mine. Maybe posting to the MSDN forums would shed a bit more light on the subject.
This was the first thing I tried (with no success). However with the help of some other forums, I have a working solution. After detecting a desired input, I use SendInput() combined with INPUT structures to send my desired inputs. I then return a negative value instead of passing the message along the hook chain. The only thing is that I had to come up with a way so the same inputs being sent using SendInput() weren’t processed by the hook, creating a recursive loop. I did this by setting a flag in the extra info of the input, and neglecting any input that came into the hook using that flag.