如何从 Powershell 事件订阅者操作​​设置前台窗口

发布于 2024-08-27 20:06:19 字数 410 浏览 21 评论 0原文

我有一个 FileSystemWatcher 实例在我的 PoSh 会话后台运行,监视文本文件的更改。 PoSh 事件订阅者附加到此事件,并且在触发时,它通过调用 Start-Process 启动控制台程序。该程序从当前前台窗口(我的 PoSh 控制台)窃取焦点。从 PoSh 事件订阅者调用 SetForegroundWindow 将焦点返回到我的 PoSh 控制台不起作用。 SwitchToThisWindow大部分时间确实有效,但根据 MSDN 文档,不应使用它。

在这种情况下,我可以防止 Start-Process 窃取焦点,或者将其从事件订阅者设置回在该事件触发之前拥有焦点的窗口吗?

I have a FileSystemWatcher instance running in the background of my PoSh session watching for changes to text files. A PoSh event subscriber is attached to this event and, when fired, it launches a console program by calling Start-Process. This program steals de focus from the current foreground window (my PoSh console). Calling SetForegroundWindow from the PoSh event subscriber to return the focus to my PoSh console doesn't work. SwitchToThisWindow does work most of the time, but according to the MSDN docs, it shoulnd't be used.

Can I prevent Start-Process from stealing the focus in this situation or set it back from the event subscriber to the window that had it before this event is fired?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

美男兮 2024-09-03 20:06:19

对我来说 SetForegroundWindow 效果很好。检查此代码:

Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class Tricks {
     [DllImport("user32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool SetForegroundWindow(IntPtr hWnd);
  }
"@
sleep -sec 2
$h = (Get-Process firefox).MainWindowHandle
[void] [Tricks]::SetForegroundWindow($h)
sleep -sec 2
$h = (Get-Process -id $pid).MainWindowHandle
[void] [Tricks]::SetForegroundWindow($h)

但请注意,如果您托管 PowerShell 或使用例如控制台 (http://sourceforge.net/projects/ console/) 那么 MainWindowHandle 就是你的主机程序的句柄。
因此,您需要的不是 (Get-Process -id $pid).Ma​​inWindowHandle,而是需要 [tricks]::SetForegroundWindow((Get-Process console).MainWindowHandle)

计时器事件示例:

$timer = New-Object Timers.Timer
$timer.Interval = 5000
$h = (Get-Process -id $pid).MainWindowHandle
$action = { 
    notepad; 
    sleep -sec 1;  # wait until the program starts (very simple approach)
    [Tricks]::SetForegroundWindow($h) }
Register-ObjectEvent $timer Elapsed -Action $action
$timer.Start()

否则,如果您运行隐藏窗口的进程,它可以解决您的问题。

$ps = new-object system.diagnostics.processstartinfo 'notepad'
$ps.windowStyle = 'hidden'
[system.diagnostics.process]::Start($ps)

从 msdn 上有关 Process 类的文档中获取并更改的示例

For me SetForegroundWindow works well. Check this code:

Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class Tricks {
     [DllImport("user32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool SetForegroundWindow(IntPtr hWnd);
  }
"@
sleep -sec 2
$h = (Get-Process firefox).MainWindowHandle
[void] [Tricks]::SetForegroundWindow($h)
sleep -sec 2
$h = (Get-Process -id $pid).MainWindowHandle
[void] [Tricks]::SetForegroundWindow($h)

But note that if you host PowerShell or use e.g. Console (http://sourceforge.net/projects/console/) then MainWindowHandle is the handle of your host program.
So instead of (Get-Process -id $pid).MainWindowHandle you would need [tricks]::SetForegroundWindow((Get-Process console).MainWindowHandle).

Example with timer event:

$timer = New-Object Timers.Timer
$timer.Interval = 5000
$h = (Get-Process -id $pid).MainWindowHandle
$action = { 
    notepad; 
    sleep -sec 1;  # wait until the program starts (very simple approach)
    [Tricks]::SetForegroundWindow($h) }
Register-ObjectEvent $timer Elapsed -Action $action
$timer.Start()

Otherwise if you run process that has its window hidden, it could solve your problem.

$ps = new-object system.diagnostics.processstartinfo 'notepad'
$ps.windowStyle = 'hidden'
[system.diagnostics.process]::Start($ps)

Example taken and altered from documentation on msdn about Process class

迷荒 2024-09-03 20:06:19

听起来它不起作用,因为你在失去焦点之前就设置了焦点。

您是否尝试过通过工作来集中注意力?当您使用控制台时,它在后台运行。

像这样的东西可能会起作用,它会在事件发生后让你的焦点保持10秒

Start-Job -ScriptBlock {
    1..100 | %{
        sleep -Milliseconds 100
        #Set focus back
    }
}

如果你混合在GetForegroundWindow中,你可以等到你失去焦点,然后把它抓回来

http://www.leeholmes.com/blog/MorePInvokeInPowerShell.aspx

It sounds like it didnt work because you set focus, before you lost focus.

Have you tried setting focus through a job? It runs in the background while you use the console.

Something like this might work, it keeps your focus for 10 seconds after the event

Start-Job -ScriptBlock {
    1..100 | %{
        sleep -Milliseconds 100
        #Set focus back
    }
}

If you mix in GetForegroundWindow, you can wait till you lose focus, then grab it back

http://www.leeholmes.com/blog/MorePInvokeInPowerShell.aspx

乙白 2024-09-03 20:06:19

当我发现这个问题时,我从上面的 @stej 答案中得到提示,因为我试图做同样的事情,我扩展以生成此代码,这将使脚本重新成为焦点,无论是在 ISE、控制台窗口还是通过cmd 提示符(通过批处理文件)。

#bring script back into focus
Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class Tricks {
     [DllImport("user32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool SetForegroundWindow(IntPtr hWnd);
  }
"@

$parent = Get-Process -id ((gwmi win32_process -Filter "processid='$pid'").parentprocessid)
If ($parent.Name -eq "cmd") {# Being run by via cmd prompt (batch file)
    $h = (Get-Process cmd).MainWindowHandle
    [void] [Tricks]::SetForegroundWindow($h)
    }
    else{# being run in powershell ISE or console
          $h = (Get-Process -id $pid).MainWindowHandle
          [void] [Tricks]::SetForegroundWindow($h)
    } 

或者为了更容易地重复使用,请将以下内容保存为模块目录中的 .psm1 文件 - 从 PS v3 开始,您不必导入它,调用模块目录中模块中的函数即可导入它。

要手动导入,Import-Module .\Getfocus.psm1(假设它位于您当前的路径中)。

Function Get-Focus{
#bring script back into focus
Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class Tricks {
     [DllImport("user32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool SetForegroundWindow(IntPtr hWnd);
  }
"@

$parent = Get-Process -id ((gwmi win32_process -Filter "processid='$pid'").parentprocessid)
If ($parent.Name -eq "cmd") {# Being run by via cmd prompt (batch file)
    $h = (Get-Process cmd).MainWindowHandle
    [void] [Tricks]::SetForegroundWindow($h)
    }
    else{# being run in powershell ISE or console
          $h = (Get-Process -id $pid).MainWindowHandle
          [void] [Tricks]::SetForegroundWindow($h)
    }
} 

Export-ModuleMember -Function Get-Focus

Taking my cue from @stej answer above when I found this question because I was trying to do the same thing, I expanded to produce this code, which will bring the script back into focus whether being run in the ISE, console window, or via cmd prompt (through a batch file).

#bring script back into focus
Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class Tricks {
     [DllImport("user32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool SetForegroundWindow(IntPtr hWnd);
  }
"@

$parent = Get-Process -id ((gwmi win32_process -Filter "processid='$pid'").parentprocessid)
If ($parent.Name -eq "cmd") {# Being run by via cmd prompt (batch file)
    $h = (Get-Process cmd).MainWindowHandle
    [void] [Tricks]::SetForegroundWindow($h)
    }
    else{# being run in powershell ISE or console
          $h = (Get-Process -id $pid).MainWindowHandle
          [void] [Tricks]::SetForegroundWindow($h)
    } 

Or to re-use more readily, save the following as a .psm1 file in your module directory - from PS v3 onwards, you don't have to import it, calling a function in a module in your module directory imports it.

To import manually, Import-Module .\Getfocus.psm1 (Assuming it's in your current path).

Function Get-Focus{
#bring script back into focus
Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class Tricks {
     [DllImport("user32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool SetForegroundWindow(IntPtr hWnd);
  }
"@

$parent = Get-Process -id ((gwmi win32_process -Filter "processid='$pid'").parentprocessid)
If ($parent.Name -eq "cmd") {# Being run by via cmd prompt (batch file)
    $h = (Get-Process cmd).MainWindowHandle
    [void] [Tricks]::SetForegroundWindow($h)
    }
    else{# being run in powershell ISE or console
          $h = (Get-Process -id $pid).MainWindowHandle
          [void] [Tricks]::SetForegroundWindow($h)
    }
} 

Export-ModuleMember -Function Get-Focus
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文