1.什么叫BHO
Browser Helper Objects,"瀏覽器幫助者對象",以下皆簡稱BHO。
2.支持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和文件瀏覽器
3.BHO注冊表中的位置
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{7C260B4B-F7A0-40B5-B403-
BEFCDC6A4C3B}
IE啟動時候根據此項到HKEY_CLASSES_ROOT\CLSID下面找到對應BHO組件加載。
4.基本邏輯
IE將自己的IUnKnown指針傳遞給BHO,BHO需要建立一個私有的基于COM的通訊通道,目的是響應IE事件。所以BHO最重要的是實現
IObjectWithSite 接口。IE 通過這個接口,傳遞自己的IUnknown接口,BHO存儲該接口,進一步通過調用IObjectWithSite 提供的方法。
IE啟動時候會依次執行一些函數,把BHO自己的函數注冊到這里,書面上稱之為連接點。這樣就能調用進入 BHO自己的程序內部了。
5.IObjectWithSite 介紹
主要有兩個函數要實現:
a).HRESULT SetSite(IUnknown* pUnkSite) 接收ie瀏覽器的IUnknown指針。典型實現是保存該指針以備將來使用。
b).HRESULT GetSite(REFIID riid, void** ppvSite) 從通過SetSite()方法設置的場所中接收并返回指定的接口,典型實現是查詢前面保
存的接口指針以進一步取得指定的接口。
6.下面通過一個實例來講解下
目標是啟動IE 訪問 http://m.tkk7.com/JAVA-HE/的時候彈出一個警告對話框。
a) 首先啟動VC 2005 新建工程 ATL Project
工程名字: HelloWorld
Application Settings 中,Server type 選擇 Dynamic-link library (dll) 其他都不選。(簡單總結為以atl 創建dll工程)
b) 其次在新建好的CLASS VIEW下選擇 工程 HelloWorld 右鍵 add -> class
選擇創建ATL Simple Object ,下一步 在short name中輸入 HelloWorldBHO 其他都自動補齊不用管。
下一步在options中 :
Threading mode 選擇 Apartment ;
Aggregation 選擇 no;
Interface 選擇 Dual
support 選擇 IObjectWithSite(IE object support)
點擊Finish ,這是一個最簡單的BHO已經創建好了。
c) 目前要做的就是添磚了
編輯 HelloWorldBHO.h 發現系統已經為你創建了 CHelloWorldBHO類, 在類的最下行有一個public: 沒后文,這里就是系統提示你要添加的代
碼了。
CHelloWorldBHO 中SetSite 已經為你添加將瀏覽器的IUnknown 指針保存下來(見m_spUnkSite);。
現在要做的是注冊到連接點。
STDMETHOD(SetSite)(IUnknown *pUnkSite)
{
IObjectWithSiteImpl<CHelloWorldBHO>::SetSite(pUnkSite);
RegisterEventHandler(TRUE);
return S_OK;
}
繼承父類的 SetSite方法,顯示調用父類(SetSite)方法,添加一個注冊函數。(就是前面所述的,添加到連接點)
HRESULT RegisterEventHandler(BOOL inAdvise)
{
CComPtr<IConnectionPoint>spCP;
m_spWebBrowser2 = m_spUnkSite;
if( m_spWebBrowser2 == NULL )
{
return E_FAIL;
}
CComQIPtr<IConnectionPointContainer,&IID_IConnectionPointContainer> spCPC(m_spWebBrowser2);
if(spCPC == NULL)
{
return E_FAIL;
}
// 查找到連接點
HRESULT hr = spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP);
if(FAILED(hr))
{
return hr;
}
if(inAdvise)
{
// 添加到連接點 (注冊)
hr = spCP->Advise(reinterpret_cast<IDispatch *>(this), &mCookie);
}else
{
// 反注冊
spCP->Unadvise(mCookie);
}
return hr;
}
其中成員聲明:
DWORD mCookie;
連接點注冊上去的索引,方便以后反注冊使用。
CComQIPtr<IWebBrowser2> m_spWebBrowser2;
m_spWebBrowser2 用來將瀏覽器IUnknown 指針轉變為 IWebBrowser2 ,并保存方便后面使用。
我們可以看到將 IDispatch 接口注冊上去了。 想想 COM組件應用(2)——IUnknown 中寫過的 QueryInterface的應用,我們就知道
這里把IDispatch 接口注冊上去,說明瀏覽器將可以調用IDispatch 的方法了。
查IDispatch 接口,主要核心在于實現 Invoke 函數。
1 STDMETHODIMP Invoke(DISPID dispidMember,REFIID riid, LCID lcid,
2 WORD wFlags, DISPPARAMS * pDispParams,
3 VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
4 UINT * puArgErr)
5 {
6 USES_CONVERSION;
7 if(!pDispParams)
8 {
9 return E_INVALIDARG;
10 }
11 switch(dispidMember)
12 {
13 case DISPID_BEFORENAVIGATE2:
14 {
15 CComBSTR strUrl;
16 if( m_spWebBrowser2 != NULL )
17 m_spWebBrowser2->get_LocationURL(&strUrl);
18
19 if (strUrl == CComBSTR("http://m.tkk7.com/JAVA-HE/"))
20 {
21 ::MessageBox(NULL, _T("該網頁是我的blog!"),_T("Warning"),MB_ICONSTOP);
22 return S_OK;
23 }
24
25 break;
26 }
27
28 case DISPID_NAVIGATECOMPLETE2:
29 break;
30 case DISPID_DOCUMENTCOMPLETE:
31 break;
32 case DISPID_DOWNLOADBEGIN:
33 break;
34 case DISPID_DOWNLOADCOMPLETE:
35 break;
36 case DISPID_NEWWINDOW2:
37 break;
38 case DISPID_QUIT:
39 RegisterEventHandler(FALSE);
40 break;
41 default:
42 break;
43 }
44
45 return S_OK;
46 }
上面是這次實例的范例代碼。有興趣的朋友可以照著敲下,下面還是講下這個函數里面的一些點:
I.最佳反注冊時機
case DISPID_QUIT:
RegisterEventHandler(FALSE);
在瀏覽器退出的時候,是最佳反注冊時機,不然可能瀏覽器退出后,你的BHO還在運行哦(有可能)
II. 有些宏需要引入頭文件
#include <exdisp.h >
#include <ExDispid.h>
III.當要使用ATL 編碼轉換時候在函數開頭引入 USES_CONVERSION; 宏,不過這里如果沒有轉換應用,可以去掉。
根據支持BHO特性,為了不讓資源管理器加載該BHO,所以在dll main 函數里加入如下代碼判斷是否加載:
if(dwReason == DLL_PROCESS_ATTACH)
{
TCHAR pszLoader[MAX_PATH];
GetModuleFileName(NULL,pszLoader,MAX_PATH);
_tcslwr(pszLoader);
if(_tcsstr(pszLoader,_T("explorer.exe")))
{
return FALSE;
}
}
posted on 2009-08-19 20:48
-274°C 閱讀(2675)
評論(0) 編輯 收藏 所屬分類:
C++