Added support for Journal Record and Playback hooks
Added MsgFilterlParam method for working with the WH_GETMESSAGE Hook.
Win32 Hooks in VB - The vbAccelerator Hook Library
The ultimate low-level control over Windows
When a subclass isn't tough enough for the job, its time to move to an even lower-level and more disruptive technique. Win32 Hooks are a method by which you can tap into the Windows message stream for every single message directed to every window in your application. You can modify or even discard messages before they even reach the target window. This technique gives you a lot of control!
Windows Hooks are defined in the Win32 SDK as follows:
This section provides a detailed look into what hooks consist of, why you use them and the various types available:
1. Hooks Compared to Sub-Classing
Essentially a Windows Hook is like a subclass except it applies at the next point up in the message chain. In Win32, messages are queued and sent to the appropriate window via the WindowProc function. A subclass can intercept messages by replacing the existing WindowProc function with a new one.
With a Hook, you get to see all messages before Windows has decided which WindowProc procedure to direct the message to. You can modify or discard most messages at this point too. So using the Hook technique you not only get to act on messages at the highest point; you can also get at messages regardless of which window the message is intended for. This is very useful if you want to process Keyboard or Mouse messages on a global basis in your application, because these messages are normally directed to the window with the focus. If you tried to do the same thing using Subclassing then you would have to subclass every single window handle in your application to follow the mouse events. Using a Hook, the process is simple!
2. An Example
If you create a VB application like the one shown above, you'll find that it doesn't behave like you would expect a normal Windows application to. Since the N mnemonic is visible on screen, it should be accessible at any time by pressing Alt+N. However, this is isn't the case in VB - in fact Alt+N only does anything when the MDI form has the focus, which is clearly a bug.
This is actually a fundamental problem in VB for MDI forms - there is no way for an accelerator on another form to be active when there is a child form active. We could solve this problem by duplicating the New button onto the child form, but in order for it to respond to accelerator keys it must be visible and part of the tab order - not what you want.
Solving the problem with a Windows Hook on the other hand is quite simple. We install a hook of type WH_KEYBOARD. Then the app receives all keyboard events for the entire application. When the keyboard events indicate that Alt+N has been pressed, the code just needs to check whether the MDIForm is the same as the window returned by GetActiveWindow; if it is it then the code fires the cmdNew_Click event and eats the keyboard message.
3. Hook Scope: System Wide or Local Thread Hooks
One of the features of the Win32 Hook functions is that they allow you to specify whether the scope of your hook is local to the current thread or whether it applies to all windows in the entire system. System Wide hooks are always a topic of interest because they let you read data intended for or otherwise modify windows owned by other applications; for example the Window Blinds application uses this method to apply a skin when drawing all windows on your system (well, it tries to, anyway!)
Before you get excited, though, VB on its own cannot be used to create a system-wide hook. This is because the hook procedure must reside within a Windows DLL, and VB cannot create these beasts (because you cannot specify to export the HookProc function). Also I should point out that system-wide hooks aren't much fun to write: you can't debug them very easily, and if anything goes wrong it takes your whole system down! If you have some C/C++ knowledge, however, there are various samples of creating system-wide hooks at MSDN and CodeGuru.
4. Types Of Windows Hooks
There are 14 different types of Windows Hooks defined in Win32, however, some of these are not implemented and some cannot be used in Visual Basic or are of very limited value when not used System Wide.
That leaves the following:
5. Hook Chains
When you install a Hook, Win32 actually adds it to what is termed the "Hook Chain". This allows you to install multiple Hooks of the same type in an application. When the first Hook is added, Windows places it at the start of the chain and begins passing messages to the Hook and receiving them from it. If another hook of the same type is added on the same thread, windows then directs output from the first hook to the second one before receiving the output for its own use.
This means that you must be careful when using a Hook to modify or remove messages. If there are two Hooks on the same thread, and one removes messages, behaviour may differ depending on the order the Hooks are installed. In VB there is very little control over the order that controls are created so you should attempt to ensure the same hook procedure is used for all objects that install a hook.
The vbAccelerator Windows Hooks Library
The vbAccelerator Windows Hooks Library is designed to simplify the process of working with hooks in your application. It provides a series of functions for installing and removing hooks and ensures multiple clients use the same hook function rather than installing multiple chained hooks. It is designed to be used either as a DLL or compiled directly into your application. An example of compiling the library directly into code is provided in the vbAccelerator Accelerator control, so this section will cover using the DLL version.
The Hooks Library consists of two parts:
This sample will give you a quick introduction to the Hooks library. Start a new project, and add a reference to the vbAccelerator Window Hooks Library by choosing Project->References and selecting the "vbAccelerator Windows Hook Helper DLL". If it isn't there, click Browse and search for vbalHook.DLL (VB5) or vbalHook6.DLL (VB6) on your disk. Once you have a reference, add various controls to your form including a TextBox control. Then add the following code:
Implements IWindowsHook Private Sub Form_Load() InstallHook Me, WH_KEYBOARD End Sub Private Sub Form_QueryUnload( _ Cancel As Integer, UnloadMode As Integer) RemoveHook Me, WH_KEYBOARD End Sub Private Function IWindowsHook_HookProc( _ ByVal eType As EHTHookTypeConstants, _ ByVal nCode As Long, _ ByVal wParam As Long, _ ByVal lParam As Long, _ bConsume As Boolean _ ) As Long If KeyBoardlParam(lParam).KeyDown Then If Me.ActiveControl is Text1 Then txtTest.SelText = " " bConsume = True End If End If End Function
Now run the project. Whenever the TextBox control Text1 is in focus, pressing the tab key will cause the tab characters to be entered into the text box rather than moving to the next control in the tab index. This works because all key presses in the project are sent through the IWindowsHook_HookProc function before being sent to any control or form. So you can consume any key press you want and stop it ever reaching the control! Now that's control...
The Sample Code
There are two samples provided with the download: