无法停止powershell中的低级钩子(c#钩子)

问题描述 投票:0回答:1

在与 chat gpt 和 bing chat 争论了一晚之后,我现在转向(希望)stackoverflow 上更聪明的人。我的问题是这样的:我在 C# 中实现了低级挂钩。我订阅 powershell 类中的事件,然后在 GUI 中使用该事件。订阅事件并启动挂钩工作得很好,但是,我无法从我的类或 GUI 程序中停止挂钩。目前我在想,每当我按“f4”时,挂钩应该停止,但我不断收到“无法在空值表达式上调用方法”,而且我真的不明白为什么它会是空值或如何我会解决它。这是我的代码,我认为没有必要展示钩子或 GUI 的实现,但请让我知道其他情况。

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

    InputRecorder() {
        $this.kh = New-Object KeyboardHookExample.KeyboardHook
        $this.mh = New-Object Ikst.MouseHook.MouseHook

        # Store the reference to the class instance
        $self = $this

        # Define the event handler for KeyDown
        $self.kh.add_KeyDown({
            param($sender, $e)
            $vkCode = $sender.vkCode
            Write-Host $vkCode
            if ($vkCode -eq 115) {
                $self.kh.Stop()
                $self.mh.Stop()
            }

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

            Write-Host $char
        })

        # Define the event handler for LeftButtonDown
        $self.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
            $CMDList.Items.Add($item)
        })

        # Start the keyboard and mouse hooks
        $self.kh.Start()
        $self.mh.Start()
    }
    [System.Collections.Concurrent.ConcurrentBag[string]] getList() {
        return $this.list
    }

    [void] StopHooks() {
        $this.mh.Stop()
        $this.kh.Stop()
    }
}
c# powershell hook low-level
1个回答
0
投票

虽然期望 PowerShell 的动态范围也适用于 PowerShell 的自定义

class
内是可以理解的,但事实并非如此: 一个

脚本块

作为事件委托传递到.NET方法从类内部:

    不会
  • 看到封闭方法

    的局部变量 - 除非您通过在脚本块上调用.GetNewClosure()来显式捕获它们。

    在没有.GetNewClosure()

    的情况下,它
      所做的
    • 看到的是来自类定义范围的变量,即那些在类的
      外部
      定义的变量,在定义类的范围内(并且来自该范围的祖先)范围),因为它在 that 范围的子范围中运行。
    • 确实
  • $this

    视为指代自身,因为不幸的是,事件委托中的

    自动
    $this变量阴影
    class
    $this级定义,而是指代
    事件发送者
    
    并且由于类内部使用$this

    是访问类的
      实例变量
    • (属性)的唯一方法,因此后者也被隐藏了。
      
      
      
      
    • 有两种解决方案:

每种方法
    为基础(使您的尝试发挥作用):
  • 定义方法局部变量,例如

    $self
      ,然后在从同一方法
    • 传递到 .NET 方法的每个事件委托脚本块上调用

      .GetNewClosure()

      ,这允许您访问该脚本中的方法局部变量块。
      但是,请注意,.GetNewClosure()

      将使您的脚本块无法访问类定义范围中的变量。
    • 最好以
    为基础:
  • 使用 (Get-Variable -Scope 1 -ValueOnly this)

    来访问手头的类实例,即
      $this
    • shadowed
      版本
      这消除了对特定于方法的逻辑的需要,并且还保留了对类定义范围中的变量的访问(如果需要)。

© www.soinside.com 2019 - 2024. All rights reserved.