SetWindowsHookEx works in Net 2 but not in Net 4

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
I am developing an application that will engage a bar code scanner and will need to be listening for input even when it is not the active application or from a separate thread from within the application. I can get a handle to the hook when I set the
project to compile for Net 2. When I set my project to compile for Net 4 I cannot get a handle from the SetWindowsHookEx. Same code, no changes at all. While obviously I can get a working DLL out of this it really is buggin the ____ out of
me. Additionally, if one of my colegues needs to adjust this DLL in the future and does not know, they may compile it in Net 4. I also have no idea what will be the effects if I reference this DLL in another project that is compiled in Net 4.
Lastly, I am worried that I may encounter more difficulties like this in the future if I cannot figure out what the difference is. Does anyone know why this is or what the solution might be?
Emory

Code:
 Imports System.Reflection<br/>
Imports System.Runtime.InteropServices<br/>
Imports System.Threading<br/>
Imports System.Windows.Forms<br/>
<br/>
Public Class KeyboardKeyEventListener<br/>
    Implements IDisposable<br/>
<br/>
#Region " Members "<br/>
<br/>
    Private Enum HookType As Integer<br/>
         WH_JOURNALRECORD = 0<br/>
         WH_JOURNALPLAYBACK = 1<br/>
         WH_KEYBOARD = 2<br/>
         WH_GETMESSAGE = 3<br/>
         WH_CALLWNDPROC = 4<br/>
         WH_CBT = 5<br/>
         WH_SYSMSGFILTER = 6<br/>
         WH_MOUSE = 7<br/>
         WH_HARDWARE = 8<br/>
         WH_DEBUG = 9<br/>
         WH_SHELL = 10<br/>
         WH_FOREGROUNDIDLE = 11<br/>
         WH_CALLWNDPROCRET = 12<br/>
         WH_KEYBOARD_LL = 13<br/>
         WH_MOUSE_LL = 14<br/>
    End Enum<br/>
<br/>
    // The Code Indicating Low Level Keyboard Message<br/>
    Private Const WH_KEYBOARD_LL As Integer = 13&<br/>
<br/>
    // Low-Level Keyboard Constants<br/>
    Private Const HC_ACTION As Integer = 0<br/>
    Private Const LLKHF_EXTENDED As Integer = &H1<br/>
    Private Const LLKHF_INJECTED As Integer = &H10<br/>
    Private Const LLKHF_ALTDOWN As Integer = &H20<br/>
    Private Const LLKHF_UP As Integer = &H80<br/>
<br/>
    // KeyUp/KeyDown Constants<br/>
    Private Const WM_KEYDOWN As Integer = &H100<br/>
    Private Const WM_KEYUP As Integer = &H101<br/>
    Private Const WM_SYSKEYDOWN As Integer = &H104<br/>
    Private Const WM_SYSKEYUP As Integer = &H105<br/>
<br/>
    // Variables<br/>
    Private KeyboardHandle As Integer<br/>
    Private Disposed As Boolean = False<br/>
<br/>
    // MarshalAs required to keep GC from recovering our delegate and creating a null reference when Windows sends the key event.<br/>
    <MarshalAs(UnmanagedType.FunctionPtr)> Private KeyboardHookProcedure As KeyboardHookDelegate = New KeyboardHookDelegate(AddressOf ProcessKeyboardMessage)<br/>
<br/>
#End Region<br/>
<br/>
#Region " Events "<br/>
<br/>
    Public Event KeyDown(ByRef TheKeyArgs As Windows.Forms.KeyEventArgs)<br/>
    Public Event KeyPress(ByRef TheKeyArgs As Windows.Forms.KeyEventArgs)<br/>
    Public Event KeyUp(ByRef TheKeyArgs As Windows.Forms.KeyEventArgs)<br/>
<br/>
#End Region<br/>
<br/>
#Region " Delegates "<br/>
<br/>
    Private Delegate Function KeyboardHookDelegate(ByVal Code As Integer, _<br/>
                                                  
 ByVal WParam As Integer, _<br/>
                                                  
 ByRef LParam As KBDLLHOOKSTRUCT) As Integer<br/>
<br/>
#End Region<br/>
<br/>
#Region " Function Declarations for user32.dll "<br/>
<br/>
    Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Integer) As Integer<br/>
<br/>
    Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Integer, _<br/>
                                                                                     
 ByVal lpfn As KeyboardHookDelegate, _<br/>
                                                                                     
 ByVal hmod As Integer, _<br/>
                                                                                     
 ByVal dwThreadId As Integer) As Integer<br/>
<br/>
    Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Integer) As Integer<br/>
<br/>
    Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Integer, _<br/>
                                                         
 ByVal nCode As Integer, _<br/>
                                                         
 ByVal wParam As Integer, _<br/>
                                                         
 ByVal lParam As KBDLLHOOKSTRUCT) As Integer<br/>
<br/>
#End Region<br/>
<br/>
#Region " Structures "<br/>
<br/>
    Private Structure KBDLLHOOKSTRUCT<br/>
        Public vkCode As Integer<br/>
        Public scanCode As Integer<br/>
        Public flags As Integer<br/>
        Public time As Integer<br/>
        Public dwExtraInfo As Integer<br/>
    End Structure<br/>
<br/>
#End Region<br/>
<br/>
#Region " Constructors, Destructors and Load Methods "<br/>
<br/>
    Public Sub New()<br/>
<br/>
        Try<br/>
<br/>
        Catch ex As Exception<br/>
            Throw ex<br/>
        End Try<br/>
<br/>
    End Sub<br/>
<br/>
    Public Overridable Sub Dispose() Implements IDisposable.Dispose<br/>
<br/>
        Try<br/>
            If Not (Disposed = True) Then<br/>
                Disposed = True<br/>
                If Not (KeyboardHandle = 0) Then UnhookWindowsHookEx(KeyboardHandle)<br/>
            Else<br/>
                Throw New ObjectDisposedException("KeyboardHook")<br/>
            End If<br/>
<br/>
        Catch ex As Exception<br/>
            Throw ex<br/>
        End Try<br/>
<br/>
    End Sub<br/>
<br/>
    Protected Overrides Sub Finalize()<br/>
<br/>
        Try<br/>
            MyBase.Finalize()<br/>
<br/>
            If Not Disposed Then<br/>
                Dispose()<br/>
            End If<br/>
<br/>
        Catch ex As Exception<br/>
            Throw ex<br/>
        End Try<br/>
<br/>
    End Sub<br/>
<br/>
#End Region<br/>
<br/>
#Region " Methods - Primary "<br/>
<br/>
    Public Function StartListening() As Boolean<br/>
<br/>
        Try<br/>
            // The first argument to SetWindowsHookEx Sets the Type of Hook.<br/>
            // The second argument is the tagged delegate that contains the address of our local callback method.<br/>
            // The third argument is the handle (hWnd) of the application doing the hooking<br/>
            // The fourth argument is the thread to listen on.  Passing 0 indicates all threads.<br/>
<br/>
            Console.WriteLine("KeyboardHandle = " + KeyboardHandle.ToString)<br/>
            Console.WriteLine("WH_KEYBOARD_LL = " + WH_KEYBOARD_LL.ToString)<br/>
            Console.WriteLine("KeyboardHookProcedure = " + KeyboardHookProcedure.ToString)<br/>
            Console.WriteLine("Current Assembly Thread = " + Marshal.GetHINSTANCE([Assembly].GetExecutingAssembly.GetModules()(0)).ToInt32.ToString)<br/>
            Console.WriteLine("")<br/>
<br/>
            KeyboardHandle = SetWindowsHookEx(WH_KEYBOARD_LL, _<br/>
                                             
 KeyboardHookProcedure, _<br/>
                                             
 Marshal.GetHINSTANCE([Assembly].GetExecutingAssembly.GetModules()(0)).ToInt32, _<br/>
                                             
 0)<br/>
<br/>
            Console.WriteLine("KeyboardHandle = " + KeyboardHandle.ToString)<br/>
<br/>
            If (KeyboardHandle = 0) Then<br/>
                Return False<br/>
            Else<br/>
                Return True<br/>
            End If<br/>
<br/>
        Catch ex As Exception<br/>
            Throw New Exception("Exception encountered in StartListening" + vbCrLf + ex.Message)<br/>
        End Try<br/>
<br/>
    End Function<br/>
<br/>
    Public Function StopListening() As Boolean<br/>
<br/>
        Try<br/>
            If Not (KeyboardHandle = 0) Then UnhookWindowsHookEx(KeyboardHandle)<br/>
<br/>
            Console.WriteLine(KeyboardHandle.ToString)<br/>
            KeyboardHandle = 0<br/>
<br/>
            Return True<br/>
<br/>
        Catch ex As Exception<br/>
            Throw ex<br/>
        End Try<br/>
<br/>
    End Function<br/>
<br/>
    Private Function ProcessKeyboardMessage(ByVal Code As Integer, ByVal WParam As Integer, ByRef LParam As KBDLLHOOKSTRUCT) As Integer<br/>
<br/>
        Try<br/>
            Dim TheKeys As Windows.Forms.Keys = CType(LParam.vkCode, Keys)<br/>
            Dim TheKeyArgs As Windows.Forms.KeyEventArgs = New Windows.Forms.KeyEventArgs(TheKeys)<br/>
<br/>
            If WParam = WM_KEYDOWN Or WParam = WM_SYSKEYDOWN Then<br/>
                RaiseEvent KeyDown(TheKeyArgs)<br/>
            ElseIf WParam = WM_KEYUP Or WParam = WM_SYSKEYUP Then<br/>
                RaiseEvent KeyUp(TheKeyArgs)<br/>
            End If<br/>
<br/>
            // Call the next hook in the hook chain and return the value<br/>
            Return CallNextHookEx(KeyboardHandle, Code, WParam, LParam)<br/>
<br/>
        Catch ex As Exception<br/>
            Throw New Exception("Exception encountered in ProcessKeyStroke" + vbCrLf + vbCrLf + ex.Message)<br/>
        End Try<br/>
<br/>
    End Function<br/>
<br/>
#End Region<br/>
<br/>
#Region " Methods - Utility "<br/>
<br/>
#End Region<br/>
<br/>
End Class<br/>
<br/>


View the full article
 
Back
Top