IEFrame 視窗類別。IEFrame → WorkerW (內容區),WorkerW 可見性為隱藏。WH_CALLWNDPROC)攔截 WM_SHOWWINDOW 訊息,判斷是否為廣告視窗,符合則發送 WM_CLOSE。
// 共享資料段 (可選,用於傳遞設定)
#pragma data_seg("SHARED")
HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:SHARED,RWS")
LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
CWPSTRUCT *pCwp = (CWPSTRUCT*)lParam;
if (!pCwp) return CallNextHookEx(g_hHook, nCode, wParam, lParam);
// 僅處理 WM_SHOWWINDOW
if (pCwp->message != WM_SHOWWINDOW)
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
// 1. 取得視窗類別名
TCHAR szClassName[128];
GetClassName(pCwp->hwnd, szClassName, 128);
if (_tcsicmp(szClassName, _T("IEFrame")) != 0)
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
// 2. 遍歷子視窗尋找 WorkerW
HWND hChild = GetWindow(pCwp->hwnd, GW_CHILD);
bool bIsAd = false;
while (hChild) {
GetClassName(hChild, szClassName, 128);
if (_tcsicmp(szClassName, _T("WorkerW")) == 0) {
// WorkerW 不可見 = 廣告視窗特徵
if (!(GetWindowLong(hChild, GWL_STYLE) & WS_VISIBLE)) {
bIsAd = true;
}
break;
}
hChild = GetWindow(hChild, GW_HWNDNEXT);
}
// 3. 關閉廣告視窗
if (bIsAd) {
PostMessage(pCwp->hwnd, WM_CLOSE, 0, 0);
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
// DLL 導出:安裝/卸載鉤子
extern "C" __declspec(dllexport) BOOL InstallHook()
{
g_hHook = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, g_hInstance, 0);
return g_hHook != NULL;
}
extern "C" __declspec(dllexport) void UninstallHook()
{
if (g_hHook) {
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
}
BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, LPVOID)
{
if (reason == DLL_PROCESS_ATTACH) g_hInstance = hInst;
return TRUE;
}
class TMainForm : public TForm
{
HINSTANCE hHookDll;
typedef BOOL (*PFN_INSTALL)();
typedef void (*PFN_UNINSTALL)();
PFN_INSTALL InstallHook;
PFN_UNINSTALL UninstallHook;
__fastcall TMainForm(TComponent* Owner) : TForm(Owner)
{
hHookDll = LoadLibrary("AdBlockHook.dll");
if (hHookDll) {
InstallHook = (PFN_INSTALL)GetProcAddress(hHookDll, "InstallHook");
UninstallHook = (PFN_UNINSTALL)GetProcAddress(hHookDll, "UninstallHook");
if (InstallHook) InstallHook();
}
}
__fastcall ~TMainForm()
{
if (UninstallHook) UninstallHook();
if (hHookDll) FreeLibrary(hHookDll);
}
};
| 點 | 說明 |
|---|---|
| WH_CALLWNDPROC | 在視窗程序**執行前**調用,可攔截/修改參數,但不可阻止調用 (需 WH_CALLWNDPROCRET 獲取返回值) |
| CWPSTRUCT | 包含 hwnd, message, wParam, lParam,即原始訊息參數 |
| 共享資料段 | 讓多進程共享 g_hHook,但本案例僅需單一鉤子實例 |
| PostMessage vs SendMessage | PostMessage 非同步,避免在鉤子中阻塞 UI 執行緒 |
| 64 位 IE | 需編譯 64 位 DLL,或啟用 32 位 IE (已淘汰) |
window.open / target=_blank。
這是一個經典的「鉤子 + 視窗特徵判斷」案例,展示了 WH_CALLWNDPROC 在視窗生命週期早期介入的威力。