首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

彈出視窗殺手(上):C# 系統匣圖示、定時器與 IE 視窗枚舉關閉

     編輯:VC 教學

專案目標

建立一個常駐系統匣的 C# 應用程式,定期掃描所有 Internet Explorer 視窗,依標題關鍵字自動關閉彈出廣告視窗,並支援熱鍵手動觸發。

核心技術點

  1. 系統匣圖示:NotifyIcon 控制項 + ContextMenuStrip 實現右鍵選單。
  2. 隱藏主視窗:ShowInTaskbar = false、WindowState = FormWindowState.Minimized、Hide()。
  3. 關閉改為最小化:覆寫 OnClosing 取消關閉並最小化隱藏。
  4. 定時掃描:System.Timers.Timer 每 3 秒觸發 FindPopupToKill。
  5. 枚舉 IE 視窗:兩種方式——EnumThreadWindows 走訪執行緒、FindWindowEx 直接用類別名 IEFrame。
  6. 關閉視窗:發送 WM_SYSCOMMAND + SC_CLOSE 軟性關閉。

關鍵程式碼片段

1. 系統匣與視窗狀態控制

public void HideApp()
{
    this.WindowState = FormWindowState.Minimized;
    this.Hide();
}
public void ShowApp()
{
    this.Show();
    this.WindowState = FormWindowState.Normal;
}
protected override void OnClosing(CancelEventArgs e)
{
    e.Cancel = true;
    this.WindowState = FormWindowState.Minimized;
    this.Hide();
}
private void menu_App_Exit(object sender, EventArgs e)
{
    NativeWIN32.UnregisterHotKey(this.Handle, 100);
    notifyIcon1.Visible = false;
    Application.Exit();
}

2. 定時器設定

m_Timer = new System.Timers.Timer();
m_Timer.Elapsed += OnTimerKillPopup;
m_Timer.Interval = 3000; // 3 秒
m_Timer.Enabled = true;

void OnTimerKillPopup(object sender, ElapsedEventArgs e)
{
    m_Timer.Enabled = false;
    FindPopupToKill();
    m_Timer.Enabled = true;
}

3. 方式一:EnumThreadWindows 走訪所有 IE 執行緒

Process[] ies = Process.GetProcessesByName("IEXPLORE");
foreach (Process p in ies)
    FindPopupToKill(p);

void FindPopupToKill(Process p)
{
    foreach (ProcessThread t in p.Threads)
    {
        NativeWIN32.EnumThreadProc cb = MyEnumThreadWindowsProc;
        NativeWIN32.EnumThreadWindows(t.Id, cb, IntPtr.Zero);
    }
}

bool MyEnumThreadWindowsProc(IntPtr hwnd, IntPtr lParam)
{
    const int WM_SYSCOMMAND = 0x0112;
    const int SC_CLOSE = 0xF060;

    NativeWIN32.STRINGBUFFER titleBuf;
    NativeWIN32.GetWindowText(hwnd, out titleBuf, 256);
    string title = titleBuf.szText;
    if (string.IsNullOrEmpty(title)) return true;

    foreach (ListViewItem item in listView1.Items)
    {
        if (title.StartsWith(item.Text))
            NativeWIN32.SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, IntPtr.Zero);
    }
    return true;
}

4. 方式二:FindWindowEx 直接找 IEFrame(效能較佳)

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

    do
    {
        hNext = NativeWIN32.FindWindowEx(hParent, hNext, IEFrame, IntPtr.Zero);
        if (hNext == IntPtr.Zero) break;

        NativeWIN32.STRINGBUFFER titleBuf;
        NativeWIN32.GetWindowText(hNext, out titleBuf, 256);
        string title = titleBuf.szText;
        if (string.IsNullOrEmpty(title)) continue;

        foreach (ListViewItem item in listView1.Items)
        {
            if (title.StartsWith(item.Text))
                NativeWIN32.SendMessage(hNext, NativeWIN32.WM_SYSCOMMAND, NativeWIN32.SC_CLOSE, IntPtr.Zero);
        }
    } while (hNext != IntPtr.Zero);
}

5. P/Invoke 封裝


public class NativeWIN32
{
    public delegate bool EnumThreadProc(IntPtr hwnd, IntPtr lParam);
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern bool EnumThreadWindows(int threadId, EnumThreadProc pfnEnum, IntPtr lParam);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct STRINGBUFFER { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string szText; }

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

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr next, string className, IntPtr windowTitle);

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

    public const int WM_SYSCOMMAND = 0x0112;
    public const int SC_CLOSE = 0xF060;

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

效能與選擇建議

  • EnumThreadWindows:能過濾非 IE 視窗,但需枚舉所有執行緒,較慢。
  • FindWindowEx + IEFrame:直接由視窗管理器查找,速度快、程式碼簡潔,推薦正式環境使用。

結語

結合系統匣、定時器、Win32 API 視窗枚舉與熱鍵,即可打造一個輕量級的 IE 彈出視窗攔截器。核心在於熟悉 FindWindowEx/EnumThreadWindows 兩種枚舉策略的優劣,並善用 WM_SYSCOMMAND/SC_CLOSE 達成「軟性關閉」避免資料遺失。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved