Низкоуровневый хук клавиатуры не распознает нажатия клавиш VB.NET

Я успешно практиковал низкоуровневые зацепки клавиатуры в Visual Basic 2010 (.NET Framework v4.0), затем перенес этот же проект перехвата в Visual Studio 2017 (.NET Framework 4.5.2), и теперь он не обнаруживает нажатий клавиш, Я уже пытался изменить целевой фреймворк на v4.0, но безрезультатно.

Вот мой код:

'Form1
Private WithEvents KbHook As KeyboardHook

 Private Sub KbHook_KeyDown(Keycode As Keys) Handles KbHook.KeyDown
    MessageBox.Show("Key pressed!")
End Sub

И класс KeyboardHook:

Imports System.Runtime.InteropServices

Public Class KeyboardHook

<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
Private Overloads Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal HookProc As KBDLLHookProc, ByVal hInstance As IntPtr, ByVal wParam As Integer) As Integer
End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
Private Overloads Shared Function CallNextHookEx(ByVal idHook As Integer, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)>
Private Overloads Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean
End Function

<StructLayout(LayoutKind.Sequential)>
Private Structure KBDLLHOOKSTRUCT
    Public vkCode As UInt32
    Public scanCode As UInt32
    Public flags As KBDLLHOOKSTRUCTFlags
    Public time As UInt32
    Public dwExtraInfo As UIntPtr
End Structure

<Flags()>
Private Enum KBDLLHOOKSTRUCTFlags As UInt32
    LLKHF_EXTENDED = &H1
    LLKHF_INJECTED = &H10
    LLKHF_ALTDOWN = &H20
    LLKHF_UP = &H80
End Enum

Public Shared Event KeyDown(ByVal Key As Keys)
Public Shared Event KeyUp(ByVal Key As Keys)

Private Const WH_KEYBOARD_LL As Integer = 13
Private Const HC_ACTION As Integer = 0
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Const WM_SYSKEYDOWN = &H104
Private Const WM_SYSKEYUP = &H105

Private Delegate Function KBDLLHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer

Private KBDLLHookProcDelegate As KBDLLHookProc = New KBDLLHookProc(AddressOf KeyboardProc)
Private HHookID As IntPtr = IntPtr.Zero

Private Function KeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
    If (nCode = HC_ACTION) Then
        Dim struct As KBDLLHOOKSTRUCT
        Select Case wParam
            Case WM_KEYDOWN, WM_SYSKEYDOWN
                RaiseEvent KeyDown(CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys))
            Case WM_KEYUP, WM_SYSKEYUP
                RaiseEvent KeyUp(CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys))
        End Select
    End If
    Dim ret As Integer = CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam)
    Return ret
End Function

Public Sub New()
    HHookID = SetWindowsHookEx(WH_KEYBOARD_LL, KBDLLHookProcDelegate, System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32, 0)
    If HHookID = IntPtr.Zero Then
        Throw New Exception("Error!")
    End If
End Sub

Protected Overrides Sub Finalize()
    If Not HHookID = IntPtr.Zero Then
        UnhookWindowsHookEx(HHookID)
    End If
    MyBase.Finalize()
End Sub
End class

В Form1 установлена ​​точка останова на

Private Sub KbHook_KeyDown(Keycode As Keys) Handles KbHook.KeyDown

но приложение никогда не ломается при наборе текста на моей клавиатуре. Я довольно запутался, так как он работал в VB2010... У кого-нибудь есть подсказки, как решить проблему?

Заранее спасибо;)

1 ответ

Спасибо за приведенный выше код blondkarol и Джиму Хьюитту. Я заставил его работать в .net 3.5. а у меня в 4.8 не работает. Поэтому я включил некоторый код из другого поста и получил следующий код для работы в .net 4.8.

      Imports System.Runtime.InteropServices

Public Class LL_KeyboardHook

   Public Delegate Function CallBack(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer

   <DllImport("user32.dll")>
   Public Shared Function SetWindowsHookEx(idHook As Integer, lpfn As CallBack, hMod As IntPtr, dwThreadId As Integer) As IntPtr
   End Function

   <DllImport("user32.dll")>
   Private Shared Function UnhookWindowsHookEx(idHook As IntPtr) As Integer
   End Function

   <DllImport("user32.dll")>
   Private Shared Function CallNextHookEx(idHook As IntPtr, nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
   End Function

   <StructLayout(LayoutKind.Sequential)>
   Private Structure KBDLLHOOKSTRUCT
      Public vkCode As UInteger
      Public scanCode As UInteger
      Public flags As UInteger
      Public time As UInteger
      Public dwExtraInfo As UInteger
   End Structure

   Private Const WH_KEYBOARD_LL As Integer = 13
   Private Const HC_ACTION As Integer = 0
   Private Const WM_KEYDOWN = &H100
   Private Const WM_KEYUP = &H101
   Private Const WM_SYSKEYDOWN = &H104
   Private Const WM_SYSKEYUP = &H105

   Private Delegate Function KBDLLHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
   Private HHookID As IntPtr = IntPtr.Zero

   Public Shared Event KeyDown(ByVal Key As Keys)
   Public Shared Event KeyUp(ByVal Key As Keys)

   Private Function KeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer

      Dim Key As Keys

      If (nCode = HC_ACTION) Then

         Dim struct As KBDLLHOOKSTRUCT

         Select Case wParam
            Case WM_KEYDOWN, WM_SYSKEYDOWN
               Key = CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys)
               RaiseEvent KeyDown(Key)
               'example below to intercept and not pass along the "A" down key
               'If Key.ToString = "A" Then
               '   Return 1
               '   Exit Function
               'End If

            Case WM_KEYUP, WM_SYSKEYUP
               Key = CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys)
               RaiseEvent KeyUp(Key)
         End Select
      End If

      Dim ret As Integer = CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam)
      Return ret

   End Function

   Public Sub New()

      Static WindowsHookProc = New CallBack(AddressOf KeyboardProc)
      HHookID = SetWindowsHookEx(WH_KEYBOARD_LL, WindowsHookProc, IntPtr.Zero, 0)

      If HHookID = IntPtr.Zero Then
         Throw New Exception("Error!")
      End If

   End Sub

   Protected Overrides Sub Finalize()
      If Not HHookID = IntPtr.Zero Then
         UnhookWindowsHookEx(HHookID)
      End If
      MyBase.Finalize()
   End Sub

End Class

Чтобы использовать код в форме:

      Private WithEvents kbHook As New LL_KeyboardHook

Private Sub kbHook_KeyDown(Key As Keys) Handles kbHook.KeyDown
   Debug.WriteLine(Key)
End Sub

Private Sub kbHook_KeyUp(Key As Keys) Handles kbHook.KeyUp
   Debug.WriteLine(Key)
End Sub
Другие вопросы по тегам