ie插件製作

正文
在Windows操作系統上,我們最常見的瀏覽器有兩種:文件瀏覽器(exploer.exe,應用於文件系統)和Internet瀏覽器(iexplore.exe,應用於互聯網資源)。由於這兩個瀏覽器功能強大,而且又與Windows操作系統捆綁銷售,最終也就成爲了瀏覽器的標準。但有時候,爲了給瀏覽器加入一些新的特性,我們往往會重新設計一個自己的瀏覽器。新的瀏覽器模仿標準瀏覽器的大部分功能,同時加入新特性。這種做法最直觀,但實際上也是相對於微軟的重複勞動,且工作量比較大。其實,使用BHO插件,一切都變得很簡單。

BHO(Browser Help Objects),是實現了特定接口的COM組件。開發好的BHO插件在註冊表特定的位置註冊好後,每當微軟的瀏覽器啓動,BHO實例就會被創建。在瀏覽器工作的工程中,BHO會接收到很多事件,比如瀏覽器瀏覽新的地址、前進或後退、生成新的窗口、瀏覽器退出等等;BHO可以在這些事件的響應中實現與瀏覽器的交互。

下面,我們首先來介紹一下BHO的工作原理。上面我們已經提到,BHO是COM組件,而且一定實現了IObjectWithSite接口。這些組件除了在註冊表中註冊爲COM Server外,還必須將它們的CLSID在HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/ CurrentVersion/Explorer/Browser Helper Objects下注冊爲子鍵。微軟在設計瀏覽器的時候,已經給這些組件預留了空間。每當瀏覽器啓動時,瀏覽器會首先在上述註冊表位置查看是否有註冊的BHO CLSID;如果有則分別創建一個實例,並對BHO實例進行初始化,建立交互連接。(注:BHO實例只有在創建它的瀏覽器窗口銷燬時才被釋放。)下圖演示了BHO的創建過程:


成功創建的BHO,不僅可以得到各種標準的瀏覽器操作事件,並做出響應;還可以定製瀏覽器的菜單、工具條等界面元素;更或者可以安裝鉤子函數,監視瀏覽器的一舉一動。值得注意的是,使用BHO插件,Internet瀏覽器要求在4.0以上版本;如果是文件瀏覽器,操作系統要求是Windows 95/98/2000或Window NT 4.0以上版本,並且Shell的版本在4.71以上。下面是支持BHO特性的系統一覽表:

Shell版本 操作系統版本 支持BHO
4.00 Windows 95 and Windows NT 4.0(IE版本爲 4.0) 僅IE4.0
4.71 Windows 95 and Windows NT 4.0(IE版本爲 4.0) IE和文件瀏覽器
4.72 Windows 98 IE和文件瀏覽器
5.00  Windows 2000 IE和文件瀏覽器

