建立一個常駐系統匣的 C# 應用程式,定期掃描所有 Internet Explorer 視窗,依標題關鍵字自動關閉彈出廣告視窗,並支援熱鍵手動觸發。
NotifyIcon 控制項 + ContextMenuStrip 實現右鍵選單。ShowInTaskbar = false、WindowState = FormWindowState.Minimized、Hide()。OnClosing 取消關閉並最小化隱藏。System.Timers.Timer 每 3 秒觸發 FindPopupToKill。EnumThreadWindows 走訪執行緒、FindWindowEx 直接用類別名 IEFrame。WM_SYSCOMMAND + SC_CLOSE 軟性關閉。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();
}
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;
}
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;
}
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);
}
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 達成「軟性關閉」避免資料遺失。