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

VC++ 實作廣告視窗自動關閉器:定時掃描 + IE 視窗特徵辨識 + 跨進程關閉

     編輯:VC 教學

前言:廣告視窗的痛點與對策

早期網頁常彈出大量無工具列、無選單的 IE 視窗作為廣告。手動關閉極其繁瑣。本文實作一個駐留系統托盤的背景程式,定時掃描所有頂層視窗,辨識「無選單、無工具列的 IE 視窗」並自動發送 WM_CLOSE 關閉。

核心辨識邏輯:三層過濾

  1. 類別名稱:GetClassName 判斷是否為 "IEFrame" (IE 主視窗類別)。
  2. 子視窗結構:透過 FindWindowEx 尋找 "WorkerW" / "WorkerA" 子視窗 (IE 內容區)。
  3. 可見性檢查:GetWindowLong(GWL_STYLE) & WS_VISIBLE 確認內容區實際可見 (排除最小化/隱藏視窗)。

完整核心代碼 (MFC 版)

1. 定時器啟動 (OnInitDialog / InitInstance)


SetTimer(TIMER_AD_SCAN, 2000, NULL); // 每 2 秒掃描一次

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
    }
}

關鍵技術細節與避坑指南

1. 跨進程視窗操作安全性

  • PostMessage(WM_CLOSE) 是非同步、跨進程安全的關閉方式,目標視窗會在自己的訊息迴圈處理關閉邏輯。
  • 避免使用 SendMessage (同步阻塞) 或直接呼叫 DestroyWindow (需同進程)。

2. 避免誤關正常視窗:白名單機制


// 白名單:視窗標題關鍵字、網域、類別名稱例外
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);

3. 系統托盤駐留與資源優化

  • 主對話框 ShowWindow(SW_HIDE),僅托盤圖示可見。
  • 編譯為 Release 版本,移除除錯資訊,壓縮體積 (UPX 可選)。
  • 記憶體佔用極低 (僅定時器 + 視窗枚舉),適合長期駐留。

4. 現代瀏覽器 (Chrome/Edge/Firefox) 的適用性

本技術針對 IE 視窗結構 (IEFrame + WorkerW/A)。現代瀏覽器使用不同類別名稱 (如 Chrome_WidgetWin_1) 且多進程架構 (每分頁一進程),需分別針對各瀏覽器類別名稱調整辨識邏輯。通用方案較複雜,建議改用瀏覽器擴充功能 (Extension) 實現廣告攔截。

擴充功能建議

  • 日誌記錄:記錄關閉時間、視窗標題、類別名稱,便於事後分析誤關情況。
  • 熱鍵切換啟用/停用:註冊全域熱鍵 (如 Ctrl+Alt+K) 切換掃描狀態。
  • 統計介面:雙擊托盤圖示顯示今日關閉數量、誤關白名單管理對話框。
  • 進程級過濾:結合 GetWindowThreadProcessId + OpenProcess + GetModuleFileNameEx 取得進程路徑,精確針對 iexplore.exe。

結語

廣告視窗自動關閉器展示了 Windows 視窗枚舉、跨進程訊息傳遞、特徵辨識的經典組合應用。雖然 IE 時代已逝,但此架構可輕鬆移植至任何「特定視窗類別自動管理」場景:自動關閉錯誤對話框、自動點擊確認按鈕、自動填寫登入表單等。核心思想:**定時掃描 + 多層特徵過濾 + 安全操作 + 白名單保護**。

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