Holy cow, I wrote a book!
The SetWindowsHookEx function accepts a HINSTANCE parameter. The documentation explains that it is a handle to the DLL containing the hook procedure. Why does the window manager need to have this handle?
SetWindowsHookEx
HINSTANCE
It needs the handle so it knows which DLL to load into each process when the hook fires. It injects the DLL you pass, then calls the function you pass. Clearly the function needs to reside in the DLL you pass in order for its code to be there when the window manager calls it.
This is also why hook functions must reside in DLLs. You can't load an EXE into another EXE.
The WH_KEYBOARD_LL and WH_MOUSE_LL hooks are exceptions to this rule. These two are non-injecting hooks, as explained in their respective documentation pages. Rather, the hook function is called in its original thread context.
WH_KEYBOARD_LL
WH_MOUSE_LL
Okay, armed with this information, perhaps you can solve this person's problem with global hooks.