表示されているウィンドウのRectを上から順に取得したい
備忘録シリーズという事で、上記の事をする必要があったんですが、こちらの実装方法をメモっときます。まずは使用するDllの宣言です
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetTopWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
[DllImport("dwmapi.dll")]
private static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT pvAttribute, int cbAttribute);
[DllImport("dwmapi.dll")]
private static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out bool pvAttribute, int cbAttribute);
次は実装方法です。GetTopWindowで最初にウィンドウのハンドルを取得して、GetWindow(hWnd, GW_HWNDNEXT)で順に取得すると上から順にウィンドウ情報が取得出来ます。次にGetWindowInfoでウィンドウの情報を取得して要らないものを省くんですが、これだけだとバックグラウンドで動いている(電卓とか設定とか)も拾ってしまい、またGetWindowInfoで取得されるRectは若干実際とずれてるんですよね。そんな時は、DwmGetWindowAttributeを使うらしいです。これはハマった。まじハマりましたが出来て良かった^^
const uint WS_VISIBLE = 0x10000000;
const uint WS_DISABLED = 0x08000000;
const uint GW_HWNDNEXT = 2;
static public List<RECT>GetWindowsRectInfo()
{
//表示されている順番にRECT情報をリストに格納する
var list = new List<RECT>();
var hWnd = GetTopWindow(IntPtr.Zero);
do
{
WINDOWINFO wi = new WINDOWINFO();
wi.cbSize = Marshal.SizeOf(wi);
int retCode = GetWindowInfo(hWnd, ref wi);
if (retCode <= 0)
continue;
if ((wi.dwStyle & WS_VISIBLE) == 0)
continue;
if ((wi.dwStyle & WS_DISABLED) == WS_DISABLED)
continue;
if (wi.cyWindowBorders == 0)
continue;
//バックグランドなのかを判定
bool isLock = false;
retCode = DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAKED, out isLock, Marshal.SizeOf(typeof(bool)));
if (retCode >= 0 && isLock == false)
{
//ウィンドウの見た目通りのRectを取得したい
//WINDOWSINFOのrcWindowだと実際のサイズより大きい
RECT rc = new RECT();
DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out rc, Marshal.SizeOf(typeof(RECT)));
list.Add(rc);
}
} while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != IntPtr.Zero);
return list;
}
しかし、まだまだuser32の関数を使う機会って結構ありますね。。