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?
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
This is also why hook functions must reside in DLLs.
You can't load an EXE into another EXE.
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.
Okay, armed with this information, perhaps you can solve
this person's problem with global hooks.