Click here to Skip to main content
Click here to Skip to main content

Using Hooks from C#

, 30 Dec 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
An article on using Windows hooks from .NET, demonstrated with a MouseHook.


MSDN's definition of a Windows hook is:

A hook is a point in the system message-handling mechanism where an application can install a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure.

While the .NET framework library has wrapped a significant portion of the Win32 API, there are numerous areas where we have to resort to P/Invoke to get at the functionality we need. Hooks are one of those areas. One likely reason for this is that hooks are pretty low-level things which most programs rarely need. Another is that they are intimately tied to the message based nature of the Windows API itself. They would likely not be portable to any other Operating System.

Windows hooks are implemented using callback functions. The callback procedure has a signature similar to the SendMessage API, so Windows hooks are very generic and are used to extend a number of different types of Windows message processing methods (see below). This library provides a C# wrapper around the hook procedure that can be used from a Windows Forms application.

A MouseHook is a particular type of Windows hook that allows your code to be notified when any window on a particular thread gets a mouse message. This example uses a mouse hook to capture the button up messages for the two navigation buttons on 5-button mice. By using a mouse hook, the application's main Form can control navigation via the mouse, regardless of what child control currently has input focus. If you don't have a 5-button mouse, the demo isn't going to be very exciting for you, but the code demonstrates the basic concepts.


Last summer, there was an interesting article, by Dino Esposito, in the MSDN magazine, about implementing hooks in C#. "Hmmm", I thought to myself, "That's interesting, but why in the world would you ever want to do that?"

Well, the application I'm currently working on uses a web browser-like "forward/back" idiom, wherein the user can navigate between views, much like they would a series of web pages. Each view is a UserControl that gets loaded dynamically as the user moves around the application.

I, for one, can no longer live without the forward and back buttons on my five button mouse, so I thought I'd add mouse navigation to our app.

I quickly realized that this was not as simple as it first appeared. Because each view UserControl takes up the entire client area of the Form it is hosted on, the Form itself never gets any MouseUp events. I didn't want to deal with this in each and every view I'd create, so I had to come up with a way to handle the mouse button navigation in one place.

My first idea was to attach to each view's MouseUp event in the Form and do the navigation from there. This quickly proved itself to be a kludge as each UserControl has its own child controls, and when they have focus, the UserControl doesn't get any mouse events either. To work, one would need to recursively attach all child control events to the same handler. Sounds messy, so scratch idea #1.

The next thought was to use the WM_PARENTNOTIFY message in the Form's WndProc. This looked promising at first and I had a proof of concept all whipped in no time. Then, I thought to myself, "The only mouse messages that spawns WM_PARENTNOTIFY are mouse down messages. I wonder when exactly a web browser navigates".

A quick test proved that web browsers navigate on mouse up, not mouse down (as, upon further reflection, one would expect). Scratch idea #2.

That led me to the implementation I was hoping I wouldn't have to delve into: a MouseHook. I recalled implementing these in VB6 (in what seems like the dark ages now) and the havoc that they could wreck upon the VB6 IDE. Well, it seemed like the only solution, so a quick Google search led me back to Dino's article, and after a quick look at the code, it began to appear that it wouldn't be as bad as I had feared.

Windows hooks are thread specific, and this implementation uses the thread of the code that calls the Install method, which if you call it synchronously from a Form, will be the main UI thread. This is perfect for my navigation problem because, now I can have code in the Form that will respond to a forward/back mouse click, no matter what control has focus.

The code download includes and uses the LocalWindowHook class which Dino Esposito used to demonstrate the basics of Windows hooks in the MSDN sample code.

Using the code

There are two classes you can use to get at the MouseHook.

The first is a class, MouseHook, that inherits directly from LocalWindowHook. Instantiate it, attach to its events, call Install(), and away you go. It will remove the hook when you Dispose it or when its finalizer runs.

private MouseHook hook = new MouseHook();

private void HookUp()
    this.hook.MouseUp += new MouseHookEventHandler( this.hook_MouseUp );

private void hook_MouseUp(object sender, MouseHookEventArgs e)
    // do some stuff with your exciting new mouse hook data

The second class is a System.ComponentModel.Component derived type that can be placed onto a design surface. In addition to making the MouseHook easier to use from the VS.NET IDE, the MouseHookComponent automatically installs the hook from the constructor that the Windows Forms Designer uses.

That means, all you really need to do is drop it on a Form and attach to the events you are interested in.

Future enhancements

The are a number of different types of hooks supported by the Windows API. Dino Esposito's LocalWindowsHook class is completely generic, and can be used to create any one of those hook types:

public enum HookType : int
    WH_KEYBOARD = 2,
    WH_CBT = 5,
    WH_MOUSE = 7,
    WH_HARDWARE = 8,
    WH_DEBUG = 9,
    WH_SHELL = 10,
    WH_KEYBOARD_LL = 13,
    WH_MOUSE_LL = 14

The MouseHook class I've created here is just one example of a derived class that abstracts the complexity of a particular kind of Windows hook. I've also included the CbtLocalHook class from the MSDN sample code.



  • 09/19/2003 - Initial release.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Don Kackman
Team Leader Starkey Laboratories
United States United States
The first computer program I ever wrote was in BASIC on a TRS-80 Model I and it looked something like:
10 PRINT "Don is cool"
20 GOTO 10
It only went downhill from there.

Hey look, I've got a blog
Follow on   Twitter

Comments and Discussions

