【问题标题】:Strange function call behavior with respect to .NET events关于 .NET 事件的奇怪函数调用行为
【发布时间】:2014-08-17 16:59:59
【问题描述】:

当点击通知图标时,下面的代码会正确显示一个消息框。

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

$NotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$NotifyIcon.Icon = New-Object System.Drawing.Icon(Join-Path $PSScriptRoot "icon.ico")
$NotifyIcon.Visible = $True

Register-ObjectEvent -InputObject $NotifyIcon -EventName Click -Action {
    Write-Host "Callback called."
    [System.Windows.Forms.MessageBox]::Show("Test") 
}

(如果没有正确指定的图标文件,程序将无法运行。例如,您可以下载一个图标here。)

如果我将显示消息框的行移到函数中,代码将无法显示该消息框:

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

function Do-Something {
    Write-Host "Do-Something called."
    [System.Windows.Forms.MessageBox]::Show("Test") 
}

$NotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$NotifyIcon.Icon = New-Object System.Drawing.Icon(Join-Path $PSScriptRoot "icon.ico")
$NotifyIcon.Visible = $True

Register-ObjectEvent -InputObject $NotifyIcon -EventName Click -Action {
    Write-Host "Callback called."
    Do-Something
}

第一个奇怪的方面是第二个代码将Callback called 写入控制台——但只有一次。一键后不再打印任何调试信息。

我使用powershell.exe 运行这两个脚本并输入./script[1|2].ps1。 (我不建议同时运行这两个脚本,因为它们使用相同的图标。关闭 PowerShell 窗口会终止脚本并删除图标资源。但是,图标会一直存在,直到您将鼠标移到它上面。)

通过 Windows PowerShell ISE 运行脚本时出现了第二个奇怪的事实:它们都像魅力一样工作。

尝试在第二个脚本的回调处理程序的两行中设置断点对我不起作用。 PowerShell ISE 总是在执行这些行时发出警告:

PS P:\...> WARNUNG: Haltepunkt Zeilenhaltepunkt bei "P:\...\script.ps1:13" wird nicht erreicht.
Callback called.
WARNUNG: Haltepunkt Zeilenhaltepunkt bei "P:\...\script.ps1:14" wird nicht erreicht.
Do-Something called.

Translation from German into English:

PS P:\...> WARNING: Breakpoint line breakpoint at "P:\...\script.ps1:13" doesn't get reached.
Callback called.
WARNING: Breakpoint line breakpoint at "P:\...\script.ps1:14" doesn't get reached.
Do-Something called.

尝试调试第一个脚本时也会出现同样的问题。

在 Internet 上搜索该问题非常困难。我尝试了powershell net callback called once(以及其他),但找不到任何东西。

【问题讨论】:

  • 我总是在 ISE 中遇到测试问题,因为脚本和运行变量的代码在会话没有终止时得到维护。另外,也许您遇到了范围问题?
  • @Matt 事实上,我也观察到了这种行为。因此,每次我想再次测试脚本时,我都会重新启动 ISE。您提到的范围问题让我重新研究了该主题并导致了解决方案(我将发布)。谢谢!

标签: powershell system-tray trayicon


【解决方案1】:

问题

Do-Something 无法调用的问题是由于范围问题,我想。由于Register-ObjectEvent 在提供操作时会返回一个事件作业,我认为操作块的执行就像jobs, which run in a different PowerShell process 一样。

另一个支持论点是调用Do-SomethingXYZ(显然不存在)不会引发任何(可见?)错误。

我的解决方案

欢迎提出更多惯用解决方案的建议!

  1. 使用MessageData parameter of Register-ObjectEvent 解决范围问题。

  2. Use ${function:xyz} to pass a function as a parameter.

  3. 使用$Event.MessageData.Invoke()调用函数。

代码:

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

function Do-Something {
    Write-Host "Do-Something called."
    [System.Windows.Forms.MessageBox]::Show("Test") 
}

$NotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$NotifyIcon.Icon = New-Object System.Drawing.Icon(Join-Path $PSScriptRoot "icon.ico")
$NotifyIcon.Visible = $True

Register-ObjectEvent -MessageData ${function:Do-Something} -InputObject $NotifyIcon -EventName Click -Action {
    Write-Host "Callback called."
    $Event.MessageData.Invoke()
}

进一步的cmets

第一个奇怪的方面:Callback called 只有一次?

第一个奇怪的方面是第二个代码将Callback called 写入控制台——但只有一次。一键后不再打印任何调试信息。

— ComFreek(在问题中)

代码如下:

Write-Host "Callback called."
Do-Something

我承认,调试消息有点误导。在通过Write-Host 编写消息时,尚未调用Do-Something。由于 PowerShell 无法解析 Do-Something,因此它会静默失败。这可能是致命的,足以停止第二次调用由Register-ObjectEvent 注册的动作处理程序。因此,调试信息只出现一次。

第二个奇怪的方面:为什么这两个脚本都适用于 PowerShell ISE?

这个问题还没有完全解决,但我可能只是补充一下我目前观察到的信息。

这个程序就像一个REPL(读取-评估-打印循环),配备了许多有用的功能。关键是它只使用一个 PowerShell 会话。 您可以通过运行包含$a = "Hello" 的脚本来观察该行为,清除文件,然后通过运行$a 输出值。所有对象(变量、函数等)都保持活动状态,并与其他脚本执行共享相同的范围。

未决问题/您可能会考虑的问题

  1. 为什么调用动作处理程序中的未知函数时 PowerShell 不抛出错误?
    是否有类似错误级别的东西限制某些类型的错误被显示?

    -ErrorAction stop 传递给Register-ObjectEvent 没有帮助。

  2. 为什么断点显然是not get reachted,但它们关联的行却被执行了?

非常欢迎这些问题的答案或 cmets :)

【讨论】:

    猜你喜欢
    • 2013-03-16
    • 2015-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多