SSブログ

PowerShell小僧:PowerShellのWindowを最前面に移動する [コンピューター]

Read-Hostコマンドレットなど、入力が必要となる場面でPowerShellのWindowを最前面に移動するには、どうするのか調べていたら、

Powershellでのアクティブウィンドウ切り替え
https://teratail.com/questions/329291

にあったコードを一部変更することで実現出来ました。

以下、そのコードです。

※なお、このコードを関数化して、別ファイルに保存して呼び出そうとするとエラーで上手くいきませんでした。理由は不明。
※$ps = Get-Process | Where-Object {$_.Name -match "pwsh"}の"pwsh"を変更すると最前面に移動するWindowを変更できます。

add-type -AssemblyName microsoft.VisualBasic
add-type -AssemblyName System.Windows.Forms


$cscode = @"
public static void ActiveWindow(IntPtr hWnd)
{
    if (hWnd == IntPtr.Zero)
    {
        return;
    }

    //ウィンドウが最小化されている場合は元に戻す
    if (IsIconic(hWnd))
    {
        ShowWindowAsync(hWnd, SW_RESTORE);
    }

    //AttachThreadInputの準備
    //フォアグラウンドウィンドウのハンドルを取得
    IntPtr forehWnd=GetForegroundWindow();
    if (forehWnd == hWnd)
    {
        return;
    }
    //フォアグラウンドのスレッドIDを取得
    uint foreThread = GetWindowThreadProcessId(forehWnd, IntPtr.Zero);
    //自分のスレッドIDを収得
    uint thisThread = GetCurrentThreadId();

    uint timeout = 200000;
    if (foreThread != thisThread)
    {
        //ForegroundLockTimeoutの現在の設定を取得
        //Visual Studio 2010, 2012起動後は、レジストリと違う値を返す
        SystemParametersInfoGet(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, ref timeout, 0);
        //レジストリから取得する場合
        //timeout = (uint)Microsoft.Win32.Registry.GetValue(
        // @"HKEY_CURRENT_USER\Control Panel\Desktop",
        // "ForegroundLockTimeout", 200000);

        //ForegroundLockTimeoutの値を0にする
        //(SPIF_UPDATEINIFILE | SPIF_SENDCHANGE)を使いたいが、
        // timeoutがレジストリと違う値だと戻せなくなるので使わない
        SystemParametersInfoSet(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, 0);

        //入力処理機構にアタッチする
        AttachThreadInput(thisThread, foreThread, true);
    }

    //ウィンドウをフォアグラウンドにする処理
    SetForegroundWindow(hWnd);
    SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,
        SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS);
    BringWindowToTop(hWnd);
    ShowWindowAsync(hWnd, SW_SHOW);
    SetFocus(hWnd);

    if (foreThread != thisThread)
    {
        //ForegroundLockTimeoutの値を元に戻す
        //ここでも(SPIF_UPDATEINIFILE | SPIF_SENDCHANGE)は使わない
        SystemParametersInfoSet(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, timeout, 0);

        //デタッチ
        AttachThreadInput(thisThread, foreThread, false);
    }
}

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BringWindowToTop(IntPtr hWnd);

[DllImport("user32.dll")]
static extern IntPtr SetFocus(IntPtr hWnd);

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWindowPos(IntPtr hWnd,
    int hWndInsertAfter, int x, int y, int cx, int cy, int uFlags);

private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOMOVE = 0x0002;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_SHOWWINDOW = 0x0040;
private const int SWP_ASYNCWINDOWPOS = 0x4000;
private const int HWND_TOP = 0;
private const int HWND_BOTTOM = 1;
private const int HWND_TOPMOST = -1;
private const int HWND_NOTOPMOST = -2;

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);

private const int SW_SHOWNORMAL = 1;
private const int SW_SHOW = 5;
private const int SW_RESTORE = 9;

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsIconic(IntPtr hWnd);

[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(
    IntPtr hWnd, IntPtr ProcessId);

[DllImport("kernel32.dll")]
private static extern uint GetCurrentThreadId();

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AttachThreadInput(
    uint idAttach, uint idAttachTo, bool fAttach);

[DllImport("user32.dll", EntryPoint = "SystemParametersInfo",
    SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SystemParametersInfoGet(
    uint action, uint param, ref uint vparam, uint init);

[DllImport("user32.dll", EntryPoint = "SystemParametersInfo",
    SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SystemParametersInfoSet(
    uint action, uint param, uint vparam, uint init);

private const uint SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000;
private const uint SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001;
private const uint SPIF_UPDATEINIFILE = 0x01;
private const uint SPIF_SENDCHANGE = 0x02;
"@

$Win32 = add-type -memberDefinition $cscode -name "Win32ApiFunctions" -passthru

$ps = Get-Process | Where-Object {$_.Name -match "pwsh"}
foreach($process in $ps){
  if($process.MainWindowTitle -ne "") {
    write-host "`$process.ID="$process.ID
    write-host "`$process.MainWindowTitle="$process.MainWindowTitle
    $Win32::ActiveWindow($process.MainWindowHandle);
  }
}

#Start-Sleep -s 30

#$ps = Get-Process | Where-Object {$_.Name -match "cmd"}
#foreach($process in $ps){
#$Win32::ActiveWindow($process.MainWindowHandle);
#}
ヤバイぜ!(13)  コメント(1) 
共通テーマ:パソコン・インターネット

ヤバイぜ! 13

コメント 1

cheese999

ヤバイぜ! ありがとうございます(^_0)ノ

何回かテストしたのですが、上手くいくときと、上手くいかないときがあります。原因ふめい...
by cheese999 (2022-08-27 09:49) 

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字(英大文字の「オー」、英小文字の「ユー」、アラビア数字の「ハチ」、アラビア数字の「イチ」、アラビア数字の「ニ」)を入力してください。

Facebook コメント

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。