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?