PopGuard は、作業中に割り込んでくる最前面(TOPMOST)のポップアップウィンドウを、一時的に裏へ送る (または最小化・非表示にする)Windows 向けのタスクトレイ常駐アプリです。
運用・設定の手順は docs/sources/ の管理者ガイド/ユーザーガイドを参照してください。
- 単体の実行ファイル
PopGuard.exe(.NET / WinForms)。ブラウザー拡張やサービスは使いません。 - 各ユーザーのセッション内で一般ユーザー権限のプロセスとして常駐します(サービスではないため、ユーザーのデスクトップのウィンドウ操作とトレイ表示が可能)。
- 抑止対象・方法は設定ファイル
PopGuard.rules.jsonで定義します。 - 抑止は「トレイメニューからの手動(期限付き)」と「Windows 11 のフォーカス セッション連動」で有効化されます。
- 裏へ送ったウィンドウは、抑止終了時・アプリ終了時・異常時に必ず元へ戻します。
| 経路 | 実装 | 役割 |
|---|---|---|
| イベント(即時) | SetWinEventHook(EVENT_OBJECT_CREATE / EVENT_OBJECT_SHOW) |
出現した瞬間に評価。チラ見えを最小化 |
| ポーリング(保険) | 700ms ごとに EnumWindows |
イベントの取りこぼし(表示後に最前面化する等)を補完 |
- イベントは
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESSで購読。メッセージポンプ(Application.Run)が 回っている STA スレッドで登録します。 - トップレベルに絞るため、コールバックで
idObject == OBJID_WINDOW && idChild == 0かつGetAncestor(hwnd, GA_ROOT) == hwndを確認します。 - どちらの経路も最終的に
GuardEngine.Consider(hwnd)を呼びます(GuardEngineは_lock/_stateLockで 保護されており、イベント(UI スレッド)とポーリング(スレッドプール)からの並行呼び出しに対して安全)。
- 抑止が有効(
IsActive:手動またはフォーカス連動)。 IsWindowかつIsWindowVisible。- 最前面(
GetWindowLong(GWL_EXSTYLE) & WS_EX_TOPMOST)。 - 自プロセス以外。
- ルール一致(まずプロセス名で安く絞り、その後クラス名・タイトルを取得して照合)。
- モーダル回避に該当しない(下記)。
一致したら hide に従い処理します。
hide |
実装 |
|---|---|
Bottom(既定) |
SetWindowPos(HWND_NOTOPMOST) → SetWindowPos(HWND_BOTTOM) |
Minimize |
ShowWindowAsync(SW_MINIMIZE) |
Hide |
ShowWindowAsync(SW_HIDE) |
HWND_NOTOPMOST だけでは「非最前面グループの先頭」に残り見た目が変わらないため、明示的に裏送り/最小化/非表示まで行います。
モーダルダイアログを裏へ送るとアプリが進められなくなるため、次のいずれかに該当すると対象外にします (企業向けに安全側へ倒す設計)。
- オーナーウィンドウが無効(
GetWindow(GW_OWNER)が無効化されている)=モーダル実行中の典型。 WS_EX_DLGMODALFRAMEを持つ。- ウィンドウクラスが
#32770(標準の Win32 ダイアログボックス。MessageBox/DialogBox由来)。
裏へ送ったウィンドウ(WasTopMost / hide 方法を記録)を追跡し、次のタイミングで RestoreAll() により
隠し方を逆転 → 元が最前面なら HWND_TOPMOST へ戻します。
- 抑止の期限切れ(
CheckExpiry、ポーリングから毎回)。 - 手動停止(
Deactivate)/アプリ終了。 AppDomain.UnhandledException/ProcessExit(取り残し防止)。
- 手動:トレイメニューの時間候補(
durations)→Activate(TimeSpan?)(nullは無制限)。 - フォーカス連動:
Windows.UI.Shell.FocusSessionManager(WinRT)のIsFocusActiveChangedを購読し、 フォーカス セッション中は自動抑止、終了で解除。手動操作が優先(自動で始めたものだけ自動解除)。 - 手動 DND は非対応:
FocusSessionManager.IsFocusActiveはフォーカス セッションのみ反映し、手動の 「応答不可」では変化しません。SHQueryUserNotificationState(QUNS_QUIET_TIME)も Win11 の新 DND を 反映しないため、確実に取得できる公式手段がなく非対応としています(NotificationStateWatcherは検証用に残置)。
- .NET 9 /
TargetFramework = net9.0-windows10.0.22621.0(FocusSessionManagerは 22621 で追加のため)。 SupportedOSPlatformVersion = 10.0.17763.0。実行時にOperatingSystem.IsWindowsVersionAtLeast(10,0,22621)で フォーカス連動をガード(未満の OS では連動スキップ、他機能は動作)。- WinForms(
UseWindowsForms)でトレイ UI。WinRT 射影でFocusSessionManager。 - 動作:Windows 10 1809+ / Windows 11(フォーカス連動は 22H2+)、x64。
PopGuard.exe と同じフォルダーに置き、起動時に一度だけ読み込みます(キー名は大文字小文字非依存)。
{
"rules": [
{ "enabled": true, "process": "SomeNotifier", "title": "*通知*",
"class": "", "hide": "Bottom", "topMostOnly": true }
],
"durations": [
{ "label": "30分", "minutes": 30 }
],
"autoSuppressDuringFocus": true,
"language": "auto"
}rules[]:process(必須・ワイルドカード)、title/class(空で無指定)、hide(Bottom/Minimize/Hide)、enabled、topMostOnly(現状未実装。常に TOPMOST のみ対象)。- ワイルドカードは
*?、全体一致・大文字小文字無視。processが空/ワイルドカードのみは無効。
- ワイルドカードは
durations[]:labelとminutes(0 以下=無制限)。省略時は既定候補(30分/1時間/2時間/一日/無制限)。autoSuppressDuringFocus:フォーカス連動(既定 true)。language:auto/ja/en。
生成支援として tools/parameter-sheet/(Excel パラメータシート)があります。
- RESX:
Resources/Strings.resx(既定=英語, ニュートラル)+Strings.ja.resx(日本語サテライト)。 - アクセサは手書き(
Resources/Strings.cs、ResourceManager)。Strings.Cultureで上書き可能。 language設定(ApplyOverride)でja/en/autoを選択。autoはCurrentUICultureに従う。
- 出力先:
%LOCALAPPDATA%\PopGuard\PopGuard.log(ユーザーごと)。 - 書き込みのたびに開閉し、10MB 超で世代ローテーション(
PopGuard_1.log〜_10.log)。 - 複数インスタンス/スレッドに備え名前付き Mutex(
Local\PopGuard.Logger)で直列化。 - Debug ビルドでは
Debug.WriteLineにも出力([Conditional("DEBUG")])。 - 主なログ:
rules:/win-event:/focus-session:/guard: suppression …/guard demote|restore|skip:/window toplevel:。
# 開発ビルド / 実行(フレームワーク依存)
dotnet build PopGuard\PopGuard.csproj
dotnet run --project PopGuard\PopGuard.csproj
# 配布用:自己完結発行(.NET ランタイム不要)
dotnet publish PopGuard\PopGuard.csproj -p:PublishProfile=win-x64-selfcontained
# 発行 + インストーラ(Inno Setup)を一括
pwsh -File build.ps1- インストーラは
SetupOutput\PopGuardSetup-<version>.exe(PopGuard.iss、Inno Setup 6)。 - 自己完結のため TFM 配下の
win-x64\publish\を丸ごと同梱(ja\サテライト含む)。
ToastTester は検証用の WinForms アプリです。
- 自前トースト:TOPMOST・非アクティブ化・ツールウィンドウの右下ポップアップ(PopGuard の抑止対象)。
- OS トースト:本物の Windows トースト(PopGuard では抑止できないことの確認用)。
- モーダルウィンドウ:TOPMOST かつモーダル(モーダル回避で
guard skipになることの確認用)。
ルールを process = ToastTester にして PopGuard を起動 → 抑止を有効化すると、自前トーストは裏送り、
モーダルは対象外、OS トーストは無反応、という挙動を確認できます。
- 抑止できるのは最前面のトップレベルウィンドウのみ。Windows 標準のトースト通知は制御不可。
- 一般ユーザー権限で動作するため、管理者権限のアプリや他セッションのウィンドウは対象外(UIPI/セッション分離)。
- 「表示→その後 TOPMOST 化」するアプリでは、次のポーリング(最大 ~700ms)まで裏送りが遅れ、その間見えることがある。
- モーダルダイアログは安全のため対象外。
topMostOnlyは設定を受け付けるが未実装(常に TOPMOST のみ)。- 手動 DND 連動は非対応(公式 API で確実に取得できないため)。