接下去,筆者就來介紹一下如何開發BHO插件,開發環境爲VC6.0(使用ATL),安裝Platform SDK中的Internet Development SDK。首先,啓動VC的ATL COM AppWizard,生成一個項目名爲BhoPlugin,其餘均採用默認設置。接着,我們就來分步詳細闡述。
第一步,增加一個ATL Object到該項目中。VC菜單Insert->New ATL Object…,在彈出的對話框中選擇“Internet Explorer Object”,輸入COM類名(在Short Name後輸入EyeOnIE,其它各項會自動生成)。完成後,我們可以看到CEyeOnIE類有一個基類IObjectWithSiteImpl,這個就是實現IObjectWithSite接口的模版類。
第二步,實現IObjectWithSite的接口方法。在這之前,我們要先定義幾個成員變量:CComQIPtr<IWebBrowser2, &IID_IWebBrowser2> mWebBrowser2,(需要加入#include "ExDisp.h"),用以保存瀏覽器組件的指針;DWORD mCookie,用以保存與瀏覽器的連接ID。IObjectWithSite有兩個接口方法:SetSite和GetSite。我們只需重載SetSite就行了。在EyeOnIE.h中增加函數聲明STDMETHOD(SetSite)(IUnknown *pUnkSite),在EyeOnIE.cpp實現如下:
STDMETHODIMP CEyeOnIE::SetSite(IUnknown *pUnkSite)
{
USES_CONVERSION;

if (pUnkSite)
{
mWebBrowser2 = pUnkSite;
if (mWebBrowser2)
{
return RegisterEventHandler(TRUE);
}
}
return E_FAIL;
}

HRESULT CEyeOnIE::RegisterEventHandler(BOOL inAdvise)
{
CComPtr<IConnectionPoint> spCP;
// Receives the connection point for WebBrowser events
CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> spCPC(mWebBrowser2);
HRESULT hr = spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP);
if (FAILED(hr))
return hr;

if (inAdvise)
{
// Pass the event handlers to the container
hr = spCP->Advise(reinterpret_cast<IDispatch*>(this), &mCookie);
}
else
{
spCP->Unadvise(mCookie);
}
return hr;
}
我們可以看到,SetSite的參數實際上指向的是瀏覽器組件。在SetSite實現中,我們首先保存瀏覽器組件指針,然後將該BHO向瀏覽器註冊爲事件處理器。
第三步,實現IDispatch接口方法。事件處理也就在IDispatch::Invoke中實現(各個事件的ID在ExDispID.h中定義)。BHO可能會接收到很多事件,但我們只需要響應我們感興趣的那一部分。首先在EyeOnIE.h中增加該函數的聲明,在EyeOnIE.cpp的實現中,筆者試着響應瀏覽器瀏覽一個地址之前發出的事件DISPID_BEFORENAVIGATE2,以此來實現簡單的網址過濾功能,代碼參考如下:
STDMETHODIMP CEyeOnIE::Invoke(DISPID dispidMember,REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS * pDispParams,
VARIANT * pvarResult,EXCEPINFO * pexcepinfo,
UINT * puArgErr)
{
USES_CONVERSION;

if (!pDispParams)
return E_INVALIDARG;

switch (dispidMember)
{
//
// The parameters for this DISPID are as follows:
// [0]: Cancel flag - VT_BYREF|VT_BOOL
// [1]: HTTP headers - VT_BYREF|VT_VARIANT
// [2]: Address of HTTP POST data - VT_BYREF|VT_VARIANT
// [3]: Target frame name - VT_BYREF|VT_VARIANT
// [4]: Option flags - VT_BYREF|VT_VARIANT
// [5]: URL to navigate to - VT_BYREF|VT_VARIANT
// [6]: An object that evaluates to the top-level or frame
// WebBrowser object corresponding to the event.
//
case DISPID_BEFORENAVIGATE2:
{
LPOLESTR lpURL = NULL;
mWebBrowser2->get_LocationURL(&lpURL);
char * strurl;
if (pDispParams->cArgs >= 5 && pDispParams->rgvarg[5].vt == (VT_BYREF|VT_VARIANT))
{
CComVariant varURL(*pDispParams->rgvarg[5].pvarVal);
varURL.ChangeType(VT_BSTR);
strurl = OLE2A(varURL.bstrVal);
}
if (strstr(strurl, "girl.com"))
{
*pDispParams->rgvarg[0].pboolVal = TRUE;
::MessageBox(NULL, _T("該網頁已被禁止!"),_T("Warning"),MB_ICONSTOP);
return S_OK;
}
break;
}

case DISPID_NAVIGATECOMPLETE2:
break;
case DISPID_DOCUMENTCOMPLETE:
break;
case DISPID_DOWNLOADBEGIN:
break;
case DISPID_DOWNLOADCOMPLETE:
break;
case DISPID_NEWWINDOW2:
break;
case DISPID_QUIT:
RegisterEventHandler(FALSE);
break;
default:
break;
}

return S_OK;
}
我們看到,當用戶瀏覽的新地址包含"girl.com"字符的時候,瀏覽器就會彈出一個警告對話框,並且停止進一步的動作。另外值得注意的是,在DISPID_QUIT事件(瀏覽器將要退出)的響應中,我們將BHO事件處理器進行了註銷。
第四步,因爲BHO可能會被文件瀏覽器加載。如果我們不想這樣,我們就要在DllMain中對加載者進行判斷,參考如下:
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// Check who''s loading us.
// If it''s Explorer then "no thanks" and exit...
TCHAR pszLoader[MAX_PATH];
GetModuleFileName(NULL, pszLoader, MAX_PATH);
_tcslwr(pszLoader);
if (_tcsstr(pszLoader, _T("explorer.exe")))
return FALSE;

_Module.Init(ObjectMap, hInstance, &LIBID_BHOPLUGINLib);
DisableThreadLibraryCalls(hInstance);
}
else if (dwReason == DLL_PROCESS_DETACH)
_Module.Term();
return TRUE; // ok
}
最後,別忘了修改註冊表文件,追加BHO的註冊信息。在EyeOnIE.rgs文件的下面增加如下代碼:
HKLM
{
SOFTWARE
{
Microsoft
{
Windows
{
CurrentVersion
{
Explorer
{
''Browser Helper Objects''
{
{6E28339B-7A2A-47B6-AEB2-46BA53782379}
}
}
}
}
}
}
}
注意,{6E28339B-7A2A-47B6-AEB2-46BA53782379}是筆者這個BHO的CLSID,如果你自己開發BHO,這裏應該正確填寫你的CLSID。

好了,一個簡單的BHO開發完成了。(可以到本人的個人主頁 http://hqtech.nease.net 下載實例源代碼。)BHO插件可以實現的功能還有很多,比如網頁內容分析、IE界面定製等等。作爲總結,筆者還要提醒讀者一點的是,如果不想讓BHO起作用了,可以註銷該插件,如下格式:regsvr32 /u yourpath/yourbho.dll,或者直接在註冊表中將“Browser Helper Objects”目錄下注冊的CLSID刪掉。
正文完

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章