|
-
Aug 31st, 2014, 09:09 AM
#1
Thread Starter
New Member
CallbackOnCollectedDelegate in keyboard hook
Hello,
I'm trying to set a keyboar hook, but I'm getting a CallbackOnCollectedDelegate exception when the object (where an instance of the hook is declared), gets disposed . The exception occures on the line where CallNextHookEx is called.
(it's an existing source, wich I translated from C# to VB.NET & modified)
Code:
#Region "File Description"
'-----------------------------------------------------------------------------
' KeyboardUtils.cs
'
' Microsoft XNA Community Game Platform
' Copyright (C) Microsoft Corporation. All rights reserved.
'-----------------------------------------------------------------------------
#End Region
#Region "Using Statements"
Imports System.Collections.Generic
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
#End Region
' This class exposes WinForms-style key events.
Namespace Hooks
''' <summary>
''' A class to provide text input capabilities to an XNA application svia Win32 hooks.
''' </summary>
Public Class TextInput
Implements IDisposable
Private m_buffer As String = ""
Private m_backSpace As Boolean = False
Public ReadOnly Property Buffer() As String
Get
Return m_buffer
End Get
End Property
Public ReadOnly Property BackSpace() As Boolean
Get
Dim b As Boolean = m_backSpace
m_backSpace = False
Return b
End Get
End Property
Public Sub clearBuffer()
m_buffer = ""
End Sub
#Region "Win32"
''' <summary>
''' Types of hook that can be installed using the SetWindwsHookEx function.
''' </summary>
Public Enum HookId
WH_CALLWNDPROC = 4
WH_CALLWNDPROCRET = 12
WH_CBT = 5
WH_DEBUG = 9
WH_FOREGROUNDIDLE = 11
WH_GETMESSAGE = 3
WH_HARDWARE = 8
WH_JOURNALPLAYBACK = 1
WH_JOURNALRECORD = 0
WH_KEYBOARD = 2
WH_KEYBOARD_LL = 13
WH_MAX = 11
WH_MAXHOOK = WH_MAX
WH_MIN = -1
WH_MINHOOK = WH_MIN
WH_MOUSE_LL = 14
WH_MSGFILTER = -1
WH_SHELL = 10
WH_SYSMSGFILTER = 6
End Enum
''' <summary>
''' Window message types.
''' </summary>
''' <remarks>Heavily abridged, naturally.</remarks>
Public Enum WindowMessage
WM_KEYDOWN = &H100
WM_KEYUP = &H101
WM_CHAR = &H102
End Enum
''' <summary>
''' A delegate used to create a hook callback.
''' </summary>
Public Delegate Function GetMsgProc(nCode As Integer, wParam As Integer, ByRef msg As Message) As Integer
''' <summary>
''' Install an application-defined hook procedure into a hook chain.
''' </summary>
''' <param name="idHook">Specifies the type of hook procedure to be installed.</param>
''' <param name="lpfn">Pointer to the hook procedure.</param>
''' <param name="hmod">Handle to the DLL containing the hook procedure pointed to by the lpfn parameter.</param>
''' <param name="dwThreadId">Specifies the identifier of the thread with which the hook procedure is to be associated.</param>
''' <returns>If the function succeeds, the return value is the handle to the hook procedure. Otherwise returns 0.</returns>
<DllImport("user32.dll", EntryPoint:="SetWindowsHookExA")> _
Public Shared Function SetWindowsHookEx(idHook As HookId, lpfn As GetMsgProc, hmod As IntPtr, dwThreadId As Integer) As IntPtr
End Function
''' <summary>
''' Removes a hook procedure installed in a hook chain by the SetWindowsHookEx function.
''' </summary>
''' <param name="hHook">Handle to the hook to be removed. This parameter is a hook handle obtained by a previous call to SetWindowsHookEx.</param>
''' <returns>If the function fails, the return value is zero. To get extended error information, call GetLastError.</returns>
<DllImport("user32.dll")> _
Public Shared Function UnhookWindowsHookEx(hHook As IntPtr) As Integer
End Function
''' <summary>
''' Passes the hook information to the next hook procedure in the current hook chain.
''' </summary>
''' <param name="hHook">Ignored.</param>
''' <param name="ncode">Specifies the hook code passed to the current hook procedure.</param>
''' <param name="wParam">Specifies the wParam value passed to the current hook procedure.</param>
''' <param name="lParam">Specifies the lParam value passed to the current hook procedure.</param>
''' <returns>This value is returned by the next hook procedure in the chain.</returns>
<DllImport("user32.dll")> _
Public Shared Function CallNextHookEx(hHook As Integer, ncode As Integer, wParam As Integer, ByRef lParam As Message) As Integer
End Function
''' <summary>
''' Translates virtual-key messages into character messages.
''' </summary>
''' <param name="lpMsg">Pointer to an Message structure that contains message information retrieved from the calling thread's message queue.</param>
''' <returns>If the message is translated (that is, a character message is posted to the thread's message queue), the return value is true.</returns>
<DllImport("user32.dll")> _
Public Shared Function TranslateMessage(ByRef lpMsg As Message) As Boolean
End Function
''' <summary>
''' Retrieves the thread identifier of the calling thread.
''' </summary>
''' <returns>The thread identifier of the calling thread.</returns>
<DllImport("kernel32.dll")> _
Public Shared Function GetCurrentThreadId() As Integer
End Function
#End Region
#Region "Hook management and class construction."
''' <summary>Handle for the created hook.</summary>
Private ReadOnly HookHandle As IntPtr
' Private ReadOnly ProcessMessagesCallback As GetMsgProc
Private ReadOnly ProcessMessagesCallback As GetMsgProc
''' <summary>Create an instance of the TextInputHandler.</summary>
''' <param name="whnd">Handle of the window you wish to receive messages (and thus keyboard input) from.</param>
Public Sub New(whnd As IntPtr)
' Create the delegate callback:
Me.ProcessMessagesCallback = New GetMsgProc(AddressOf ProcessMessages)
' Create the keyboard hook:
Me.HookHandle = SetWindowsHookEx(HookId.WH_GETMESSAGE, Me.ProcessMessagesCallback, IntPtr.Zero, GetCurrentThreadId())
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
' Remove the hook.
If Me.HookHandle <> IntPtr.Zero Then
UnhookWindowsHookEx(Me.HookHandle)
End If
End Sub
#End Region
#Region "Message processing"
Private Function ProcessMessages(nCode As Integer, wParam As Integer, ByRef msg As Message) As Integer
' Check if we must process this message (and whether it has been retrieved via GetMessage):
If nCode = 0 AndAlso wParam = 1 Then
' We need character input, so use TranslateMessage to generate WM_CHAR messages.
TranslateMessage(msg)
' If it's one of the keyboard-related messages, raise an event for it:
Select Case CType(msg.Msg, WindowMessage)
Case WindowMessage.WM_CHAR
Me.OnKeyPress(New KeyPressEventArgs(Chr(msg.WParam.ToInt32)))
Exit Select
Case WindowMessage.WM_KEYDOWN
Me.OnKeyDown(New KeyEventArgs(CType(msg.WParam, Keys)))
Exit Select
Case WindowMessage.WM_KEYUP
Me.OnKeyUp(New KeyEventArgs(CType(msg.WParam, Keys)))
Exit Select
End Select
End If
Return CallNextHookEx(0, nCode, wParam, msg)
End Function
#End Region
#Region "Events"
Public Event KeyUp As KeyEventHandler
Protected Overridable Sub OnKeyUp(e As KeyEventArgs)
RaiseEvent KeyUp(Me, e)
End Sub
Public Event KeyDown As KeyEventHandler
Protected Overridable Sub OnKeyDown(e As KeyEventArgs)
RaiseEvent KeyDown(Me, e)
End Sub
Public Event KeyPress As KeyPressEventHandler
Protected Overridable Sub OnKeyPress(e As KeyPressEventArgs)
RaiseEvent KeyPress(Me, e)
If e.KeyChar.GetHashCode().ToString() = "524296" Then
m_backSpace = True
Else
m_buffer += e.KeyChar
End If
End Sub
#End Region
End Class
End Namespace
What am I doing wrong/how would I fix this?
-
Aug 31st, 2014, 01:42 PM
#2
Re: CallbackOnCollectedDelegate in keyboard hook
i cant replicate your error using the code you provided. maybe you have set up two hooks on the same window?
this is how i tested it:
Code:
Public Class Form1
Private WithEvents o As Hooks.TextInput
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
o = New Hooks.TextInput(Me.Handle)
End Sub
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
o.Dispose()
End Sub
Private Sub o_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles o.KeyDown
Debug.Print(DateTime.Now)
End Sub
End Class
-
Sep 1st, 2014, 06:11 AM
#3
Thread Starter
New Member
Re: CallbackOnCollectedDelegate in keyboard hook
Don't you get an error when you dispose Form1?
Even when I disposed the instance of the hook, I still get the error when disposing Form1.
I'll check if I accedently set up 2 hooks.
-
Sep 1st, 2014, 06:40 AM
#4
Re: CallbackOnCollectedDelegate in keyboard hook
no error here. i just created a new project, added your code to a new class, added two buttons to the form and my code in the form and ran it. once button1 is clicked i do get debug output with each keystroke, once button2 is clicked no more output as expected, can close the form all without any error popping up.
the error message you report may mean that CallNextHookEx attemted to jump to a memory location that was already collected by the GC. thats why i came up with the idea that you maybe have multiple hooks on the same window.
-
Sep 15th, 2014, 10:10 AM
#5
Thread Starter
New Member
Re: CallbackOnCollectedDelegate in keyboard hook
(Sorry for this gravedig)
The error kept happening for some wierd reason (I should clean up my code ), but for those wondering; I temporary 'fixed' it this way:
I created a global variable for the hook in a module & created an instance at launch.
Sorry for my bad English!
Duts
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|