3

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

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

4

3 回答 3

13

对我来说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).MainWindowHandle您将需要[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类的文档中获取和更改的示例

于 2010-04-01T13:05:18.797 回答
1

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

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

像这样的东西可能会起作用,它可以让你在活动结束后保持注意力 10 秒

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

如果你混入GetForegroundWindow,你可以等到失去焦点,然后再把它拿回来

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

于 2010-08-05T19:27:39.303 回答
0

当我发现这个问题时从上面的@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
于 2016-04-12T13:48:46.460 回答