GeneralMy vote of 4 PinmemberSivaji156527-Sep-13 0:51 
Questiongood article PinmemberCIDev7-Nov-12 5:39 
GeneralMy vote of 5 Pinmemberluoly1218-Aug-12 17:40 
QuestionCan't run in VS2010 Pinmemberhambor29-Aug-11 4:16 
AnswerRe: Can't run in VS2010 Pinmemberwooohaa26-Jun-12 4:03 
QuestionGlobal CBTHook? PinmemberZiggy98118-Aug-10 22:13 
GeneralCool - If you like Hooks PinmemberMarkJoel6021-Jan-10 5:57 
Generalin vb. Pinmemberrdpeake11-Jan-10 7:07 
GeneralRe: in vb. PinmemberDon Kackman18-Jan-10 17:28 
GeneralRe: in vb. Pinmemberrdpeake19-Jan-10 3:10 
GeneralRe: in vb. [modified] PinmemberDon Kackman20-Jan-10 4:54 
GeneralRe: in vb. Pinmemberrdpeake20-Jan-10 14:52 
GeneralWPF Pinmemberdarrellp1-Jan-10 6:36 
I know you're using Windows Forms here and I'm not suggesting a complete change in architecture to fix this, but just FYI, if you'd been working in WPF the event bubbling there would have handled this automagically. Your top level user controls would have gotten the event and if they allowed it to pass through it would have bubbled up to the main window where you could have handled it without the hooks. Glad you wrote up the article on hooks generally, regardless.
GeneralRe: WPF PinmemberDon Kackman2-Jan-10 9:36 
GeneralRe: WPF Pinmemberdarrellp2-Jan-10 11:16 
GeneralRe: WPF PinmemberDon Kackman2-Jan-10 15:27 
GeneralI didn't know it! Pinmemberyyhotspring30-Dec-09 18:41 
GeneralAbove link is SPAM Pinmemberspoodygoon31-Dec-09 8:13 
QuestionIs this a joke? PinmemberMember 14391572-Dec-09 3:52 
AnswerRe: Is this a joke? PinmemberDon Kackman2-Dec-09 5:05 
GeneralHook ReadFile Pinmemberwei_future5-Jun-08 22:04 
Questionc# DoModal in handler doesn't return?!? Pinmemberjfstephe1-Nov-07 9:20 
GeneralVB.Net Pinmemberwestville_mike17-Oct-07 5:27 
QuestionCancel events? PinmemberJohnny J.23-Aug-07 23:40 
QuestionHook on Insert Smart Card into Smart Card Reader PinmemberIdeazzkds17-Dec-06 21:21 
QuestionHook for copy, cut, paste, delete PinmemberIoBebe26-Nov-06 8:33 
QuestionVisual Studio 2005 - AppDomain.GetCurrentThreadId PinmemberGBerrySqueeze30-May-06 12:38 
AnswerRe: Visual Studio 2005 - AppDomain.GetCurrentThreadId Pinmember_iTcHy_25-Mar-09 1:03 
QuestionkEYBOARD HOOKERS - Local Hooks in C# PinmemberAnnie Fernando2-Apr-06 22:01 
AnswerRe: kEYBOARD HOOKERS - Local Hooks in C# Pinmemberwarrior bard11-Mar-07 21:20 
GeneralBack Forward Button Pinmembermjorg26-Feb-06 7:42 
QuestionLocalWindowsHook Code analysis PinmemberRuth Ivimey-Cook19-Jan-06 14:21 
AnswerRe: LocalWindowsHook Code analysis PinmemberGBerrySqueeze30-May-06 12:07 
GeneralRe: LocalWindowsHook Code analysis [modified] PinmemberRuth Ivimey-Cook30-May-06 23:16 
GeneralHooking API - OpenProcess PinmemberVitoto2-Jan-06 17:47 
GeneralHook on Minimize PinmemberThomasManz13-Nov-05 3:38 
GeneralRe: Hook on Minimize PinmemberRadu Sebastian LAZIN2-May-06 4:09 
GeneralPrevent target form from receiving messages Pinmemberbanal15-Sep-05 12:22 
GeneralSingle Form Mouse Move PinmemberMBursill14-Aug-05 16:31 
GeneralRe: Single Form Mouse Move PinmemberDon Kackman6-Sep-05 15:11 
GeneralRe: Single Form Mouse Move PinmemberMBursill24-Sep-05 9:01 
GeneralRe: Single Form Mouse Move PinmemberDon Kackman24-Sep-05 9:48 
QuestionHow can I handle mouse click? PinsussAnonymous22-Jul-05 1:38 
Generalchanging mouse events Pinmemberveligeti28-Jun-05 8:54 
GeneralWH_JOURNALRECORD and WH_JOURNALPLAYBACK PinmemberDigital Logic Net7-Sep-04 22:18 
GeneralRe: WH_JOURNALRECORD and WH_JOURNALPLAYBACK PinmemberMerrion5-Oct-04 0:26 
GeneralRe: WH_JOURNALRECORD and WH_JOURNALPLAYBACK Pinmemberfala707-Oct-06 1:33 
GeneralRe: WH_JOURNALRECORD and WH_JOURNALPLAYBACK PinmemberKenneth Chan19-May-07 15:18 
GeneralRebroadcasting Keyboard Events PinmemberRapidFireBill12-Aug-04 11:20 
QuestionA solution to .NET global hooks? PinsussAnonymous13-Feb-04 19:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150414.1 | Last Updated 30 Dec 2009
Article Copyright 2003 by Don Kackman
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid