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

Global Windows Hooks

By , 24 Sep 2010
 

Introduction

The WindowsHookLib is a single library to hook the mouse, keyboard and the clipboard system wide. WindowsHookLib library has been rewritten in C# and therefore it uses Common Language Runtime (CLR). This means that the library can be referenced from various projects in .NET. The mouse and keyboard hooks are low level so you can use the Handled property of the MouseEventArgs or the KeyboardEventArgs to prevent the windows messages being passed to the other applications. Note you need to use the DLL file, not the classes in your projects; otherwise they might not work correctly.

  • Clipboard hook
  • Keyboard hook
  • Mouse hook

This component differs from what I have seen in other similar articles, by providing two more things:

  1. Preventing a message to be passed to other windows
  2. Raising the MouseClick and MouseDoubleClick events (I have never seen implementation of this in other low level hooks!)

Mouse Hook

The MouseHook class of the 'WindowsHookLib' library is designed to hook the mouse globally and raise some useful events. Since this hook is low level and low level mouse hooks don't get the MouseClick and MouseDoubleClick messages, it simulates these events. In order to use these events, the class object variable should be declared with the WithEvents keyword.

The MouseDown, MouseUp, MouseWheel, and MouseMove event handlers have a WindowsHookLib.MouseEventArgs class object which provides all the relevant information about the mouse as does the System.Windows.Forms.MouseEventArgs, and two additional properties, Handled and Control. You can set the Handled property to True to prevent the message from being passed to the other windows. The Control property provides the handle of the control under the mouse pointer. If you decide to set the Handled property in the MouseUp event, then it is recommended to set it in the MouseDown event as well for application performance. Conversely, if you decide to set the Handled property in the MouseDown event, then it is recommended to set it in the MouseUp event.

Note: If you set the Handled property in the mentioned events unconditionally, then you might not be able to use the mouse. To condition (block the mouse message to be passed to other windows or controls), you should compare the Control property's value against allowed control handle(s). If the allowed controls' handle list doesn't contain the Control property value, then you can set the Handled property to True; otherwise, don't set it. You can check the demo project's examples to see how you can condition the mouse handled process.

Note: Before you exit your application, you must call the hook object's Dispose method to uninstall the hook and free the class variables.

Keyboard Hook

The KeyboardHook class of the 'WindowsHookLib' library can be used to hook the keyboard globally. The class provides three events whose KeyDown and KeyUp event handlers contain a WindowsHookLib.KeyEventArgs object that has all the relevant information about the key as the System.Windows.Forms.KeyEventArgs. As with the mouse hook, you can set the Handled property to True in the KeyDown and KeyUp event handlers to prevent the message from being passed to other windows.

Clipboard Hook

The ClipboardHook class of the 'WindowsHookLib' library can be used to hook a window to the clipboard chain. The class provides two events, ClipbordChanged and StateChanged. The ClipboardChanged event handler contains a WindowsHookLib.ClipboardEventArgs object that has all the relevant information about the event.

Using the Code

Note: You need to use the DLL file by referencing it in your project, not the classes; otherwise, they might not work correctly. If you need the method descriptions, then you need to copy the 'WindowsHookLib.xml' file into your project folder.

Imports WindowsHookLib

'Class level declarations
Dim WithEvents kHook As New KeyboardHook
Dim WithEvents mHook As New MouseHook
Dim WithEvents cHook As New ClipboardHook

'Allowed control handle list
Dim alowedList As New List(Of IntPtr)

Try
    'Install the hooks
    kHook.InstallHook()
    mHook.InstallHook()
    cHook.InstallHook(Me) 'takes a window as its parameter.
Catch ex As Exception
    Console.WriteLine(ex.Message)
End Try

Try
    'Remove the hooks
    kHook.RemoveHook()
    mHook.RemoveHook()
    cHook.RemoveHook()
Catch ex As Exception
    Console.WriteLine(ex.Message)
End Try

Private Sub kHook_KeyDown( _
  ByVal sender As Object, _
  ByVal e As WindowsHookLib.KeyEventArgs) Handles kHook.KeyDown
    'Block Alt+PrintScreen key combination
    e.Handled = (e.Modifiers = Keys.Alt AndAlso _
                 e.KeyCode = Keys.PrintScreen)
End Sub

Private Sub mHook_MouseDown( _
  ByVal sender As Object, _
  ByVal e As WindowsHookLib.MouseEventArgs) Handles mHook.MouseDown
    'Set the Handled property for the mouse down event
    'to block the mouse down message for the 
    'controls that are not in the alowedList.
    e.Handled = Not Me.alowedList.Contains(Ctype(sender,IntPtr))
    'Do some other things here
    '...
    '...
End Sub

Private Sub mHook_MouseUp( _
  ByVal sender As Object, _
  ByVal e As WindowsHookLib.MouseEventArgs) Handles mHook.MouseUp
    'Set the Handled property for the mouse up event
    'to block the mouse up message for the 
    'controls that are not in the alowedList.
    e.Handled = Not Me.alowedList.Contains(Ctype(sender,IntPtr))
    'Do some other things here
    '...
    '...
End Sub

Private Sub cHook_ClipboardChanged( _
  ByVal sender As Object, _
  ByVal e As WindowsHookLib.ClipboardEventArgs) _
  Handles cHook.ClipboardChanged
    'The clipboard content is changed, do something about it.
    '...
    '...
End Sub

For more examples, check out the source code and demo files.

Background

In the core of this component lies the API methods. All hooks use some API methods to hook and monitor for Windows messages. The following list is the API methods that have been used:

  • SetWindowsHookEx
  • UnhookWindowsHookEx
  • CallNextHookEx
  • WindowFromPoint
  • SendInput
  • SetClipboardViewer
  • ChangeClipboardChain

Points of Interest

I learned many things from this project like how to make a DLL file component that can be used in various projects (VB.NET, C#, C++, J#) in the .NET environment. Also, how to apply attributes to classes or methods that will make a component professional.

Since low level mouse hooks don't get the MouseClick and MouseDoubleClick event messages (which I believe are generated by a window that gets the MouseDown and MouseUp messages), I tried to simulate these events such that they are generated in the same pattern as the Windows MouseClick and MouseDoubleClick events.

WindowsHookLib Information

  • Author: Arman Ghazanchyan
  • Current assembly version: 1.1.1.2
  • Current file version: 1.0.0.6
  • WindowsHookLib webpage

History

  • Updated assembly version 1.1.0.1. This update addresses all hooks.
    • The WindowsHookLib assembly is signed.
    • A clipboard hook is added - New
  • Updated assembly version 1.1.0.2. This update addresses the Keyboard hook.
    • Small change in the KeyEventArgs class
  • Updated assembly version 1.1.0.5. This update addresses to all hooks.
    • Small changes and fixes
  • Updated assembly version 1.1.1.0. This update addresses to all hooks.
    • Some changes and fixes
  • Updated assembly version 1.1.1.2. This update addresses to all hooks, the update is highly recommended.
    • The library is rewritten in C# language.
    • There are many fixes and optimizations to the library.
    • Clipboard Hook bug fix. The hook was not implementing correctly in the previous versions which would lead to breaking up the windows clipboard chain. This version fixes the problem.
    • This version of the library is smaller in size than the previous versions.

License

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

About the Author

VBDT
Software Developer (Senior)
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: Strange problemmemberVBDT10 Jan '08 - 19:48 
Hi Gooberstain,
Thanks for reporting the double-click problem. The problem was due to a small bug. In the remove method it was setting the double-click rectangle to empty rectangle which shouldn’t. The rectangle determines the system double click area and it is set ones when the object is created. As it was sett to an empty rectangle in the remove hook method it was not sett with the values in the install hook method.
 
Anyways the problem is fixed Smile | :)
Best regards,
Arman G.
GeneralBrilliant!memberMagicPantsMan30 Oct '07 - 17:59 
Excellent work, thank you!
Your library works out of the box perfectly.
I also like the way you have exposed the API, its very clean and intuitive.
Great work!
QuestionIs this possible?File Path retrivalmembermohandilli12 Oct '07 - 18:39 
hi all,
This project is really rocking.Actually i need a solution for the problem berfied below
When a file is clicked whether its possible to retrive the path of the selected file and write it to a log file.
GeneralRe: Is this possible?File Path retrivalmemberThe_Mega_ZZTer14 Mar '08 - 18:16 
If you want to log the files clicked in Windows Explorer, this library does not give you the appropriate tools. It would be like trying to start a car with a crowbar.
 
The scripting program AutoIt is better suited for this task (it SHOULD be able to detect a selection change in a listview, which seems to be what you want), but keep in mind the Explorer interface changes from Windows version to Windows version so don't expect your program to work on different versions of Windows... that said, the way AutoIt finds controls in windows, and the fact that Explorer windows have only one listview, it should theoretically work on most Windows versions if you get it working on one.
QuestionTrying the code outmemberPer Sderberg1 Oct '07 - 3:10 
Hi,
This will be a superb feature to have, so I wrote the following test programme:
-----------------------------------------
Public Class Form1
'Class level declarations
Friend WithEvents gkh As New LLKeyboardHook
 
Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
Try
'Remove the keyboard hook
gkh.RemoveHook()
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
Me.gkh.Dispose()
End Sub
 
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Console.WriteLine("Keyboard Hook " & Me.gkh.GetState.ToString)
End Sub
 
Private Sub gkh_StateChanged(ByVal sender As Object, ByVal e As WindowsHookLib.StateChangedEventArgs) Handles gkh.StateChanged
'Print the keyboard hook state in the KeyboardGroupBox name
 
If e.State = WindowsHookLib.HookState.Uninstalled Then
'Clear the Handle Keyboard checkbox
 
End If
End Sub
 

Private Sub gkh_KeyDown( _
ByVal sender As Object, _
ByVal e As WindowsHookLib.KeyEventArgs) Handles gkh.KeyDown
 
e.Handled = (e.Modifiers = Keys.LWin Or e.Modifiers = Keys.RWin)
e.Handled = (e.Modifiers = Keys.Alt AndAlso e.KeyCode = Keys.Escape)
End Sub
 
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
'Install the keyboard hook
gkh.InstallHook()
 
Catch ex As Exception
Console.WriteLine("Message:")
Console.WriteLine(ex.Message)
Console.WriteLine("Source:")
Console.WriteLine(ex.Source)
Console.WriteLine("StackTrace:")
Console.WriteLine(ex.StackTrace)
 
MessageBox.Show("Failed to install the keyboard hook!." _
& Environment.NewLine & ex.Message, "Keyboard Hook Error!", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Console.WriteLine(ex.Message)
End Try
End Sub
 
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Try
'Remove the mouse hook
gkh.RemoveHook()
Catch ex As Exception
Console.WriteLine("Message:")
Console.WriteLine(ex.Message)
Console.WriteLine("Source:")
Console.WriteLine(ex.Source)
Console.WriteLine("StackTrace:")
Console.WriteLine(ex.StackTrace)
End Try
 
End Sub
End Class
----------------------------------------------
And added the source files and library according to the demo as enclosed. The demo I got to work perfectly.
My aim is to prevent the windows logo button to be used and I wish to block LWIN, RWIN and ctrl-esc
However when running the above programme and hitting the button1 gives an system.componentmodel.win32exception.
Something went wrong in the environment. I run under XP pro.
Any idea on what can be wrong would be greatly appriciated.
 
Per in Sweden
AnswerRe: Trying the code outmemberVBDT1 Oct '07 - 6:50 
I tested your code and there seems to be no problem with it. I don’t get any error. I also use XP pro. What is the error message?
Anyways, I just want to say that LWin or RWin keys are not modifiers and unfortunately you can’t block these keys. These keys are reserved by the system and the windows start menu will appear before the hook process the message. There are some other hotkeys that low level keyboard hook or any other hook can’t block (for exp: Ctrl+Alt+Delete).
Best regards,
VBDT

AnswerRe: Trying the code outmemberPer Sderberg1 Oct '07 - 21:56 
Hi,
Many thanks! Great with your help!
Yes, the error disappeared after that I restarted the computer.
It was my feeling also that I got the start menu before the hook gave it's trace writeline. i found several VB6 articles how to block the LWIN and RWIN in VB6 but yours is the first I found for VB.NET so I apppriciate your article very much! Smile | :)
 
OK, then I suppose I will block the whole keyboard - that works (fortunately) in the application when I need to disallow the start menu.
When I run your demo the whole keyboard is blocked when I mark the handle checkbox. So I will try with in the gkh_keydown add "e.handled = true" then that would solve the problem. If it doesn't I will post again.
All the best and thanks again!
Per
GeneralRe: Trying the code outmemberVBDT2 Oct '07 - 6:39 
Actually, you are right about the demo blocks the LWin and RWin keys. I tested it again and it confirmed that. The reason I said it doesn’t because I tried it with a break point so and since it is breaking at the point the message is being passed. There is a time limitation for windows hooks; if they don’t return the message in the hook process then it will automatically be returned. Anyways, this is just an info, so you should be fine on this.
Best regards,
VBDT

GeneralRe: Trying the code outmemberPer Sderberg2 Oct '07 - 21:26 
Hi,
Yes, many thanks. However I do see a need to only block LWIN and RWIN (And ctrl-esc but that I can block with your hook!).
When building an application you really don't wish to allow the user to run other stuff like setups in the control panel, etc. - Particulary for XP embedded applications where you might need to make maintenance but while the application is running the start menu should be unavailable.
And if it would be possible to solve (it was obviously possible in VB6) also for VB.NET it would surely be fantastic. even though I don't need it now, I'm sure I will need it sooner or later. Smile | :)
Keep up the great work!
Best,
Per

GeneralRe: Trying the code out [modified]memberVBDT3 Oct '07 - 0:00 
So far all the combinations you mentioned in here can be blocked with this LLHook. The only combination that this hook or any other hook doesn’t block is Ctrl+Alt+Delete.
Best regards,
VBDT
 

-- modified at 21:09 Wednesday 3rd October, 2007

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 24 Sep 2010
Article Copyright 2007 by VBDT
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid