VB.NET显微镜登录系统LowLevelKeyboardProc委托被回收报错求助
解决方案:低级键盘钩子委托被GC回收问题
这个错误的核心原因是你的LowLevelKeyboardProc委托被.NET垃圾回收器(GC)回收了——哪怕你声明了变量,要么是变量作用域不对,要么是注销时没正确卸载钩子,导致系统钩子仍在引用已被回收的委托。闲置10分钟触发是因为GC会在后台周期性回收无引用对象,刚好在这段时间回收了该委托。
以下是具体修复步骤:
1. 将委托声明为类级共享变量
确保委托变量的生命周期和应用程序/窗口周期一致,避免局部变量被GC回收:
' 在主窗体/核心类中声明类级共享委托变量 Private Shared _keyboardHookProc As LowLevelKeyboardProc Private Shared _hookHandle As IntPtr = IntPtr.Zero ' 定义钩子回调委托 Private Delegate Function LowLevelKeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
2. 注销流程中主动卸载钩子
在F2触发注销时,必须先卸载已注册的低级键盘钩子,再切换回登录界面:
Private Sub Logout() ' 先卸载钩子 If _hookHandle <> IntPtr.Zero Then UnhookWindowsHookEx(_hookHandle) _hookHandle = IntPtr.Zero End If ' 切换回登录界面 LoginForm.Show() Me.Hide() End Sub ' 导入卸载钩子的API函数 <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> Private Shared Function UnhookWindowsHookEx(ByVal hhk As IntPtr) As Boolean End Function
3. 登录成功后重新注册钩子
确保钩子的生命周期和登录状态严格绑定:每次登录后注册钩子,注销时卸载:
Private Sub RegisterKeyboardHook() If _hookHandle = IntPtr.Zero Then _keyboardHookProc = AddressOf LowLevelKeyboardHookCallback _hookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardHookProc, GetModuleHandle(Nothing), 0) ' 可选:强制GC暂时不回收委托(辅助手段,核心还是靠作用域和卸载) GC.KeepAlive(_keyboardHookProc) End If End Sub ' 登录成功时调用 Private Sub LoginSuccess() RegisterKeyboardHook() MainForm.Show() LoginForm.Hide() End Sub
4. 钩子回调函数的正确实现
确保回调逻辑规范,避免不必要的引用泄漏:
Private Function LowLevelKeyboardHookCallback(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr If nCode >= 0 Then ' 处理Win+ESC、Win+D、Alt+Tab等组合键屏蔽逻辑 Dim keyData = CType(Marshal.ReadInt32(lParam), Keys) If (keyData = Keys.Escape AndAlso (Control.ModifierKeys And Keys.LWin) = Keys.LWin) OrElse _ (keyData = Keys.D AndAlso (Control.ModifierKeys And Keys.LWin) = Keys.LWin) OrElse _ (Control.ModifierKeys And Keys.Alt) = Keys.Alt AndAlso (keyData = Keys.Tab) Then ' 返回1表示拦截该按键消息 Return New IntPtr(1) End If End If ' 传递消息给下一个钩子 Return CallNextHookEx(_hookHandle, nCode, wParam, lParam) End Function
关键注意点:
- 绝对不能让钩子在注销后仍处于激活状态,否则即便委托被回收,系统仍会尝试调用它触发错误。
- 类级共享变量能确保委托在类的生命周期内不会被GC回收,直到你主动卸载钩子并置空引用。
内容的提问来源于stack exchange,提问作者xiao000139
相关产品推荐
相关产品推荐

