前回はPowerShellからWindows APIを使用する方法を紹介した。基本的な部分のみを取り上げたが、それだけでも結構いろいろとできるようになったはずだ。今回はこの機能を使って、アプリケーションの座標データを取得し、さらにその座標データを変更して表示場所やサイズを変更する方法を紹介する。

必要になるWindows APIを絞り込む

今回は次のスクリプトを参考にして説明を行っている。


上記スクリプトでは、user32.dllを読み込んで、次の3つの関数を利用している。

  • GetWindowRect()
  • GetClientRect()
  • MoveWindow()


GetWindowRect()とGetClientRect()は似たような動作をする。アプリケーションウインドウの座標データ(左上X座標、左上Y座標、右下X座標、右下Y座標)を得るための関数だ。しかし、対象が異なっている。GetWindowRect()はタイトルバーといった装飾も含めたウインドウの座標データ、GetClientRect()はタイトルバーといった装飾を抜いた中身だけの座標データだ。

ここではウインドウのタイトルバーも含めてサイズを変更できればよいので、GetWindowRect()を使えばよい。MoveWindow()はウィンドウを指定した座標(左上X座標、左上Y座標、幅、高さ)に設定する関数だ。つまり、次の2つの関数を使えばよいことになる。


この2つの関数のシンタックスは、上記マニュアルによればそれぞれ次の通りだ。

GetWindowRect function (winuser.h)

BOOL GetWindowRect(
  HWND   hWnd,
  LPRECT lpRect
);

MoveWindow function (winuser.h)

BOOL MoveWindow(
  HWND hWnd,
  int  X,
  int  Y,
  int  nWidth,
  int  nHeight,
  BOOL bRepaint
);

前回の方法に倣って、この2つの関数を使えるようにしてみよう。

PowerShellから使えるように「Add-Type」で整える

先ほどの2つの関数をPowerShellから扱えるようにAdd-Typeコマンドレットで整理すると次のようになる。

Add-Type @"
using System;
using System.Runtime.InteropServices;

public struct RECT
{
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
}

public class WinAPI
{
        // ウインドウの現在の座標データを取得する関数
        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

        // ウインドウの座標を変更する関数
        [DllImport("user32.dll")]
        public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
}
"@

前回との違いは、Add-Typeコマンドレットの中で「RECT」という構造体を定義していることだ。GetWindowRect()関数が「RECT」という構造体を使うので、これを上記のように書いておく必要がある。詳しい説明は省くが、現時点では、こうやって書くものだと思っておいてもらえればと思う。

用意したWindows APIを使用する

Add-Typeコマンドレットで整理した関数は、次のように使うことになる。

# ウインドウ座標データ構造体
$rc = New-Object RECT

# ウインドウの現在の座標データを取得
[WinAPI]::GetWindowRect(ウインドウハンドラ, [ref]$rc)

# 左上の場所はそのままに、ウインドウのサイズを変更
[WinAPI]::MoveWindow(ウインドウハンドラ, $rc.Left, $rc.Top, 幅, 高さ, $true)

ウインドウの左上の位置は変えることなく縦と横のサイズを調整したい。これはウインドウの右下をマウスやタッチパッドで掴んでウインドウサイズを変更する操作と同じだ。このため、対象となるアプリケーションの座標データを最初に得て、左上の座標を知る必要があるのだ。

まず、座標データを格納する構造体をオブジェクトとして生成する。次に、[WinAPI]::GetWindowRect関数を呼び出す。この処理でRECTのオブジェクトである$rcに座標データが格納される。次に[WinAPI]::MoveWindow関数で、先ほど取得した左上の座標データと、目的とする幅と高さを指定すれば、対象とするアプリケーションのサイズが良い具合に変更されるというわけだ。

window_resizer.ps1 ver.2

今回の内容をPowerShellスクリプトにまとめてみよう。動作が確認できればよいので、対象とするアプリケーションやウインドウサイズはスクリプトに直接書いておく。対象となるアプリケーションのプロセスを特定する方法は、前々回にまとめた内容をそのまま使う。整理すると次のようになる。

window_resizer.ps1

Add-Type @"
using System;
using System.Runtime.InteropServices;

public struct RECT
{
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
}

public class WinAPI
{
        // ウインドウの現在の座標データを取得する関数
        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

        // ウインドウの座標を変更する関数
        [DllImport("user32.dll")]
        public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
}
"@

$processName="msedge"
$windowTitle=".*"
$width="1200"
$height="1200"

Get-Process -Name $processName |
        ? { $_.MainWindowHandle -ne 0 } |
        ? { $_.MainWindowTitle -match "$windowTitle" } |
        % {
                # ウインドウ座標データ構造体
                $rc = New-Object RECT

                # ウインドウの現在の座標データを取得
                [WinAPI]::GetWindowRect($_.MainWindowHandle, [ref]$rc)

                # 左上の場所はそのままに、ウインドウのサイズを変更
                [WinAPI]::MoveWindow($_.MainWindowHandle, $rc.Left, $rc.Top, $width, $height, $true)
}

スクリプトに直接書いたサイズを書き変えながらスクリプトを実行してみると、次の結果が得られる。

Microsoft Edge 1200x1200

Microsoft Edge 1200x1000

Microsoft Edge 1200x800

Microsoft Edge 1200x600

かなり想定した挙動に近づいてきた感じだ。

PowerShellスクリプトで生産効率を引き上げよう

アプリケーションのウインドウサイズを変更するスクリプトの本質となる処理は、今回のスクリプトがほぼ押さえている。さらに何かやるとすれば、このスクリプトをもう少し汎用的に扱えるように整えたり、ちょっと機能拡張を行ったりするくらいだ。

整えたPowerShellスクリプトは、環境変数PATHの通ったフォルダに置いておけば、コマンドやコマンドレットのように扱うことができる。ほかのスクリプトやバッチファイルから呼び出すことも可能だ。こうした”ちょっと便利なスクリプト”を積み上げていくことで、これまで手動で行っていた操作を少しずつだが自動化していくことができるのだ。一つ一つで得られる時短効果はごくわずかかもしれないが、これが積み重なると結構大きな違いになってくる。コツコツ便利なスクリプトを作成して、操作効率を引き上げていこう。