BHO (Browser Helper Object) 是實作 IObjectWithSite 的 ATL COM 物件。Internet Explorer 啟動時會載入所有已註冊的 BHO,每個 IE 實例各載入一次。BHO 運行於 IE 進程位址空間,可存取視窗、文件物件模型 (DOM) 等一切 IE 內部資源,生命週期與 IE 實例綁定。
IObjectWithSite::SetSiteIE 呼叫 SetSite(IUnknown* pUnkSite) 傳遞自身 IUnknown。BHO 必須:
QueryInterface 取得 IWebBrowser2(控制瀏覽器核心)QueryInterface 取得 IConnectionPointContainer(事件連接)Advise 訂閱 DWebBrowserEvents2 事件
STDMETHODIMP CBho::SetSite(IUnknown* pUnkSite) {
m_spWebBrowser2 = pUnkSite; // 取得 IWebBrowser2
if (!m_spWebBrowser2) return E_INVALIDARG;
m_spCPC = m_spWebBrowser2; // 取得 IConnectionPointContainer
if (!m_spCPC) return E_POINTER;
return Connect(); // 連接事件
}
HRESULT CBho::Connect() {
CComPtr spCP;
HRESULT hr = m_spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP);
if (FAILED(hr)) return hr;
// 將自身 (IDispatch) 註冊為事件接收器
return spCP->Advise(static_cast(this), &m_dwCookie);
}
IDispatch::Invoke 攔截導航事件
STDMETHODIMP CBho::Invoke(DISPID dispid, REFIID, LCID, WORD,
DISPPARAMS* pDispParams, VARIANT* pVarResult,
EXCEPINFO*, UINT*) {
USES_CONVERSION;
if (dispid == DISPID_BEFORENAVIGATE2 || dispid == DISPID_NAVIGATECOMPLETE2) {
// 取得目前 URL
CComBSTR bstrUrl;
if (FAILED(m_spWebBrowser2->get_LocationURL(&bstrUrl))) return S_OK;
CComPtr spDisp;
if (pDispParams->cArgs > 0 && pDispParams->rgvarg[0].vt == VT_DISPATCH)
spDisp = pDispParams->rgvarg[0].pdispVal; // 目標框架
// 比對封鎖清單(此處簡化為硬編碼)
if (_wcsicmp(bstrUrl, L"https://www.xyz.com/") == 0) {
VARIANT vFlags = {0}, vTarget = {0};
// 導向空白頁或自訂封鎖頁
m_spWebBrowser2->Navigate(SysAllocString(L"about:blank"), &vFlags, &vTarget, NULL, NULL);
m_spWebBrowser2->put_Visible(VARIANT_TRUE);
if (pVarResult) pVarResult->vt = VT_BOOL, pVarResult->boolVal = VARIANT_TRUE; // 取消導航
return S_FALSE;
}
}
return S_OK;
}
關鍵事件:
DISPID_BEFORENAVIGATE2:導航前,可取消DISPID_NAVIGATECOMPLETE2:導航完成,可二次檢查(防 POST 重導)專案 .rgs 檔加入:
HKLM {
NoRemove Software {
NoRemove Microsoft {
NoRemove Windows {
NoRemove CurrentVersion {
NoRemove Explorer {
NoRemove "Browser Helper Objects" {
ForceRemove {YOUR_CLSID_HERE} = s "Your BHO Description"
}
}
}
}
}
}
}
編譯產出 DLL 後:
regsvr32 YourBho.dll // 註冊
regsvr32 /u YourBho.dll // 解除註冊
BHO 預設也會隨 Active Desktop 載入 explorer.exe。若僅針對 IE:
BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) {
if (reason == DLL_PROCESS_ATTACH) {
TCHAR path[MAX_PATH];
GetModuleFileName(NULL, path, MAX_PATH);
if (_tcsicmp(_tcsrchr(path, '\\')+1, _T("explorer.exe")) == 0)
return FALSE; // 拒絕載入
}
return TRUE;
}
IObjectWithSite、IDispatchSetSite 取得 IWebBrowser2 + 事件連接Invoke 攔截 BEFORENAVIGATE2/NAVIGATECOMPLETE2.rgs 註冊 BHO CLSID 至 HKLM\...\Browser Helper ObjectsIE 已停止維護,Edge 採用 WebView2 / 擴充功能 (Manifest V3) 架構。新專案請考慮:
BHO 僅適用於維護舊版 IE 相容系統。
BHO 透過 COM 機制深度整合 IE,攔截導航事件實現 URL 封鎖。核心流程:SetSite → IWebBrowser2 → IConnectionPointContainer → Advise → Invoke 處理事件。雖技術成熟,但 IE 退役意味著 BHO 已成歷史,新開發請轉向現代瀏覽器擴充生態。