You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell中无法停止C#实现的低级钩子问题求助

低级钩子停止失败与空值错误的原因分析及解决办法

问题原因分析

  • 脚本块变量作用域丢失:事件处理脚本块中使用的$self变量,受PowerShell作用域规则限制,事件触发时该变量可能已脱离原始作用域,导致$self.kh或$self.mh为空值,调用Stop()时触发空值错误。
  • GUI控件引用不规范:鼠标事件中直接使用全局CMDList,而非类成员$this.list,既不符合封装原则,也可能因控件对象引用失效引发异常。
  • 钩子停止逻辑的潜在冲突:在键盘事件中直接停止两个钩子,可能导致其中一个钩子对象提前被回收,另一个调用时出现空值。

解决办法

1. 用$using:固定脚本块的变量引用

PowerShell中通过$using:关键字让脚本块捕获当前作用域的变量,避免引用丢失。修改键盘事件绑定部分:

# 定义KeyDown事件处理器
$this.kh.add_KeyDown({
    param($sender, $e)
    $vkCode = $sender.vkCode
    Write-Host $vkCode
    if ($vkCode -eq 115) { # F4键的VK码为115
        $using:this.kh.Stop()
        $using:this.mh.Stop()
    }

    $charCode = [Win32.NativeMethods]::MapVirtualKey($vkCode, 2)
    $char = [char]$charCode
    Write-Host $char
})

2. 修正GUI控件引用

鼠标事件中使用类成员$this.list替代全局CMDList,确保控件引用正确:

# 定义LeftButtonDown事件处理器
$this.mh.add_LeftButtonDown({
    param($sender, $e)
    $mousePosition = $sender.pt
    $y = $mousePosition.y
    $x = $mousePosition.x
    $item = New-Object System.Windows.Forms.ListViewItem
    $item.ToolTipText = $global:dict["LeftClickCode"] -f $x, $y
    $item.Text = $global:dict["LeftClickDescription"] -f $x, $y
    $using:this.list.Items.Add($item)
})

3. 优化钩子停止逻辑

先检查对象是否为空再调用Stop(),同时可解除事件绑定避免后续无效触发:

# 修正KeyDown中的停止逻辑
if ($vkCode -eq 115) {
    if ($using:this.kh) {
        $using:this.kh.Stop()
        $using:this.kh.remove_KeyDown($this)
    }
    if ($using:this.mh) {
        $using:this.mh.Stop()
        $using:this.mh.remove_LeftButtonDown($this)
    }
}

4. 完整修正后的类代码

class InputRecorder {
    [KeyboardHookExample.KeyboardHook] $kh
    [Ikst.MouseHook.MouseHook] $mh
    [System.Windows.Forms.ListView] $list

    InputRecorder([System.Windows.Forms.ListView]$targetListView) {
        $this.list = $targetListView
        $this.kh = New-Object KeyboardHookExample.KeyboardHook
        $this.mh = New-Object Ikst.MouseHook.MouseHook

        # 定义KeyDown事件处理器,使用$using:捕获当前实例
        $this.kh.add_KeyDown({
            param($sender, $e)
            $vkCode = $sender.vkCode
            Write-Host $vkCode
            if ($vkCode -eq 115) {
                if ($using:this.kh) {
                    $using:this.kh.Stop()
                }
                if ($using:this.mh) {
                    $using:this.mh.Stop()
                }
            }

            $charCode = [Win32.NativeMethods]::MapVirtualKey($vkCode, 2)
            $char = [char]$charCode
            Write-Host $char
        })

        # 定义LeftButtonDown事件处理器
        $this.mh.add_LeftButtonDown({
            param($sender, $e)
            $mousePosition = $sender.pt
            $y = $mousePosition.y
            $x = $mousePosition.x
            $item = New-Object System.Windows.Forms.ListViewItem
            $item.ToolTipText = $global:dict["LeftClickCode"] -f $x, $y
            $item.Text = $global:dict["LeftClickDescription"] -f $x, $y
            $using:this.list.Items.Add($item)
        })

        # 启动钩子
        $this.kh.Start()
        $this.mh.Start()
    }

    [System.Windows.Forms.ListView] getList() {
        # 修正原方法返回类型与实际对象不匹配的问题
        return $this.list
    }

    [void] StopHooks() {
        if ($this.mh) {
            $this.mh.Stop()
        }
        if ($this.kh) {
            $this.kh.Stop()
        }
    }
}

额外注意事项

  • 确保KeyboardHookExample.KeyboardHook和Ikst.MouseHook.MouseHook类的Stop()方法实现正确,不会提前释放对象资源。
  • 构造函数新增ListView参数,确保控件引用正确传入,避免依赖全局变量。

内容的提问来源于stack exchange,提问作者pfeidewigo100

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 21:43:35