2026年2月8日

Windows11の、右下に出てくるポップ広告を出た瞬間に消すアプリ(2)「PopSentry02.exe」

 ここで、コードを全部公開する。

プログラミングは40年も昔にN88_BASICでちょこっとやっただけなので、とても自信が無いけど、AIの力をお借りしてなんとか形になったとは思う。コード生成はAI任せだったので全くわかりません。でもちゃんと機能してるみたいですよ。



このアプリは、「PopSentry02.exe」という名前にした。POPの見張番という意味だ。

インストール不要、Windows11の適当なフォルダにコピーして、ショートカットをスタートアップにおいておくだけで、起動時に常駐する。

アプリの説明だけど、ここにWIN11機がないからスクショが取れない、よって言葉だけで説明する。

ポップが出た瞬間に感知し、表示の許可を求めてくる。重要だと思えば「はい」にすれば、同種のポップは今後も同じように表示してくる。不要なポップは「いいえ」を選べば、ブラックリストに追加され、瞬時に消され、今後一切出てきた瞬間に消去される。

という感じのアプリです。

https://github.com/sanmasystem-Jima/Popsentry02

ここで公開しました!github


ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー


using Newtonsoft.Json;

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Drawing;

using System.IO;

using System.Runtime.InteropServices;

using System.Text;

using System.Threading;

using System.Windows.Forms;


namespace PopSentry

{

    internal static class Program

    {

        // WinAPI

        private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);


        [DllImport("user32.dll")]

        private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);


        [DllImport("user32.dll")]

        private static extern bool IsWindowVisible(IntPtr hWnd);


        [DllImport("user32.dll")]

        private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);


        [DllImport("user32.dll")]

        private static extern int GetWindowTextLength(IntPtr hWnd);


        [DllImport("user32.dll")]

        private static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);


        [DllImport("user32.dll")]

        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);


        [DllImport("user32.dll")]

        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);


        private const uint WM_CLOSE = 0x0010;


        [StructLayout(LayoutKind.Sequential)]

        private struct RECT

        {

            public int Left;

            public int Top;

            public int Right;

            public int Bottom;

        }


        // 設定

        class Settings

        {

            public List<string> WhiteList { get; set; } = new List<string>();

            public List<string> BlackList { get; set; } = new List<string>();

        }


        private static Settings settings = new Settings();

        private const string SettingsFile = "popsentry.json";

        private const string LogFile = "popsentry.log";


        [STAThread]

        static void Main()

        {

            bool createdNew;

            using (var mutex = new System.Threading.Mutex(true, "PopSentryMutex", out createdNew))

            {

                if (!createdNew)

                {

                    MessageBox.Show(

                        "PopSentry はすでに起動しています。",

                        "PopSentry",

                        MessageBoxButtons.OK,

                        MessageBoxIcon.Information

                    );

                    return;

                }


                Application.EnableVisualStyles();

                Application.SetCompatibleTextRenderingDefault(false);


                LoadSettings();


                // トレイアイコン

                NotifyIcon icon = new NotifyIcon();

                icon.Icon = SystemIcons.Information;

                icon.Visible = true;

                icon.Text = "PopSentry - 稼働中";


                ContextMenuStrip menu = new ContextMenuStrip();

                menu.Items.Add("ログを開く", null, (s, e) =>

                {

                    if (File.Exists(LogFile))

                        Process.Start("notepad.exe", LogFile);

                });

                menu.Items.Add("終了", null, (s, e) =>

                {

                    icon.Visible = false;

                    Application.Exit();

                });

                icon.ContextMenuStrip = menu;


                // 監視スレッド

                Thread t = new Thread(RunLoop);

                t.IsBackground = true;

                t.Start();


                Application.Run();

            }

        }


        private static void RunLoop()

        {

            while (true)

            {

                EnumWindows(EnumWindowCallback, IntPtr.Zero);

                Thread.Sleep(300);

            }

        }


        private static bool EnumWindowCallback(IntPtr hWnd, IntPtr lParam)

        {

            if (!IsWindowVisible(hWnd))

                return true;


            int length = GetWindowTextLength(hWnd);

            if (length == 0)

                return true;


            StringBuilder sb = new StringBuilder(length + 1);

            GetWindowText(hWnd, sb, sb.Capacity);

            string title = sb.ToString();


            if (!GetWindowRect(hWnd, out RECT rect))

                return true;


            var screen = Screen.PrimaryScreen.WorkingArea;


            bool isRightBottom =

                rect.Left > screen.Right - 800 &&

                rect.Top > screen.Bottom - 800;


            if (!isRightBottom)

                return true;


            GetWindowThreadProcessId(hWnd, out uint pid);

            string procName = "unknown";


            try

            {

                using (var p = Process.GetProcessById((int)pid))

                    procName = p.ProcessName;

            }

            catch { }


            // ホワイト → 毎回ログしてスルー

            if (settings.WhiteList.Contains(procName))

            {

                LogWhite(procName, title);

                return true;

            }


            // ブラック → 毎回ログして即死

            if (settings.BlackList.Contains(procName))

            {

                LogKill(procName, title);

                SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);

                return true;

            }


            // 未登録 → ユーザーに聞く

            DialogResult result = MessageBox.Show(

                $"このポップアップを許可しますか?\n\nプロセス: {procName}\nタイトル: {title}",

                "PopSentry",

                MessageBoxButtons.YesNo,

                MessageBoxIcon.Question);


            if (result == DialogResult.Yes)

            {

                settings.WhiteList.Add(procName);

                SaveSettings();

                LogWhite(procName, title);   // 初回ログ

            }

            else

            {

                settings.BlackList.Add(procName);

                SaveSettings();

                LogKill(procName, title);    // 初回ログ

                SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);

            }


            return true;

        }


        private static void LoadSettings()

        {

            try

            {

                if (File.Exists(SettingsFile))

                {

                    string json = File.ReadAllText(SettingsFile);

                    settings = JsonConvert.DeserializeObject<Settings>(json) ?? new Settings();

                }

            }

            catch

            {

                settings = new Settings();

            }

        }


        private static void SaveSettings()

        {

            try

            {

                string json = JsonConvert.SerializeObject(settings, Formatting.Indented);

                File.WriteAllText(SettingsFile, json);

            }

            catch { }

        }


        // ホワイトログ(毎回)

        private static void LogWhite(string procName, string title)

        {

            try

            {

                string line = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} WHITE {procName} | {title}";

                File.AppendAllText(LogFile, line + Environment.NewLine);

            }

            catch { }

        }


        // ブラックログ(毎回)

        private static void LogKill(string procName, string title)

        {

            try

            {

                string line = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} KILL {procName} | {title}";

                File.AppendAllText(LogFile, line + Environment.NewLine);

            }

            catch { }

        }

    }

}

0 件のコメント:

コメントを投稿