Вопрос был задан на форуме OsZone.Net в теме «PowerShell — Закрытие всех окон приложений кроме активного« . Был предложен вариант с ярлыком, но возникла проблема, при нажатии hotkey — фокус приложения переключался на другое приложение.
Что нам потребуется:
- WASP — Windows Automation Snapin for PowerShell
- PowerShell V2 и выше
- .NET Framework 3.5
Основная проблема – это работа с hotkey. Идея работы позаимствована у Hans Passant’a — How to prevent my C# winforms application from stealing focus when I set the visible properly to true?
Схема скрипта:
- Функция RegisterHotKey — определяет комбинацию «горячая» клавиша для текущего потока
RegisterHotKey(this.Handle, MYKEYID, MOD_CONTROL + MOD_SHIFT, Keys.U);
- this.Handle — Идентификатор окна нашей формы,которое принимает сообщение WM_HOTKEY
- MYKEYID — Определяет идентификатор комбинации
- MOD_CONTROL + MOD_SHIFT — Определяет клавиши, которые должны быть нажаты в комбинации с клавишей, заданной параметром vk, чтобы генерировать сообщение WM_HOTKEY. Параметр modifiers может быть комбинацией следующих значений:
- MOD_ALT — Любая клавиша ALT должна удерживаться нажатой.
- MOD_CONTROL — Любая клавиша CTRL должна удерживаться нажатой.
- MOD_SHIFT — Любая клавиша SHIFT должна удерживаться нажатой.
- Keys.U — Определяет код виртуальной клавиши комбинации «горячая» клавиша.
В данном примере комбинация будет CTRL+Shift + U
- Функция UnregisterHotKey — освобождает комбинацию «горячая» клавиша, предварительно зарегистрированную вызывающим потоком
UnregisterHotKey(this.Handle, MYKEYID);
- this.Handle — Идентификатор окна нашей формы,которое принимает сообщение WM_HOTKEY
- MYKEYID — Определяет идентификатор комбинации
Вызывается при закрытии формы
- Для обработки сообщений операционной системы в нашей форме, потребуется переопределить метод WndProc.
- if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == MYKEYID) { – Производим проверку на получение сочетания CTRL+Shift +
- Вызов скрипта PowerShell — How to run PowerShell scripts from C#
- Import-Module -Name Wasp\r\nSelect-Window | Where-Object { -not $_.IsActive} | Remove-Window
- Import-Module -Name Wasp – Импортирует модуль WASP (не обязательно для PowerShell V3, но с учетом того,что переменная $PSModuleAutoloadingPreference не None)
- Select-Window – Получаем список окон
- Where-Object { -not $_.IsActive} – Отфильтровываем все кроме активного
- Remove-Window – Закрываем окна
- Function OnLoad – Определяем свойства для запуска формы в скрытом режиме
- Function OnClick – При нажатии на кнопку меню Exit – закрываем форму
- Создаем значок в трее и определяем меню Exit
- Запуск формы
$ActiveWindow = @' using System; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Management.Automation; using System.Management.Automation.Runspaces; namespace WindowsApplication1 { public partial class Form1 : Form { private const int MYKEYID = 0; public Form1() { RegisterHotKey(this.Handle, MYKEYID, MOD_CONTROL + MOD_SHIFT, Keys.U); this.FormClosing += Form1_FormClosing; } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { UnregisterHotKey(this.Handle, MYKEYID); } protected override void SetVisibleCore(bool value) { base.SetVisibleCore(false); } protected override void WndProc(ref Message m) { if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == MYKEYID) { // create Powershell runspace Runspace runspace = RunspaceFactory.CreateRunspace(); // open it runspace.Open(); // create a pipeline and feed it the script text string scriptText = "Import-Module -Name Wasp\r\nSelect-Window | Where-Object { -not $_.IsActive} | Remove-Window"; Pipeline pipeline = runspace.CreatePipeline(); pipeline.Commands.AddScript(scriptText); // execute the script pipeline.Invoke(); // close the runspace runspace.Close(); } base.WndProc(ref m); } // P/Invoke declarations private const int WM_HOTKEY = 0x312; private const int MOD_ALT = 1; private const int MOD_CONTROL = 2; private const int MOD_SHIFT = 4; [DllImport("user32.dll")] private static extern int RegisterHotKey(IntPtr hWnd, int id, int modifier, Keys vk); [DllImport("user32.dll")] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); } } '@ Function OnLoad { $form.Visible = $false $form.ShowInTaskbar = $false } Function OnClick { $trayIcon.Visible = $False $form.close() } Add-Type -TypeDefinition $ActiveWindow -ReferencedAssemblies System.Windows.Forms Add-Type -AssemblyName System.Drawing $trayIcon = New-Object System.Windows.Forms.NotifyIcon $trayMenu = New-Object System.Windows.Forms.ContextMenu $menuExit = New-Object System.Windows.Forms.MenuItem $form = New-Object WindowsApplication1.Form1 $trayIcon.Icon = [System.Drawing.SystemIcons]::Information $trayIcon.ContextMenu = $trayMenu $menuExit.Text = "Exit" $menuExit.Add_Click({OnClick}) $trayMenu.MenuItems.AddRange(@($menuExit)) $form.Add_Load({OnLoad}) $trayIcon.Visible = $true [Windows.Forms.Application]::Run($form)
Запуск скрипта:
Powershell –WindowStyle Hidden –File «C:\Script\Close-InactiveWindow.ps1»
Выход: