早期網頁常彈出大量無工具列、無選單的 IE 視窗作為廣告。手動關閉極其繁瑣。本文實作一個駐留系統托盤的背景程式,定時掃描所有頂層視窗,辨識「無選單、無工具列的 IE 視窗」並自動發送 WM_CLOSE 關閉。
GetClassName 判斷是否為 "IEFrame" (IE 主視窗類別)。FindWindowEx 尋找 "WorkerW" / "WorkerA" 子視窗 (IE 內容區)。GetWindowLong(GWL_STYLE) & WS_VISIBLE 確認內容區實際可見 (排除最小化/隱藏視窗)。
SetTimer(TIMER_AD_SCAN, 2000, NULL); // 每 2 秒掃描一次
void CAdKillerDlg::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == TIMER_AD_SCAN)
{
ScanAndCloseAdWindows();
}
CDialog::OnTimer(nIDEvent);
}
void CAdKillerDlg::ScanAndCloseAdWindows()
{
// 從第一個頂層視窗開始枚舉
CWnd* pWnd = CWnd::GetTopWindow(); // 等價 GetWindow(GW_HWNDFIRST)
while (pWnd)
{
// 1. 取得類別名稱
TCHAR szClassName[256] = {0};
GetClassName(pWnd->GetSafeHwnd(), szClassName, 255);
// 2. 過濾:必須是 IEFrame
if (_tcscmp(szClassName, _T("IEFrame")) == 0)
{
// 3. 尋找內容區子視窗 WorkerW / WorkerA
HWND hWorker = FindWindowEx(pWnd->GetSafeHwnd(), NULL, _T("WorkerW"), NULL);
if (!hWorker)
hWorker = FindWindowEx(pWnd->GetSafeHwnd(), NULL, _T("WorkerA"), NULL);
if (hWorker)
{
// 4. 尋找下一個同級子視窗 (通常為實際內容渲染區)
HWND hContent = FindWindowEx(pWnd->GetSafeHwnd(), hWorker, _T("WorkerW"), NULL);
if (!hContent)
hContent = FindWindowEx(pWnd->GetSafeHwnd(), hWorker, _T("WorkerA"), NULL);
// 5. 關鍵判斷:內容區存在且可見,且父視窗無選單/工具列特徵
if (hContent && (GetWindowLong(hContent, GWL_STYLE) & WS_VISIBLE))
{
// 進一步驗證:父視窗無選單 (GetMenu==NULL) 且無標準工具列
// 此處簡化:直接關閉符合上述條件的視窗
// 實際專案建議加入白名單機制 (如特定網域、視窗標題關鍵字)
// 發送 WM_CLOSE 關閉視窗 (跨進程安全)
pWnd->PostMessage(WM_CLOSE, 0, 0);
// 關閉後繼續掃描下一個視窗 (pWnd 已失效,從頭開始或記錄下一個)
// 此處為簡化,直接返回,下一輪定時器再掃
return;
}
}
}
pWnd = pWnd->GetNextWindow(); // GW_HWNDNEXT
}
}
PostMessage(WM_CLOSE) 是非同步、跨進程安全的關閉方式,目標視窗會在自己的訊息迴圈處理關閉邏輯。SendMessage (同步阻塞) 或直接呼叫 DestroyWindow (需同進程)。
// 白名單:視窗標題關鍵字、網域、類別名稱例外
bool IsWhitelisted(CWnd* pWnd)
{
CString title;
pWnd->GetWindowText(title);
title.MakeLower();
// 例外關鍵字
static LPCTSTR whiteKeys[] = {
_T("webmail"), _T("outlook"), _T("gmail"), _T("chat"),
_T("messenger"), _T("meeting"), _T("video"), _T("admin")
};
for (auto key : whiteKeys)
{
if (title.Find(key) != -1) return true;
}
return false;
}
// 在關閉前加入判斷
if (!IsWhitelisted(pWnd))
pWnd->PostMessage(WM_CLOSE);
ShowWindow(SW_HIDE),僅托盤圖示可見。本技術針對 IE 視窗結構 (IEFrame + WorkerW/A)。現代瀏覽器使用不同類別名稱 (如 Chrome_WidgetWin_1) 且多進程架構 (每分頁一進程),需分別針對各瀏覽器類別名稱調整辨識邏輯。通用方案較複雜,建議改用瀏覽器擴充功能 (Extension) 實現廣告攔截。
Ctrl+Alt+K) 切換掃描狀態。GetWindowThreadProcessId + OpenProcess + GetModuleFileNameEx 取得進程路徑,精確針對 iexplore.exe。廣告視窗自動關閉器展示了 Windows 視窗枚舉、跨進程訊息傳遞、特徵辨識的經典組合應用。雖然 IE 時代已逝,但此架構可輕鬆移植至任何「特定視窗類別自動管理」場景:自動關閉錯誤對話框、自動點擊確認按鈕、自動填寫登入表單等。核心思想:**定時掃描 + 多層特徵過濾 + 安全操作 + 白名單保護**。