この前出した「ぷるまど」の内部実装の話。
やっぱWinAPIだよね
他のアプリケーションを操作する場合、基本的にはウィンドウハンドルをどうやって取得するか、という問題に絞られます。
プロセスが分かっている場合はもちろんプロセスから攻めるわけですが、今回は「ウィンドウ」があるものをを取得したい。
というわけで、それを取得するAPIがEnumWindowsです。
[DllImport("user32")]
public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, IntPtr lParam);
[DllImport("user32")]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("USER32.DLL", SetLastError = true)]
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId);
}
みたいな感じでテキトーに定義して、EnumWindowsを呼び出してくるくる回せば色々できます。
WinAPI.EnumWindows((h, i) =>
{
if (WinAPI.IsWindowVisible(h))
{
WinAPI.GetWindowThreadProcessId(h,out int id);
result.Add((h, Process.GetProcessById(id).ProcessName)); //このresultに結果を蓄えているので、後はご随意に
}
return true;//Trueを返すと処理が継続する
},
IntPtr.Zero);
「WinAPI.IsWindowVisible」を呼び出して、ウィンドウが表示されているかどうかを判定していますが、「ウィンドウは持っているけど表示されない」みたいな例外動作をするアプリケーションもあります。
代表例がexplorerのProgram Manager。
こういった特殊なアプリケーションをどう扱うかは仕様次第だと思います。
「ぷるまど」は汎用的、かつ雑なアプリということもあり、そのあたりはあまり考えないことにしました。「ぷるまど」には、他のアプリケーションの都合が分からないから、とりあえず表示しておけ、てな動作をしています。
ウィンドウ操作系API等
他にはこの辺りを、こんな感じで定義して使っています。
[DllImport("user32", CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
public const int SW_RESTORE = 9; // 画面を元の大きさに戻す
public const int SW_SHOWNORMAL = 1;
[DllImport("User32.dll")]
public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
public static extern int MoveWindow(IntPtr hwnd, int x, int y, int nWidth, int nHeight, int bRepaint);
[DllImport("USER32.DLL", CharSet = CharSet.Auto)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
何をするAPIかは、名前を見てもらえば大体わかるかと……