views:

446

answers:

5

Global Windows hooks must be in a DLL because the hook is going to be called in the context of a different process, so the hook procedure's code must be injected into that process. However, there are limitations:

SetWindowsHookEx can be used to inject a DLL into another process. A 32-bit DLL cannot be injected into a 64-bit process, and a 64-bit DLL cannot be injected into a 32-bit process. If an application requires the use of hooks in other processes, it is required that a 32-bit application call SetWindowsHookEx to inject a 32-bit DLL into 32-bit processes, and a 64-bit application call SetWindowsHookEx to inject a 64-bit DLL into 64-bit processes. The 32-bit and 64-bit DLLs must have different names.

For this reason, I'd rather use the low-level hooks WH_MOUSE_LL and WH_KEYBOARD_LL, instead of WH_MOUSE and WH_KEYBOARD. As seen from their documentation:

This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.

This leads me to think that these particular hook procedures do not need to be in a separate DLL, and can just live inside the EXE that hooked them up. The documentation for SetWindowsHookEx, however, says:

lpfn

[in] Pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a DLL.

No explicit exception for the two low-level hooks is mentioned.

I have seen several .NET applications that use the low-level hooks without having their hook procedures in a separate DLL. That is another hint that this is acceptable. However, I'm a bit scared to do this myself since the documentation forbids it.

Does anyone foresee any trouble if I don't use a DLL and just put these low-level hook procedures straight into my EXE?

Edit: For the bounty, I would like a definitive "yes, this is ok, because..." or "no, this can go wrong, because...".

+1  A: 

Global hooks, whether low or high level, have to be in a separate DLL that can be loaded into each process. The documentation you quoted makes that pretty clear, and if there was an exception that applied to the low-level hooks, that documentation would say so as well.

Ken White
I think you should read the question more carefully. If this is indeed a requirement, how do .NET applications use the low-level hooks successfully?
Thomas
The question related to global hooks, AFAICT. "Having a message loop" doesn't mean it can't be a DLL that implements it; I've done several DLLs that created a message loop for various reasons. I have no idea whether or not .NET apps can or do use the low-level hooks, as I've never seen or heard of one that does. I'd guess, though, that if they can and do they are using unsafe code in a DLL to do so, but as I say I'd be guessing. :-)
Ken White
+1  A: 

There is one exception to the global hooking function in dll rule. Mouse and keyboard hooks are executed in the context of the calling process, not the process being hooked. Therefore the hook code is not executed in an arbitrary process and can be written in .Net. See http://www.codeproject.com/KB/cs/CSLLKeyboardHook.aspx for an example.

You do need to call the 32 bit version of SetWindowsHookEx and pass a hook function in a 32bit process and call the 64bit version of SetWindowsHookEx and pass a hook function in a 64bit process, though.

Sheng Jiang 蒋晟
A: 

Rule of thumb: When the docs say not to do something, there's usually a pretty good reason for it. While it may work in some cases, that fact that it works may be an implementation detail, and subject to change. If that happens, then your code will be broken if the implementation is ever modified.

Billy ONeal
A: 

Edit: I take back my previous answer. It turns out that WH_MOUSE_LL and WH_KEYBOARD_LL are exceptions to the usual rule about global hooks:

What is the HINSTANCE passed to SetWindowsHookEx used for?

Peter Ruderman
A: 

Turns out that this is actually in the documentation. Although not in the documentation of SetWindowsHookEx and friends, but in a .NET knowledge base article.

Low-level hook procedures are called on the thread that installed the hook. Low-level hooks do not require that the hook procedure be implemented in a DLL.

Thomas