Как установить приоритетное окно из действия подписчика событий Powershell - PullRequest
3 голосов
/ 01 апреля 2010

У меня есть экземпляр FileSystemWatcher , работающий в фоновом режиме моего сеанса PoSh, отслеживающий изменения в текстовых файлах. Подписчик на событие PoSh присоединяется к этому событию и при запуске запускает консольную программу, вызывая Start-Process . Эта программа крадет фокус из текущего окна переднего плана (моя консоль PoSh). Вызов SetForegroundWindow от подписчика события PoSh для возврата фокуса на мою консоль PoSh не работает. SwitchToThisWindow работает большую часть времени , но, согласно документам MSDN, его не следует использовать.

Могу ли я предотвратить Start-Process от кражи фокуса в этой ситуации или вернуть его обратно от подписчика события к окну, в котором он находился до запуска этого события?

Ответы [ 3 ]

13 голосов
/ 01 апреля 2010

Для меня 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 о Процесс Класс

1 голос
/ 05 августа 2010

Похоже, это не сработало, потому что вы установили фокус, прежде чем потеряли фокус.

Вы пытались настроить фокус на работе? Он работает в фоновом режиме, пока вы используете консоль.

Нечто подобное может сработать, оно удерживает ваш фокус на 10 секунд после события

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

Если вы микшируете в GetForegroundWindow, вы можете подождать, пока не потеряете фокус, а затем вернуть его обратно

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

0 голосов
/ 12 апреля 2016

Взяв мою реплику от ответа @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
...