用Visual Studio 2008開發IE BHO (瀏覽器幫助物件)之一
這篇文章是應同學們的要求寫的,以前都是用VC++ 6.0+Platform SDK完成的. 遷移到 VS2008之後,原來Visual Studio 6.0裡的BHO嚮導不復存在,因此特此不厭其煩,詳細說明,本文也適用於VS2005.
首先談BHO的開發工具,我偏向使用VC++(unmanaged C++) 作為開發工具,因為Java JVM或.Net CLR的虛擬機器是個很笨重的東西,也是記憶體殺手, 並不具備寫plugin的快捷輕巧的特點.個人並不喜歡將其作為Plug-in的開發平臺,不過我會有另文說明用C#開發BHO的全過程, 作為那些偏重開發效率的同學的參考.
其次是類庫的選擇,我傾向利用“活動模板庫”(ATL) 來開發使用 C++ 的 BHO。之所以使用 ATL,是因為它方便地實現了我們可以按需進行擴充套件的基本樣板。儘管使用“Microsoft 基礎類”(MFC) 或 Win32 API 和 COM)也可以建立BHO,但 ATL 是為我們提供了自動處理許多細節的輕型庫,包括建立含有 BHO 類識別符號 (CLSID) 的登錄檔。
ATL 的另一個優勢在於它的 COM智慧感知指標類(例如,CComPtr 和 CComBSTR),這些類可管理 COM 物件的生命週期。例如,CComPtr 在賦值時會呼叫 AddRef,而在物件被銷燬或超出範圍時會呼叫 Release。智慧指標簡化了程式碼並且有助於避免記憶體洩漏。當在單個方法範圍內使用時,它們的穩定性和可靠性尤為有用。
介紹完ATL, 我們也簡單介紹一下BHO. BHO是將自定義功能新增到 Internet Explorer 的輕型 DLL 擴充套件,除了IE, BHO 還可以將功能新增到 Windows 資源管理器外殼程式.
BHO 通常並不提供其自身的任何使用者介面 (UI)。它們而是通過在後臺響應瀏覽器事件和使用者輸入資料來發揮作用。例如,BHO 可以攔截彈出視窗、自動填充窗體或為滑鼠手勢新增支援。
有一種常見誤解認為工具欄擴充套件項需要 BHO.但如果將 BHO 與工具欄配合使用,則可以實現更豐富的使用者體驗。(關於IE工具欄的程式設計,在另一篇文章中說明).
BHO 的生命週期與它所互動的瀏覽器例項的生命週期相等。在 IE 6 和早期版本中,這意味著要為每個新的頂層視窗建立(和銷燬)一個新 BHO。在IE 7中則是為每個選項卡都建立和銷燬一個新 BHO。
BHO 必須實現 IObjectWithSite 介面, 該介面提供了兩個方法GetSite和SetSite。根據MSDN的說明:
我們主要是對後者進行呼叫,此方法方便了與 Internet Explorer 的初始通訊,並會在其將要釋放時通知 BHO。我們實現此介面,然後將 BHO 的 CLSID 新增到登錄檔中,就可以建立一個簡單的瀏覽器擴充套件。過程如下:
1. 在Visual Studio中,選擇VC++中的ATL專案, 建立一個新的專案MySolutionPlugin, 在隨後的嚮導中,確認Server Type是Dll, Visual Studio會為我們建立程式的模板.
2. 為該專案新增我們的程式主體, (不熟悉visual studio的同學在資源瀏覽器裡的右鍵選單裡選 add-->class, 可別選到New Item), 型別選ATL Simple Object , short name命名為RayBHO,各項屬性如下:
a) “執行緒模型” ---“Apartment”
b) “聚合”---“否”
c) “介面”---“雙重”
d) “支援”---勾上“IobjectWithSite”。
具體的含義請參考MSDN.
一般來說,Internet Explorer 至少呼叫SetSite方法兩次: 一次用於建立連線,另一次則是在瀏覽器退出時。我們 BHO 中的 SetSite 實現將執行以下操作:
•儲存對站點的引用。在初始化期間,瀏覽器將 IUnknown 指標傳遞給頂層 WebBrowser 控制元件,然後 BHO 將對它的引用儲存在一個專用成員變數中。
•釋放目前被佔用的站點指標。Internet Explorer 傳遞 NULL 時,BHO 必須釋放所有介面引用並且斷開與瀏覽器的連線。
要實現SetSite,我們需手工在新增一個public的方法:
STDMETHOD 巨集是將方法標記為虛方法並且確保其具有適用於公共 COM 介面的呼叫約定的一個ATL 約定, 它有助於區分 COM 介面和該類中可能存在的其他公共方法。其實現成員方法時應相應使用 STDMETHODIMP 巨集。同時我們需要宣告一個私有變數來儲存Browser的指標"
然後是SetSite的實現
從上面的介紹我們知道, 初始化期間,瀏覽器將傳遞一個對其頂層 IWebBrowser2 介面(我們對其進行快取處理)的引用。瀏覽器關閉時將傳遞 NULL,為避免記憶體洩漏和迴圈引用計數,此時釋放所有指標和資源非常重要。最後,我們呼叫基類實現以便繼續執行介面合約的其餘部分。
載入DLL 後,系統將通過 DLL_PROCESS_ATTACH 通知呼叫 DllMain 函式。由於 Internet Explorer 大量使用多執行緒,因此,對 DllMain 的頻繁的 DLL_THREAD_ATTACH 和 DLL_THREAD_DETACH 通知會降低擴充套件和瀏覽器程式的整體效能。
如果BHO 不需要執行緒級的跟蹤,我們可以在 DLL_PROCESS_ATTACH 通知期間呼叫 DisableThreadLibraryCalls 以避免新執行緒通知的額外開銷。修改DllMain.cpp 中的DllMain函式:
要使BHO工作,我們還需要把BHO 的 CLSID 新增到登錄檔中。此條目會將 此DLL 標記為瀏覽器幫助程式物件,並使 Internet Explorer 在啟動時載入 BHO。我們可以在MySolutionPlugin.idl中找到該BHO的CLSID.幸運的,Visual Studio會幫助我們實現這些, 你看到:
您的機器的CLSID可能有所不同, 接著開啟RayBHO.rgs檔案,新增入:
這一段是為了在登錄檔裡新增一個雙位元組的NoExplorer=1的鍵,不讓Windows Explorer載入該BHO,因此該BHO只能在ie中執行.
你可以編譯這個BHO. 如果一切正常, 你可以在IE的管理載入項裡看到這個BHO.
如果不幸報錯: 該BHO無法被註冊,根據我的經驗,原因大概有2類,可以依次檢查
1. 你是否有管理員許可權以修改登錄檔,如不是管理員身份,可以在選單上右擊Microsoft Visual studio 2008,從右鍵選單中選擇"執行方式"...
2. 你的登錄檔條目語法是否正確,或者含有非法字元.
首先談BHO的開發工具,我偏向使用VC++(unmanaged C++) 作為開發工具,因為Java JVM或.Net CLR的虛擬機器是個很笨重的東西,也是記憶體殺手, 並不具備寫plugin的快捷輕巧的特點.個人並不喜歡將其作為Plug-in的開發平臺,不過我會有另文說明用C#開發BHO的全過程, 作為那些偏重開發效率的同學的參考.
其次是類庫的選擇,我傾向利用“活動模板庫”(ATL) 來開發使用 C++ 的 BHO。之所以使用 ATL,是因為它方便地實現了我們可以按需進行擴充套件的基本樣板。儘管使用“Microsoft 基礎類”(MFC) 或 Win32 API 和 COM)也可以建立BHO,但 ATL 是為我們提供了自動處理許多細節的輕型庫,包括建立含有 BHO 類識別符號 (CLSID) 的登錄檔。
ATL 的另一個優勢在於它的 COM智慧感知指標類(例如,CComPtr 和 CComBSTR),這些類可管理 COM 物件的生命週期。例如,CComPtr 在賦值時會呼叫 AddRef,而在物件被銷燬或超出範圍時會呼叫 Release。智慧指標簡化了程式碼並且有助於避免記憶體洩漏。當在單個方法範圍內使用時,它們的穩定性和可靠性尤為有用。
介紹完ATL, 我們也簡單介紹一下BHO. BHO是將自定義功能新增到 Internet Explorer 的輕型 DLL 擴充套件,除了IE, BHO 還可以將功能新增到 Windows 資源管理器外殼程式.
BHO 通常並不提供其自身的任何使用者介面 (UI)。它們而是通過在後臺響應瀏覽器事件和使用者輸入資料來發揮作用。例如,BHO 可以攔截彈出視窗、自動填充窗體或為滑鼠手勢新增支援。
有一種常見誤解認為工具欄擴充套件項需要 BHO.但如果將 BHO 與工具欄配合使用,則可以實現更豐富的使用者體驗。(關於IE工具欄的程式設計,在另一篇文章中說明).
BHO 的生命週期與它所互動的瀏覽器例項的生命週期相等。在 IE 6 和早期版本中,這意味著要為每個新的頂層視窗建立(和銷燬)一個新 BHO。在IE 7中則是為每個選項卡都建立和銷燬一個新 BHO。
BHO 必須實現 IObjectWithSite 介面, 該介面提供了兩個方法GetSite和SetSite。根據MSDN的說明:
- GetSite: Gets the last site set with IObjectWithSite::SetSite. If there is no known site, the object returns a failure code.
- SetSite: Provides the site's IUnknown pointer to the object.
GetSite: Gets the last site set with IObjectWithSite::SetSite. If there is no known site, the object returns a failure code.
SetSite: Provides the site's IUnknown pointer to the object.
我們主要是對後者進行呼叫,此方法方便了與 Internet Explorer 的初始通訊,並會在其將要釋放時通知 BHO。我們實現此介面,然後將 BHO 的 CLSID 新增到登錄檔中,就可以建立一個簡單的瀏覽器擴充套件。過程如下:
1. 在Visual Studio中,選擇VC++中的ATL專案, 建立一個新的專案MySolutionPlugin, 在隨後的嚮導中,確認Server Type是Dll, Visual Studio會為我們建立程式的模板.
2. 為該專案新增我們的程式主體, (不熟悉visual studio的同學在資源瀏覽器裡的右鍵選單裡選 add-->class, 可別選到New Item), 型別選ATL Simple Object , short name命名為RayBHO,各項屬性如下:
a) “執行緒模型” ---“Apartment”
b) “聚合”---“否”
c) “介面”---“雙重”
d) “支援”---勾上“IobjectWithSite”。
具體的含義請參考MSDN.
一般來說,Internet Explorer 至少呼叫SetSite方法兩次: 一次用於建立連線,另一次則是在瀏覽器退出時。我們 BHO 中的 SetSite 實現將執行以下操作:
•儲存對站點的引用。在初始化期間,瀏覽器將 IUnknown 指標傳遞給頂層 WebBrowser 控制元件,然後 BHO 將對它的引用儲存在一個專用成員變數中。
•釋放目前被佔用的站點指標。Internet Explorer 傳遞 NULL 時,BHO 必須釋放所有介面引用並且斷開與瀏覽器的連線。
要實現SetSite,我們需手工在新增一個public的方法:
- STDMETHOD(SetSite)(IUnknown * pUnkSite);
STDMETHOD(SetSite)(IUnknown * pUnkSite);
STDMETHOD 巨集是將方法標記為虛方法並且確保其具有適用於公共 COM 介面的呼叫約定的一個ATL 約定, 它有助於區分 COM 介面和該類中可能存在的其他公共方法。其實現成員方法時應相應使用 STDMETHODIMP 巨集。同時我們需要宣告一個私有變數來儲存Browser的指標"
- CComPtr<IWebBrowser2> m_spWebBrowser;//儲存Browser指標的私有變數
CComPtr<IWebBrowser2> m_spWebBrowser;//儲存Browser指標的私有變數
然後是SetSite的實現
- STDMETHODIMP CRayBHO::SetSite(IUnknown*pUnkSite)
- {
- if(pUnkSite!=NULL)
- {
- //快取指向IWebBrowser2的指標。
- pUnkSite->QueryInterface(IID_IWebBrowser2,(void**)&m_spWebBrowser);
- }
- else
- {
- //在此釋放快取的指標和其他資源。
- m_spWebBrowser.Release();
- }
- //返回基類實現
- return IObjectWithSiteImpl::SetSite(pUnkSite);
- }
STDMETHODIMP CRayBHO::SetSite(IUnknown*pUnkSite)
{
if(pUnkSite!=NULL)
{
//快取指向IWebBrowser2的指標。
pUnkSite->QueryInterface(IID_IWebBrowser2,(void**)&m_spWebBrowser);
}
else
{
//在此釋放快取的指標和其他資源。
m_spWebBrowser.Release();
}
//返回基類實現
return IObjectWithSiteImpl::SetSite(pUnkSite);
}
從上面的介紹我們知道, 初始化期間,瀏覽器將傳遞一個對其頂層 IWebBrowser2 介面(我們對其進行快取處理)的引用。瀏覽器關閉時將傳遞 NULL,為避免記憶體洩漏和迴圈引用計數,此時釋放所有指標和資源非常重要。最後,我們呼叫基類實現以便繼續執行介面合約的其餘部分。
載入DLL 後,系統將通過 DLL_PROCESS_ATTACH 通知呼叫 DllMain 函式。由於 Internet Explorer 大量使用多執行緒,因此,對 DllMain 的頻繁的 DLL_THREAD_ATTACH 和 DLL_THREAD_DETACH 通知會降低擴充套件和瀏覽器程式的整體效能。
如果BHO 不需要執行緒級的跟蹤,我們可以在 DLL_PROCESS_ATTACH 通知期間呼叫 DisableThreadLibraryCalls 以避免新執行緒通知的額外開銷。修改DllMain.cpp 中的DllMain函式:
- extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
- {
- if(dwReason==DLL_PROCESS_ATTACH)
- {
- DisableThreadLibraryCalls(hInstance);
- }
- return _AtlModule.DllMain(dwReason,lpReserved);
- }
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if(dwReason==DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hInstance);
}
return _AtlModule.DllMain(dwReason,lpReserved);
}
要使BHO工作,我們還需要把BHO 的 CLSID 新增到登錄檔中。此條目會將 此DLL 標記為瀏覽器幫助程式物件,並使 Internet Explorer 在啟動時載入 BHO。我們可以在MySolutionPlugin.idl中找到該BHO的CLSID.幸運的,Visual Studio會幫助我們實現這些, 你看到:
- importlib("stdole2.tlb");
- [
- uuid(057F3E68-6C2E-40A5-A641-E8CF9D6766F3),
- helpstring("RayBHO Class")
- ]
importlib("stdole2.tlb");
[
uuid(057F3E68-6C2E-40A5-A641-E8CF9D6766F3),
helpstring("RayBHO Class")
]
您的機器的CLSID可能有所不同, 接著開啟RayBHO.rgs檔案,新增入:
- HKLM
- {
- NoRemove SOFTWARE
- {
- NoRemove Microsoft
- {
- NoRemove Windows
- {
- NoRemove CurrentVersion
- {
- NoRemove Explorer
- {
- NoRemove 'Browser Helper Objects'
- {
- ForceRemove {057F3E68-6C2E-40A5-A641-E8CF9D6766F3} = s 'RayBHO Class'
- {
- val NoExplorer = d '1'
- }
- }
- }
- }
- }
- }
- }
- }
HKLM
{
NoRemove SOFTWARE
{
NoRemove Microsoft
{
NoRemove Windows
{
NoRemove CurrentVersion
{
NoRemove Explorer
{
NoRemove 'Browser Helper Objects'
{
ForceRemove {057F3E68-6C2E-40A5-A641-E8CF9D6766F3} = s 'RayBHO Class'
{
val NoExplorer = d '1'
}
}
}
}
}
}
}
}
這一段是為了在登錄檔裡新增一個雙位元組的NoExplorer=1的鍵,不讓Windows Explorer載入該BHO,因此該BHO只能在ie中執行.
你可以編譯這個BHO. 如果一切正常, 你可以在IE的管理載入項裡看到這個BHO.
如果不幸報錯: 該BHO無法被註冊,根據我的經驗,原因大概有2類,可以依次檢查
1. 你是否有管理員許可權以修改登錄檔,如不是管理員身份,可以在選單上右擊Microsoft Visual studio 2008,從右鍵選單中選擇"執行方式"...
2. 你的登錄檔條目語法是否正確,或者含有非法字元.
相關文章
- IE瀏覽器開發瀏覽器
- IE瀏覽器外掛開發瀏覽器
- Win10開啟IE瀏覽器方法 Win10怎麼用IE瀏覽器?Win10瀏覽器
- 微軟推跨平臺IE瀏覽器 用於開發測試微軟瀏覽器
- microsoft edge是ie瀏覽器嗎 edge瀏覽器和ie瀏覽器一樣嗎ROS瀏覽器
- IE瀏覽器相容瀏覽器
- ie瀏覽器開啟變成別的瀏覽器怎麼辦 開啟ie瀏覽器變成360怎麼改瀏覽器
- .net火狐瀏覽器 ie瀏覽器 判斷瀏覽器
- javascript相容低版本IE瀏覽器的事件物件JavaScript瀏覽器事件物件
- 惡搞IE瀏覽器瀏覽器
- ie瀏覽器開啟怎麼是360導航 ie每次開啟都是360瀏覽器怎麼解決瀏覽器
- ie瀏覽器怎麼升級 ie瀏覽器版本過低怎麼辦瀏覽器
- 建立相容IE6瀏覽器的ajax請求物件瀏覽器物件
- win10有沒有ie瀏覽器?win10系統怎麼開啟ie瀏覽器Win10瀏覽器
- ie瀏覽器在電腦哪裡 電腦自帶的ie瀏覽器怎麼開啟使用瀏覽器
- 微軟IE瀏覽器正式退役微軟瀏覽器
- c#控制IE瀏覽器C#瀏覽器
- IE 瀏覽器的創新瀏覽器
- IE瀏覽器的安全(轉)瀏覽器
- 自己的IE——用VB製作瀏覽器 (轉)瀏覽器
- ie瀏覽器打不開網頁怎麼辦 網路正常但是ie瀏覽器打不開解決方法瀏覽器網頁
- 替代Edge瀏覽器?微軟開發新的瀏覽器:採用Chrome核心瀏覽器微軟Chrome
- 微軟: 是時候開源IE瀏覽器了微軟瀏覽器
- 微軟協助谷歌開發Chrome瀏覽器,高通或有參與微軟谷歌Chrome瀏覽器
- 怎麼調出ie瀏覽器_win10 ie瀏覽器怎麼調出來瀏覽器Win10
- edge是什麼瀏覽器 microsoft edge是ie瀏覽器嗎瀏覽器ROS
- IE瀏覽器版本的判斷瀏覽器
- VB操作IE瀏覽器完全控制瀏覽器
- 瀏覽器之爭:程式設計師眼裡瀏覽器的地位 IE:我開了!瀏覽器程式設計師
- 瀏覽器之爭:程式設計師眼裡瀏覽器的地位IE:我開了!瀏覽器程式設計師
- 微軟是時候把IE瀏覽器開源了微軟瀏覽器
- ie瀏覽器退役後還能用嗎 ie瀏覽器關閉停用以後怎麼辦瀏覽器
- ie瀏覽器相容模式怎麼設定在哪裡 ie瀏覽器相容模式設定方法瀏覽器模式
- JavaScript瀏覽器事件物件JavaScript瀏覽器事件物件
- 在Visual Studio 中使用git——瀏覽版本庫(七)Git
- Visual Studio 2008中的Linq開發技術
- edge怎麼改成ie 怎麼把預設瀏覽器從edge恢復到ie瀏覽器瀏覽器
- 如何判斷IE瀏覽器的版本瀏覽器