なつねこメモ

主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ 書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。

EnumWindows で見えない UWP アプリを除外したい

突然の Win32 ネタです。
トップレベルウィンドウを列挙する場合、 EnumWindows を使うのですが、
そのとき、見えないウィンドウなども混ざってしまいます。

そういうのを除外する方法です。

コードはこんな感じ。

NativeMethods.EnumWindows((hWnd, lParam) =>
{
    // WS_VISIBLE でない
    if (!NativeMethods.IsWindowVisible(hWnd))
        return true;

    // タイトル空
    var title = new StringBuilder(1024);
    NativeMethods.GetWindowText(hWnd, title, title.Capacity);
    if (string.IsNullOrWhiteSpace(title.ToString()))
        return true; // Skipped

    // UWP
    NativeMethods.DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.Cloaked, out var isCloaked, Marshal.SizeOf(typeof(bool)));
    if (isCloaked)
        return true;

    // ここが見えるウィンドウ
    return true;
}, IntPtr.Zero);

で、問題の見えないウィンドウなんですが、タスクマネージャを開くと分かるのですが、
Windows 10 の場合、いくつかの UWP アプリはバックグラウンドプロセスとして動作しており、
それらは見えないながらも、トップレベルウィンドウとして存在しています。
例えば、起動していなくても「設定」「Microsoft Edge」は普通に取得できてしまいます。

また、それらのアプリは IsWindowVisible で除外することもできません。
そういうときに使うのが、DwmGetWindowAttribute です。

第 2 引数に DWMWA_CLOAKED を指定し、第 3 引数に入れられた値を見ることで、除外できます。

ということで、除外する方法でした。
(NativeMethods の部分は、 pinvoke.net からコピーしてくれば良いと思います。)