The latest MSDN & Windows SDK documentation has been corrected. The documentation for CallNextHookEx() now includes the following description for the hhk parameter: "[in] Windows 95/98/ME: Handle to the current hook. An application receives this handle as a result of a previous call to the SetWindowsHookEx function."
For years, Microsoft's Platform SDK documentation described the first parameter of CallNextHookEx as:
"hhk - Handle to the current hook. An application receives this handle as a result of a previous call to the SetWindowsHookEx function."
I don't recall exactly when the documentation was changed, but as of May 8th 2006, it reads:
"hhk - Ignored."
The way window hooks are supposed to work is that the program calls SetWindowsHookEx() to install a hook procedure to be called whenever a specific event occurs. When the event occurs, the hook procedure does its thing and then calls CallNextHookEx() to call the next hook procedure. The next hook procedure does its thing and calls CallNextHookEx(). This continues until all of the hook procedures in the chain have been called. When the program exits, or no longer cares about the event in question, it calls UnhookWindowsHookEx() to remove its hook procedure from the chain.
The initial call to SetWindowsHookEx() returns a hook handle (HHOOK) that is supposed to be supplied as the first parameter of CallNextHookEx(). In an ideal situation, this handle would also be supplied to the hook procedure as a parameter. As it stands, this is not the case. The hook handle is only made available to the program when the hook is initially installed.
If your program's hooking is limited to your own process, you can just store the HHOOK value in a global variable. If your program is installing a global or remote hook, however, process boundaries will prevent the hook procedure from being able to access global variables within your program's process. Obviously, this presents a problem.
Two different methods have been devised to deal with this situation. One, while being easy to implement, is criticized as being insecure and isn't very elegant. The other method involves adding a lot of extra code just to get one variable into one API function call.
So, the revelation by the recent Platform SDK documentation that CallNextHookEx() ignores the HHOOK parameter is great news! We can dispense with the added code of the secure solution and the insecurity and ickiness of the easy solution. Let's celebrate!
There's just one thing, though. For years, the documentation stated that the HHOOK parameter was required. As much as we would like to, we cannot simply brush that aside. So I set out to put this question to rest; to prove that the HHOOK parameter is ineed ignored by CallNextHookEx(). To do this, I wrote a simple test program.


The test program creates a window and installs two hook procedures. Whenever the window receives a WM_PAINT message, it sends a custom message to itself that contains the HDC the window is using to draw itself. When the hook procedures see the custom message, they draw on the HDC. One hook draws a blue rectangle, the other draws a red rectangle.
If both hooks are properly called, two rectangles will be drawn within the window. If something is wrong, it'll be easy to spot.
For ease of comparison, tapping the space bar will switch between calling CallNextHookEx() with the correct HHOOK value and a value of NULL.
I ran the test on Windows 95, 98, Me, NT4, 2000, XP and 2003. On NT platforms (NT4, 2000, XP, 2003), the documentation appears to be correct -- the HHOOK parameter seems to be ignored. On 9x platforms (95, 98, Me), the test tells a different story. When not passing the correct HHOOK to CallNextHookEx(), only one of the rectangles is drawn. These platforms require the correct HHOOK handle when calling CallNextHookEx() or the hook procedure chain will be broken.
The test program, including the source code is available for download (30 KB).