BHO(浏覽器輔助對象)是一種簡單的ATL COM對象,而Internet Explorer會在每次運行時都加載它;換句話來說,即每個Internet Explorer的實例都會加載它。BHO運行在Internet Explorer的地址空間內,能對可訪問的對象(如窗口、模塊等等)執行任何操作,且因為它依附於浏覽器的主窗口,所以其生命期與浏覽器實例的生命期一致。
如果在系統中打開了活動桌面,BHO也能隨同Windows Explorer一起啟動。如果不想在Windows Explorer中運行BHO,可將如下代碼添加到DLLMain中:
TCHAR strLoader[MAX_PATH];
::GetModuleFileName (NULL, strLoader, MAX_PATH);
if(stricmp("explorer.exe", strLoader) == 0)
return FALSE;
BHO的COM Server必須實現IObjectWithSite,以便對象可以掛鉤到浏覽器事件,Internet Explorer會依靠IObjectWithSite將一個指針傳遞到它的IUnknown接口,所以,只需實現IObjectWithSite的SetSite方法就行了,如下所示:
STDMETHODIMP CBhoApp::SetSite(IUnknown *pUnkSite)
{
//獲取並存儲IWebBrowser2指針
m_spWebBrowser2 = pUnkSite;
if (m_spWebBrowser2 == NULL)
return E_INVALIDARG;
//獲取並存儲IConnectionPointerContainer指針
m_spCPC = m_spWebBrowser2;
if (m_spCPC == NULL)
return E_POINTER;
//連接到宿主程序以接收事件通知
return Connect();
}
以下是Connect函數比較簡單的實現:
HRESULT CBhoApp::Connect()
{
HRESULT hr;
CComPtr<IConnectionPoint> spCP;
//獲取訪問WebBrowser事件的連接指針
hr = m_spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP);
if (FAILED(hr))
return hr;
//把事件處理程序傳遞給宿主程序Each time an event
//每次有事件產生時,宿主程序都會調用我們實現的IDispatch接口的函數
hr = spCP->Advise(reinterpret_cast<IDispatch*>(this),&m_dwCookie);
return hr;
}
通過調用Advise方法,告之浏覽器BHO想要接受事件通知,這意味著BHO會把指向IDispatch的指針提供給浏覽器(這是由於要進行組件事件處理),接下來,浏覽器會調用IDispatch的Invoke方法,並傳遞給它一個事件的ID作為參數,因此,BHO必須實現Invoke方法以處理所發生的事件。
STDMETHODIMP CBhoApp::Invoke(DISPID dispidMember,REFIID riid,
LCID lcid,WORD wFlags,
DISPPARAMS *pDispParams,VARIANT
*pvarResult, EXCEPINFO *pExcepInfo,
UINT *puArgErr)
{
//在使用ATL字符串轉換宏(此處用的是OLE2T)防止編譯錯誤時,必須先調用這個宏
USES_CONVERSION;
if(dispidMember == DISPID_BEFORENAVIGATE2)
{
BSTR bstrUrlName;
HRESULT hr = m_spWebBrowser2->get_LocationURL(&bstrUrlName);
if(FAILED(hr))
return hr;
LPTSTR psz = new TCHAR[SysStringLen(bstrUrlName)];
lstrcpy(psz, OLE2T(bstrUrlName));
//此處,直接比較www.xyz.com,也可從一個要屏蔽的網站列表中進行比較。
if(stricmp("http://www.xyz.com/",psz) == 0)
{
VARIANT vFlags = {0},vTargetFrameName = {0};
//如果不想顯示"空白頁",也可重定向至某個表明此網站已被屏蔽的頁面。
m_spWebBrowser2->Navigate(SysAllocString(L"about:blank"),&vFlags,&vTargetFrameName,
NULL,NULL);
m_spWebBrowser2->put_Visible(VARIANT_TRUE);
return S_FALSE;
}
return S_OK;
}
else if(dispidMember == DISPID_NAVIGATECOMPLETE2)
//檢查以防止頁面的post導航加載(post-navigation loading)
{
BSTR bstrUrlName;
HRESULT hr = m_spWebBrowser2->get_LocationURL(&bstrUrlName);
if(FAILED(hr))
return hr;
//把文本從Unicode轉換為ANSI
LPTSTR psz = new TCHAR[SysStringLen(bstrUrlName)];
lstrcpy(psz, OLE2T(bstrUrlName));
::OutputDebugString("In Navigate Complete");
::OutputDebugString(psz);
if(stricmp("http://www.xyz.com/",psz) == 0)
{
VARIANT vFlags = {0},vTargetFrameName = {0};
m_spWebBrowser2->Navigate(SysAllocString(L"about:blank"),
&vFlags,&vTargetFrameName,
NULL,NULL);
m_spWebBrowser2->put_Visible(VARIANT_TRUE);
}
return S_OK;
}
return S_FALSE;
}
還需修改工程的.rgs文件,依據所定格式添加以下注冊表項:
HKLM\ SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects
ForceRemove {0CB66BA8-5E1F-4963-93D1-E1D6B78FE9A2}
在編譯完成後,使用regsvr32注冊組件,如果想卸載,只需在regsvr32後帶上/u。