首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 彈出視窗殺手:系統匣常駐、定時掃描、熱鍵快速新增封鎖清單

     編輯:關於C#

專案功能

  • 常駐系統匣 (NotifyIcon),主視窗隱藏不佔用工作列
  • 定時器週期性掃描 IE 視窗,標題符合封鎖清單者自動關閉
  • 兩種掃描演算法:EnumThreadWindows (依執行緒) 與 FindWindowEx (依類別名)
  • 系統熱鍵 (Ctrl+Shift+J) 快速將前景視窗標題加入封鎖清單
  • 右鍵選單顯示/隱藏主視窗、結束程式
  • 關閉視窗改為最小化至系統匣,不真正退出

核心模組實作

1. 系統匣與視窗狀態管理

public partial class MainForm : Form
{
    private NotifyIcon trayIcon;
    private ContextMenuStrip trayMenu;

    public MainForm()
    {
        InitializeComponent();
        this.ShowInTaskbar = false;
        this.Visible = false; // 啟動即隱藏

        // 建立 NotifyIcon
        trayIcon = new NotifyIcon
        {
            Icon = new Icon("app.ico"),
            Visible = true,
            Text = "彈出視窗殺手"
        };

        // 右鍵選單
        trayMenu = new ContextMenuStrip();
        trayMenu.Items.Add("顯示主視窗", null, (s,e)=>ShowApp());
        trayMenu.Items.Add("隱藏主視窗", null, (s,e)=>HideApp());
        trayMenu.Items.Add("-");
        trayMenu.Items.Add("結束", null, (s,e)=>ExitApp());
        trayIcon.ContextMenuStrip = trayMenu;

        // 雙擊圖示切換顯示
        trayIcon.DoubleClick += (s,e) => 
        {
            if (this.WindowState == FormWindowState.Minimized) ShowApp();
            else HideApp();
        };
    }

    void ShowApp() { this.Show(); this.WindowState = FormWindowState.Normal; }
    void HideApp() { this.WindowState = FormWindowState.Minimized; this.Hide(); }

    // 關閉鈕改為最小化
    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        e.Cancel = true;
        HideApp();
    }

    void ExitApp()
    {
        NativeMethods.UnregisterHotKey(Handle, HOTKEY_ID);
        trayIcon.Visible = false;
        Application.Exit();
    }
}

2. 定時掃描與關閉彈出視窗

private System.Timers.Timer scanTimer;
private List blockList = new List(); // 從 ListView 同步

private void StartScanner(int intervalMs = 3000)
{
    scanTimer = new System.Timers.Timer(intervalMs);
    scanTimer.Elapsed += (s,e) => 
    {
        scanTimer.Enabled = false;
        FindAndKillPopups();
        scanTimer.Enabled = true;
    };
    scanTimer.Start();
}

// 方法 A:EnumThreadWindows (較精確,僅掃 IE 進程)
void FindAndKillPopups()
{
    foreach (Process ie in Process.GetProcessesByName("iexplore"))
    {
        foreach (ProcessThread t in ie.Threads)
        {
            NativeMethods.EnumThreadWindows(t.Id, EnumWindowCallback, IntPtr.Zero);
        }
    }
}

bool EnumWindowCallback(IntPtr hwnd, IntPtr lParam)
{
    var sb = new StringBuilder(256);
    NativeMethods.GetWindowText(hwnd, sb, sb.Capacity);
    string title = sb.ToString();
    if (string.IsNullOrEmpty(title)) return true;

    foreach (string block in blockList)
    {
        if (title.StartsWith(block))
        {
            NativeMethods.SendMessage(hwnd, NativeMethods.WM_SYSCOMMAND, NativeMethods.SC_CLOSE, IntPtr.Zero);
            break;
        }
    }
    return true; // 繼續列舉
}

3. 更高效掃描:FindWindowEx 依類別名 "IEFrame"

void FindAndKillPopups_Fast()
{
    IntPtr hParent = IntPtr.Zero, hNext = IntPtr.Zero;
    const string IE_CLASS = "IEFrame";

    while (true)
    {
        hNext = NativeMethods.FindWindowEx(hParent, hNext, IE_CLASS, IntPtr.Zero);
        if (hNext == IntPtr.Zero) break;

        var sb = new StringBuilder(256);
        NativeMethods.GetWindowText(hNext, sb, sb.Capacity);
        string title = sb.ToString();
        if (!string.IsNullOrEmpty(title))
        {
            foreach (string block in blockList)
            {
                if (title.StartsWith(block))
                {
                    NativeMethods.SendMessage(hNext, NativeMethods.WM_SYSCOMMAND, NativeMethods.SC_CLOSE, IntPtr.Zero);
                    break;
                }
            }
        }
    }
}

4. 系統熱鍵註冊與處理


const int HOTKEY_ID = 100;
const int WM_HOTKEY = 0x0312;

[Flags]
enum KeyModifiers { None=0, Alt=1, Control=2, Shift=4, Windows=8 }

[DllImport("user32.dll")]
static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk);
[DllImport("user32.dll")]
static extern bool UnregisterHotKey(IntPtr hWnd, int id);

private void RegisterGlobalHotKey()
{
    KeyModifiers mod = KeyModifiers.Control | KeyModifiers.Shift;
    RegisterHotKey(Handle, HOTKEY_ID, mod, Keys.J); // Ctrl+Shift+J
}

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == HOTKEY_ID)
    {
        ProcessHotKey();
    }
    base.WndProc(ref m);
}

void ProcessHotKey()
{
    IntPtr fgWnd = NativeMethods.GetForegroundWindow();
    if (fgWnd != IntPtr.Zero)
    {
        var sb = new StringBuilder(256);
        NativeMethods.GetWindowText(fgWnd, sb, sb.Capacity);
        if (sb.Length > 0)
        {
            AddToBlockList(sb.ToString()); // 加入 ListView 並同步 blockList
        }
    }
}

5. NativeMethods P/Invoke 定義彙整


class NativeMethods
{
    public const int WM_SYSCOMMAND = 0x0112;
    public const int SC_CLOSE = 0xF060;

    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    public static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
    public delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);

    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, IntPtr lpszWindow);

    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);

    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();
}

關鍵優勢

  • FindWindowEx + "IEFrame" 直接過濾 IE 視窗,避免列舉所有進程/執行緒,效能顯著優於 EnumThreadWindows 版本。
  • 熱鍵操作無需切換到主視窗,即時將惱人彈窗標題加入黑名單。
  • 系統匣常駐不干擾工作,關閉視窗不退出保護持續運行。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved