Hooking in Microsoft .NET






3.81/5 (10 votes)
Jun 27, 2007
3 min read

55111

1309
An article discussing hook implementation in .NET
Win32 hooks: a refresher
The Win32 hook is a mechanism by which user-defined functions can be intercepted before an event reaches the target application. Hooks decreases system performance due to the additional processing required for each message. So, they should be installed only when necessary and uninstalled as soon as possible.
Microsoft Windows supports many types of hooks, like WH_KEYBOARD
, which can be used for hooking the keyboard. Each type of hook provides access to different types of messages. The system maintains a data structure called a hook chain for each type of hook. This chain is a list of pointers to functions called hook procedures. Some types of hooks can only monitor messages; others can modify messages or stop their progress through the chain, preventing them from reaching the next hook procedure or the destination window.
The prototype of the hook procedure varies a bit according to the type of message it is expected to catch. Applications install hooks using the SetWindowsHookEx
API and UnhookWindowsHookEx
is used for uninstalling the same.
HHOOK SetWindowsHookEx (int idHook,
HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);
The first parameter above specifies the hook ID, e.g. WH_KEYBOARD
for hooking the keyboard, WH_MOUSE
for hooking the mouse. The second parameter is the hook procedure that will be called when the particular message gets fired. The third parameter is the instance/module handle where the hook procedure is defined. The last parameter specifies the window thread to be hooked. This can be retrieved using the API GetWindowThreadProcessId
for passing the window handle. If this parameter is empty, then this will install a system hook. For more information, refer to this MSDN article.
Global hooks are not supported in .NET. This behavior requires a DLL export and .NET Framework does not support DLL exports.
Hooks in .NET
There is no built-in support for hooks in Microsoft .NET; P/Invoke
is used to handle such things. P/Invoke
is a method of calling unmanaged APIs. In .NET, the smallest units of processing are Application Domains -- called AppDomains for short -- whereas in Win32, the smallest unit of processing is a process. So, we make use of the SetWindowsHookEx
API through the P/Invoke
method to install hooks and we use UnhookWindowsHookEx
for uninstalling the hooks.
How the code works
The sample application with this article contains a class called Win32Hook
that is a simple wrapper for handling the hook. The function InstallHook
installs a WH_GETMESSAGE
type hook.
public bool InstallHook()
This function returns true
if the hook is installed successfully. Next, the function...
public bool UninstallHook ()
...uninstalls the hook. Don't forget to call this after you have done with it.
m_oHookManager.HookInvoked+=
new Win32Hook.HookEventHandler(m_oHookManager_OnHookMessage);
Here, the method m_oHookManager_OnHookMessage
will be called whenever an event is fired on the target window. The function prototype is:
void m_oHookManager_OnHookMessage (object sender, HookEventArgs hea)
The class HookEventArgs
is defined in the same file and contains all of the messages related to a message, such as the identifier, whether it is going to be removed from the queue (PM_REMOVE
or PM_NOREMOVE
), etc.
[DllImport ("user32.dll")]
private static extern IntPtr SetWindowsHookEx(HookId hookId, HProc hookProc,
IntPtr hInstance, Int32 threadId);
[DllImport ("user32.dll")]
private static extern Int32 UnhookWindowsHookEx(IntPtr hHook);
[DllImport ("user32.dll")]
private static extern Int32 CallNextHookEx(IntPtr hHook, Int32 nCode,
IntPtr wParam, IntPtr lParam);
The DllImport
attribute specifies the DLL where the function is defined. This attribute is defined in System.Runtime.InteropServices
. For more information, refer to this MSDN article. It might take a long time to implement hooks in Microsoft .NET due to the architectural changes introduced in the native to managed code transition.
History
- 27 June, 2007 -- Original version posted