developer.com
Search EarthWeb
CodeGuru | Gamelan | Jars | Wireless | Discussions
Navigate developer.com
Architecture & Design  
Database  
Java
Languages & Tools
Microsoft & .NET
Open Source  
Project Management  
Security  
Techniques  
Voice  
Web Services  
Wireless/Mobile
XML  
New
 
Technology Jobs  

   Developer.com Webcasts:
  The Impact of Coding Standards and Code Reviews

  Project Management for the Developer

  Defining Your Own Software Development Methodology

  more Webcasts...




Vote for the Developer.com Product of the Year Winners!




Developer Jobs

Be a Commerce Partner














 


Developer News -
Are We Ready for the Cloud?    November 7, 2008
Windows 7 Drivers to Get a Makeover    November 6, 2008
Sun Serves Up Some Java EE 6 in GlassFish    November 6, 2008
Devs Dish Some iPhone App Tips    November 5, 2008
Free Tech Newsletter -

Managing Low-Level Keyboard Hooks in VB .NET
By Paul Kimmel

Go to page: Prev  1  2  3  Next  

Implementing the Keyboard Delegate

To hook the keyboard, we are inserting our method into the address space for the existing low-level handler. This is what we did with interrupt handlers, and we still perform the same basic operation at a moderately higher level of abstraction. As is true with interrupt handlers, we need to hang onto the old handler, and ensure we call it. If we don't call the old handler, we prevent someone else's code from running. This would be rude unless our intention is to prevent someone else's keyboard code from running.

The delegate signature has to play by the same rules as a plain vanilla function pointer. The delegate signature must match an expected signature. Delegates will be invoked with the anticipation and necessity of receiving specific arguments and a return value if one is expected. In our example, the operating system will be calling with two integers and a structure that contains key state information. The caller will be expecting a return value, too. We can name the delegate anything, but as mentioned, the signature must match. The signature of our callback method is defined next.

Public Delegate Function KeyboardHookDelegate( _
  ByVal Code As Integer, _
  ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) _
               As Integer

Decomposed into chunks, we have:

  • Public—The Delegate type is public
  • Delegate—Defines this method signature as a subclass of the System.Delegate type
  • Function—Indicates that the caller will expect a return value
  • KeyboardHookDelegate—Is the name of the delegate
  • Code—Is the name of the first argument, an Integer, that is passed by value
  • wParam—Is a by-value Integer that we don't need in the example but is commonly found in message methods
  • lParam—Very important to keyboard hooking; we need a pointer to the keyboard state information. This structure will tell us everything we need to know about the keys being pressed, released, and held. It is important to define this argument ByRef.
  • As Integer—Indicates that the caller will be expecting an Integer.

We will actually need a method that very closely matches the signature of the delegate. The only point at which we can deviate is the name of the actual arguments. The callback method can use different names for the arguments, but the order and type of the arguments and the method type—function or subroutine—must match exactly.

Hooking the Keyboard

To hook the keyboard, we need to call the SetWindowsHookEx method. We will need a constant indicating what we want to hook, the idHook argument. We need a method that can be called back, the lpfn argument. A handle of the application doing the hooking, which is our application and the hmod argument, and the thread of the process we want to hook.

When hooking the keyboard in .NET, this part of the revision—from VB6–7 to VB.NET—is the most problematic. To facilitate, I have taken an important excerpt from the complete listing, listing 2. That excerpt is provided in listing 1.

Listing 1: Critical revisions to hooking the keyboard in .NET.

<MarshalAs(UnmanagedType.FunctionPtr)> _
Private callback As KeyboardHookDelegate

Public Sub HookKeyboard()
  callback = New KeyboardHookDelegate(AddressOf KeyboardCallback)

  KeyboardHandle = SetWindowsHookEx( _
    WH_KEYBOARD_LL, callback, _
    Marshal.GetHINSTANCE( _
    [Assembly].GetExecutingAssembly.GetModules()(0)).ToInt32, 0)

   Call CheckHooked()
  End Sub

Delegates are managed objects in .NET. This means that they are garbage collected. A problem occurs when we pass a delegate to the unmanaged code of the user32.dll API. Apparently, the garbage collector doesn't know that the delegate object is in use and after a short interval—roughly 47 seconds in experiments—the delegate is garbage collected. Consequently, when the API method attempts to call the method represented by the delegate back, a null reference exception occurs. To prevent the delegate from getting GC'd, we need to tag a delegate variable with the System.Runtime.InteropServices.MarshalAsAttribute, passing the enumerated value UnmanagedType.FunctionPtr. This tags the delegate argument, preventing it from being GC'd in an untimely fashion.

The first argument to SetWindowsHookEx is WH_KEYBOARD_LL. The second argument is the tagged delegate that contains the address of our local callback method. The third argument is the handle (hWnd) of the application doing the hooking, and passing 0 for the thread id means that we want to hook the keyboard for all threads.

For all of our efforts, if we forget the MarshalAsAttribute, the code fails miserably. You can read more about COMInterop in my new book Visual Basic .NET Power Coding from Addison-Wesley, available July, 2003.

Go to page: Prev  1  2  3  Next  


Tools:
Add www.developer.com to your favorites
Add www.developer.com to your browser search box
IE 7 | Firefox 2.0 | Firefox 1.5.x
Receive news via our XML/RSS feed


.NET Archives






internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info

Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers