The following code register a low level mouse hook to monitor mouse events globally.
It's the simplest working example I can get.
Compiled with VC++ 2010: cl test.cpp /link /entry:mainCRTStartup /subsystem:windows
#include <windows.h>
HWND label1 ;
//THE HOOK PROCEDURE
LRESULT CALLBACK mouseHookProc(int aCode, WPARAM wParam, LPARAM lParam){
static int msgCount = 0 ;
static char str[20] ;
SetWindowText( label1, itoa(++msgCount, str, 10) ) ;
return CallNextHookEx(NULL, aCode, wParam, lParam) ;
}
int main(){
/**/// STANDARD WINDOW CREATION PART //////////////////////////////////////////////////////
/**/
/**/ WNDCLASSEX classStruct = { sizeof(WNDCLASSEX), 0, DefWindowProc, 0, 0, GetModuleHandle(NULL), NULL,
/**/ LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_BTNFACE+1), NULL, "winClass", NULL } ;
/**/ RegisterClassEx(&classStruct) ;
/**/
/**/ HWND mainWin = CreateWindow("winClass", "", 0, 200,200, 100,100, NULL, NULL, NULL, NULL) ;
/**/ ShowWindow(mainWin, SW_SHOWDEFAULT) ;
/**/
/**/ label1 = CreateWindow("static", "0", WS_CHILD, 5,5, 80,20, mainWin, NULL, NULL, NULL) ;
/**/ ShowWindow(label1, SW_SHOWNOACTIVATE) ;
/**/
/**/// END OF WINDOW CREATION PART ////////////////////////////////////////////////////////
//HOOK INSTALATION
HHOOK hookProc = SetWindowsHookEx(WH_MOUSE_LL, mouseHookProc, GetModuleHandle(NULL), 0) ;
//MESSAGE LOOP
MSG msg ;
while( GetMessage(&msg, NULL, 0, 0) ){
TranslateMessage(&msg) ;
DispatchMessage(&msg) ;
}
UnhookWindowsHookEx(hookProc) ;
}
It's the basic one thread, one window, one message pump example. Except for the mouse hook.
My doubt is that what this code is doing contradicts two things I've read over and over in SO, MSDN, forums, blogs, etc..
Global hook procedures must reside in a DLL
MSDN documentation forSetWindowsHookEx
confirms this by saying:If the dwThreadId parameter is zero, the lpfn parameter MUST point to a hook procedure in a DLL
A GUI thread (one with a message pump) can't be interrupted because
GetMessase
's waiting state is not alertable. Which means that whenGetMessage
blocks in wait for more messages, it cannot receive a signal that interrupts its wait state.
However, there's no DLL anywhere to be seen here, and also the hook procedure must be interrupting the thread, otherwise the program wouldn't work, and it does (I'm assuming there's only one thread in this program).
So either I've completely misinterpreted these two points or this code is working in a way that doesn't match the asynchronous procedure call approach that I was expecting.
Either way, I'm cluless as to what is happening here.
Could you please explain how this code works.
Is it a single-thread program?
Is the hook procedure interrupting the thread?
Are any of the two points above actually true?