青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

勤能補拙,Expter

成都游戲Coder,記錄游戲開發過程的筆記和心得!

如何使用BHO定制你的Internet Explorer瀏覽器

原文出處:Browser Helper Objects: The Browser the Way You Want It
一、簡介
  有時,你可能需要一個定制版本的瀏覽器。在這種情況下,你可以自由地把一些新穎但又不標準的特征增加到一個瀏覽器上。結果,你最終有的只是一個新但不標準的瀏覽器。Web瀏覽器控件只是瀏覽器的分析引擎。這意味著仍然存在若干的與用戶接口相關的工作等待你做――增加一個地址欄,工具欄,歷史記錄,狀態欄,頻道欄和收藏夾等。如此,要產生一個定制的瀏覽器,你可以進行兩種類型的編程――一種象微軟把Web瀏覽器控件轉變成一個功能齊全的瀏覽器如Internet Explorer;一種是在現有的基礎上加一些新的功能。如果有一個直接的方法定制現有的Internet Explorer該多好?BHO(Browser Helper Objects,我譯為"瀏覽器幫助者對象",以下皆簡稱BHO)正是用來實現此目的的。
二、關于軟件定制
  以前,定制一個軟件的行為主要是通過子類化方法實現的。 通過這種辦法,你可以改變一個窗口的外表與行為。子類化雖然被認為是一種有點暴力方式――受害者根本不知道發生的事情――但它還是長時間以來的唯一的選擇。
  隨著微軟Win32 API的到來,進程間子類化不再被鼓勵使用并愈發變得困難起來。當然,如果你是勇敢的--指針從未嚇倒你,而最重要的是,如果你已經游刃于系統鉤子之間,你可能覺得這一問題太簡單了。 但是情形并不總是這樣。暫放下這點不管,問題在于每一個進程運行在自己的地址空間中,而且打破進程邊界略微有些不正確性。 另一方面, 你可能需要對定制進行更好的管理。更經常情況下,定制可能是程序本身強烈要求實現的。
  在后者情況下,已安裝的軟件只需在既定的磁盤位置查詢另外的組件模塊,然后裝載、設定初值,最后讓它們自由地按照既定的設計工作。這正是Internet Explorer瀏覽器和它的BHO所要實現的。
三、什么是BHO?
  從某種觀點看,Internet Explorer同普通的Win32程序沒有什么兩樣。借助于BHO,你可以寫一個進程內COM對象,這個對象在每次啟動時都要加載。這樣的對象會在與瀏覽器相同的上下文中運行,并能對可用的窗口和模塊執行任何行動。例如,一個BHO能夠探測到典型的事件,如GoBack、GoForward、DocumentComplete等;另外BHO能夠存取瀏覽器的菜單與工具欄并能做出修改,還能夠產生新窗口來顯示當前網頁的一些額外信息,還能夠安裝鉤子以監控一些消息和動作。簡而言之, BHO的工作如我們打入瀏覽器領地的一位間諜(注意這是微軟允許的合法工作)。
  在進一步了解BHO細節之前,有幾點我需要進一步闡述。首先,BHO對象依托于瀏覽器主窗口。實際上,這意味著一旦一個瀏覽器窗口產生,一個新的BHO對象實例就要生成。任何 BHO對象與瀏覽器實例的生命周期是一致的。其次, BHO僅存在于Internet Explorer 4.0及以后版本中。
如果你在使用Microsoft Windows? 98, Windows 2000, Windows 95, or Windows NT版本4.0 操作系統的話,也就一塊運行了活動桌面外殼4.71,BHO也被 Windows資源管理器所支持。 BHO是一個COM進程內服務,注冊于注冊表中某一鍵下。在啟動時,Internet Explorer查詢那個鍵并把該鍵下的所有對象預以加載。
  Internet Explorer瀏覽器初始化這一對象并要求某一接口功能。如果發現這一接口, Internet Explorer使用其提供的方法傳遞 IUnknown 指針到BHO對象。見圖一:

圖一 ie瀏覽器如何裝入和初始化BHO對象,BHO場所(site)是用于實現通信的COM接口
  瀏覽器可能在注冊表中發現一系列的CLSID,并由此為每個CLSID建立一個進程中實例。結果是,這些對象被裝載至瀏覽器上下文中并運行起來,好象它們是本地組件一樣。但是,由于Internet Explorer的COM特性,即使被裝入到它的進程空間中于事(你的野心實現)也不一定會有多大幫助。用另一說法, BHO的確能夠做許多潛在的有用的事情,如子類化組成窗口或者安裝線程局部鉤子,但是它確實遠離瀏覽器的核心活動。為了鉤住瀏覽器的事件或者自動化瀏覽器,BHO需要建立一個私有的基于COM的通訊通道。為此,該BHO應該實現一個稱為IObjectWithSite的接口。事實上,通過接口IobjectWithSite, Internet Explorer 可以傳遞它的IUnknown 接口。BHO反過來能夠存儲該接口并進一步查詢更專門的接口,如IWebBrowser2、IDispatch和IConnectionPointContainer。
  另外一種分析BHO對象的途徑與Internet Explorer外殼擴展有關。我們知道,一個WINDOWS外殼擴展即是一個進程內的COM服務器,它在Windows資源管理器執行某種動作時裝入內存――如顯示上下文菜單。通過建立一個實現幾個COM接口的COM模塊,你就給上下文菜單加上一些項并能預以正確處理。一個外殼擴展必須以Windows資源管理器能夠發現的方法注冊。一個BHO對象遵循同樣的模式――唯一的改變在于要實現的接口。然而,盡管實現方式有所不同,外殼擴展與 BHO 仍有許多共同的特點。如下表一:
表一 外殼擴展與 BHO相近特性比較

特性
外殼擴展
BHO對象

加載者
Windows資源管理器
Internet Explorer(和外殼4.17及以上版本的Windows資源管理器)

擊活動作
在某類文檔上的用戶動作(即單擊右鍵)
打開瀏覽器窗口

何時卸載
參考計數達到0的幾秒之后
導致它加載的窗口關閉時

實現形式
COM進程中DLL
COM 進程中 DLL

注冊需求
常常是為一個COM服務器設置的入口處,另加的入口依賴于外殼類型及它要應用至的文檔類型
常常是為一個COM服務器設置的入口處,另加一個把它申請為BHO的注冊入口

接口需求
依賴于外殼擴展的類型
IObjectWithSite

如果你對SHELL擴展編程有興趣的話,可以參考MSDN有關資料。
四、BHO的生存周期
  前面已經說過,BHO不僅僅為Internet Explorer所支持。如果你在使用外殼 4.71或者更高版本,你的BHO對象也會被Windows資源管理器所加載。下表二展示了我們可以使用的不同版本的外殼產品情況,Windows外殼版本號存于庫文件shell32.dll中。
表二 不同版本的Windows外殼對于BHO的支持情況

外殼版本
安裝的產品
BHO的支持情況

4.00
Windows 95,Windows  NT 4.0 帶或不帶 Internet Explorer 4.0 或更老版本。 注意沒有安裝外殼更新
Internet Explorer 4.0

4.71
Windows 95,Windows NT 4.0 帶Internet Explorer 4.0 和活動桌面外殼更新
Internet Explorer 與Windows 資源管理器

4.72
Windows 98
Internet Explorer與Windows 資源管理器

5.00
Windows 2000
Internet Explorer與Windows 資源管理器

  BHO對象隨著瀏覽器主窗口的顯示而裝入,隨著瀏覽器主窗口的銷毀而缷載。如果你打開多個瀏覽器窗口,多個BHO實例也一同產生。
  無論瀏覽器以什么樣的命令行啟動,BHO對象都被加載。舉例來說,即使你只是想要見到特定的 HTML 頁或一個給定的文件夾,BHO對象也被加載。一般地,當 explorer.exe 或 iexplore.exe 運行的時候,BHO都要被考慮在內。如果你設置了"Open each folder in its own window"(對每一個文件夾以一個獨立窗口打開)文件夾選項,那么你每次打開一個文件夾,BHO對象都要被加載。見圖二。

圖二 經過這樣設置,你每次打開一個文件夾時,執行一個獨立的explorer.exe實例,并裝入已注冊的BHO對象。
  但是注意,這種情形僅適于當你從桌面上的"我的電腦"圖標中打開文件夾的情況。在這種情況下,每次你移到另外一個文件夾時外殼都要調用explorer.exe。這種情況在你同時用兩個窗格進行瀏覽時是不會發生的。事實上,當你改變文件夾時,外殼是不會啟動瀏覽器的新的實例的而僅是簡單創建嵌入視圖對象的另外一個實例。奇怪的是,如果你在地址欄中輸入一個新的名字來改變文件夾時,在同一個窗口中同樣可以達到瀏覽之目的,無論Windows資源管理器視圖是單個的還是雙視圖形式。
  對于Internet Explorer的情形,事情要更簡單一些。只有你顯式地多次運行iexplore.exe瀏覽器時,你才有多個Internet Explorer的拷貝。當你從Internet Explorer中打開新的窗口時,每一個窗口在一個新的線程中被復制而不是創建一個新的進程,因此也就不需要重新載入BHO對象。
  首先,BHO最有趣的地方是,它是極度動態的。每次Windows資源管理器或者Internet Explorer打開,裝載器從注冊表中讀取已安裝的BHO對象的CLSID然后處理它們。如果你在打開的瀏覽器多個實例中間編輯注冊表的話,你可以隨著多個瀏覽器拷貝的載入而裝入多個不同的BHO。 這就是說,如果你選擇從頭創建一個新的屬于自己的瀏覽器,那么你可以把它內嵌在一個Visual Basic或者MFC框架窗口中。同時你有相當的機會來靈活安排瀏覽程序。如果它們能滿足你的需要的話,你可以依賴于Internet Explorer的強大的功能并且加上你想要的盡可能多的插件。
五、關于IObjectWithSite接口
  從一個高起點來看,BHO即是一個DLL,它能夠依附于Internet Explorer瀏覽器的一個新建的實例,在某些情況下也適用于Windows資源管理器。
  一般地,一個場所(site)是一個中間對象,它位于容器對象與被包容對象之間。通過它,容器對象管理被包容對象的內容,也因此使得對象的內部功能可用。為此,容器方要實現接口IoleClientSite,被包容對象要實現接口IOleObject 。通過調用IOleObject提供的方法,容器對象使得被包容對象清楚地了解其HOST的環境。
  一旦容器對象成為Internet Explorer(或是具有WEB能力的Windows資源管理器),被包容對象只需實現一個輕型的IObjectWithSite接口。該接口提供了以下方法:
表三 IObjectWithSite定義

方法
描述

HRESULT SetSite(IUnknown* pUnkSite)
接收ie瀏覽器的IUnknown指針。典型實現是保存該指針以備將來使用。.

HRESULT GetSite(REFIID riid, void** ppvSite)
從通過SetSite()方法設置的場所中接收并返回指定的接口,典型實現是查詢前面保存的接口指針以進一步取得指定的接口。

  對BHO 的唯一嚴格的要求正在于必須實現這一個接口。 注意你應該避免在調用以上任何一個函數時返回E_NOTIMPL 。 要么你不實現這一接口,要么應保證在調用這些方法時進行正確地編碼。
六、構造自己的BHO對象
  一個BHO對象就是一個進程中服務器DLL,選用ATL創建它是再恰當不過的了。我們選擇ATL的另外一個原因是因為它已經提供了缺省的而且提供了IObjectWithSite接口的足夠好的實現。另外,在ATL COM 向導本地支持的已定義好的對象類型當中,有一個,就是Internet Explorer對象,這正是一個BHO應該具有的類型。一個 ATL Internet Explorer 對象,事實上是一個簡單對象――也就是說,是一個支持IUnknown和自注冊,還有接口IObjectWithSite的COM 服務器。如果你在ATL工程中添加一個這樣的對象,并調用相應的類CViewSource,你將從向導中得到下列代碼:

class ATL_NO_VTABLE CViewSource :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CViewSource, &CLSID_ViewSource>,
public IObjectWithSiteImpl<CViewSource>,
public IDispatchImpl<IViewSource, &IID_IViewSource,
&LIBID_HTMLEDITLib>      
  正如你所見,向導已經使類從接口IObjectWithSiteImpl繼承,這是一個ATL模板類,它提供了接口IObjectWithSite的基本實現。一般情況下,沒有必要重載成員函數GetSite()。取而代之的是, SetSite() 實現代碼經常需要加以定制。ATL實際上僅僅把一個IUnknown接口指針存儲在成員變量m_spUnkSite中。
  在文章的剩余部分,我將討論一個 BHO 的相當復雜而豐富的例子。該BHO對象將依附于Internet Explorer,并顯示一個文本框來顯示當前正瀏覽的網頁源碼。 該代碼窗口將 隨著你改變網頁而自動更新,如果瀏覽器顯示的不是一個HTML網頁時,它將變灰。你對于原始HTML代碼的任何改動立即反映在瀏覽器中。HTML (DHTML)使得這一看似魔術般的實現成為可能。該代碼窗口可被隱藏和通過按動熱鍵重現。 在可見情況下,它與Internet Explorer共享整個桌面空間,見圖三。

圖三 BHO對象在使用中。它依附于Internet Explorer,并顯示一個窗口來顯示當前正瀏覽的網頁源碼。還允許你源碼進行修改。
  本例子的關鍵點在于存取Internet Explorer的瀏覽機制,其實它只不過是WebBrowser控件的一個實例而已。這個例子可以分解為以下五步來實現:
  1. 探測誰在裝入這個對象,是Internet Explorer還是Windows資源管理器;
  2. 獲取接口IWebBrowser2以實現Web瀏覽器對象;
  3. 捕捉Web瀏覽器的特定事件;
  4. 存取當前文檔對象,確定它是一份HTML類型的文件;
  5. 管理對話框窗口以實現HTML源碼的顯示;

  第一個步驟是在DllMain()中完成的。SetSite()是取得指向WebBrowser對象指針的適當位置。請詳細分析以下步驟。
七、探測誰在調用這個對象
  如前所述,一個BHO對象會被Internet Explorer或者Windows資源管理器(前提:外殼版本4.71或者更高)所加載。所以我專門設計了一個BHO來處理HTML網頁,因此這個BHO與資源管理器毫無關系。如果一個Dll不想被調用者一起加載,只需在DllMain()中實現了探明誰在調用該對象后返回FALSE即可。參看下面代碼:

if (dwReason == DLL_PROCESS_ATTACH)
{
TCHAR pszLoader[MAX_PATH];
//返回調用者模塊的名稱,第一個參數應為NULL,詳見msdn。
GetModuleFileName(NULL, pszLoader, MAX_PATH);
_tcslwr(pszLoader);
if (_tcsstr(pszLoader, _T("explorer.exe")))
return FALSE;
}
一旦知道了當前進程是Windows資源管理器,可立即退出。
  注意,再多加一些條件語句是危險的!事實上,另外一些進程試圖裝入該DLL時將被放棄。如果你做另外一個試驗,比方說針對Internet Explorer的執行文件iexplorer.exe,這時第一個受害者就是regsvr32.exe(該程序用于自動注冊對象)。
if (!_tcsstr(pszLoader, _T("iexplore.exe")))
  你不能夠再次注冊該DLL庫了。 事實上,當 regsvr32.exe 試圖裝入DLL以激活函數DllRegisterServer()時,該調用將被放棄。
八、與Web瀏覽器取得聯系
  SetSite()方法正是BHO對象被初始化的地方,此外,在這個方法中你可以執行所有的僅僅允許發生一次的任務。當你用Internet Explorer打開一個URL時,你應該等待一系列的事件以確保要求的文檔已完全下載并被初始化。唯有在此時,你才可以通過對象模型暴露的接口(如果存在的話)存取文檔內容。這就是說你要取得一系列的指針。第一個就是指向IWebBrowser2(該接口用來生成WebBrowser對象)的指針。第二個指針與事件有關。該模塊必須作為一個瀏覽器的事件偵聽器來實現,目的是為接收下載以及與文檔相關的事件。下面用ATL靈敏指針加以封裝:
CComQIPtr< IWebBrowser2, &IID_IWebBrowser2> m_spWebBrowser2;
CComQIPtr<IConnectionPointContainer,
&IID_IConnectionPointContainer> m_spCPC;
源代碼部分如下所示:
HRESULT CViewSource::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;
//檢索并存儲瀏覽器的句柄HWND. 并且安裝一個鍵盤鉤子備后用
RetrieveBrowserWindow();
// 為接受事件通知連接到容器
return Connect();
}
  為了取得IWebBrowser2接口指針,你可以進行查詢。當然也可以在事件剛剛發生時查詢IConnectionPointContainer。這里,SetSite()檢索了瀏覽器的句柄HWND,并且在當前線程中安裝了一個鍵盤鉤子。HWND用于后面Internet Explorer窗口的移動或尺寸調整。這里的鉤子用來實現熱鍵功能,用戶可以按動熱鍵來顯示/隱藏代碼窗口。
九、從Internet Explorer瀏覽器取得事件
  當你導向一個新的URL時,瀏覽器最需要完成的是兩種事件:下載文檔并為之準備HOST環境。也就是說,它必須初始化某對象并使該對象從外部可以利用。針對不同的文檔類型,或者裝入一個已注冊的Microsoft ActiveX? 服務器來處理該文檔(如Word對于.doc文件的處理)或者初始化一些內部組件來分析文檔內容并生成和顯示該文檔。對于HTML網頁就是這樣,其內容由于DHTML對象作用而變得可用。當文檔全部下載結束,DownloadComplete事件被激活。這并不是說,這樣利用對象模型就可以安全地管理文檔的內容了。事實上,DocumentComplete 事件僅指明一切已經結束,文檔已準備好了 (注意DocumentComplete事件僅在你第一次存取URL時到達,如果你執行了刷新動作,你僅僅收到一個DocumentComplete事件)。
  為了截獲瀏覽器發出的事件, BHO需要通過IConnectionPoint 接口連接到瀏覽器上 并且實現傳遞接口IDispatch指針以處理各種事件。現在利用前面取得的IConnectionPointContainer指針來調用FindConnectionPoint方法――它返回一個指針指向連接點對象(正是通過這個連接點對象來取得要求的外向接口,此時是DIID_DWebBrowserEvent2)。 下列代碼顯示了連接點的發生情況:
HRESULT CViewSource::Connect(void)
{
HRESULT hr;
CComPtr<IConnectionPoint> spCP;
//為Web瀏覽器事件而接收(receive)連接點
hr = m_spCPC->FindConnectionPoint(DIID_DWebBrowserEvent2, &spCP);
if (FAILED(hr))
return hr;
// 把事件處理器傳遞到容器。每次事件發生容器都將激活我們實現的IDispatch接口上的相應的函數。
hr = spCP->Advise( reinterpret_cast<IDispatch*>(this), &m_dwCookie);
return hr;
}
  通過調用接口IConnectionPoint的Advise() 方法, BHO告訴瀏覽器它對它產生的事件很感興趣。 由于COM事件處理機制,所有這些意味著BHO把IDispatch接口指針提供給瀏覽器。瀏覽器將回調IDispatch接口的Invoke() 方法,以事件的ID值作為第一參數:
HRESULT CViewSource::Invoke(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,
VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
if (dispidMember == DISPID_DOCUMENTCOMPLETE) {
OnDocumentComplete();
m_bDocumentCompleted = true;
}
:
}
  切記,當事件不再需要時,應該使之與瀏覽器分離。如果你忘記了做這件事情,BHO對象將被鎖定,即使在你關閉瀏覽器窗口之后。很明顯,實現分離的最佳時機是收到事件OnQuit時。
十、存取文檔對象
  此時,該BHO已經有一個參照指向Internet Explorer的Web瀏覽器控件并被連接到瀏覽器控件以接收所有它產生的事件。當網頁被全部下載并正確初始化后,我們就可以通過DHTML文檔模型存取它。Web瀏覽器的文檔屬性返回一個指向文檔對象的IDispatch接口的指針:
CComPtr<IDispatch> pDisp;
HRESULT hr = m_spWebBrowser2->get_Document(&pDisp);
  get_Document() 方法取得的僅僅是一個接口指針。我們要進一步確定在IDispatch 指針背后存在一個HTML文檔對象。用VB實現的話,可以用下面代碼:
Dim doc As Object
Set doc = WebBrowser1.Document
If TypeName(doc)="HTMLDocument" Then
'' 獲取文檔內容并予以顯示
Else
'' Disable the display dialog
End If
  現在要了解一下get_Document()返回的IDispatch指針 。Internet Explorer不僅僅是一個HTML瀏覽器,而且還是一個ActiveX文檔容器。 這樣一來,難以保證當前瀏覽對象就是一個HTML文檔。不過辦法還是有的――你想,如果IDispatch指針真正指向一個HTML文檔,查詢IHTMLDocument2 接口一定成功。
IHTMLDocument2接口包裝了DHTML對象模型用來展現HTML頁面的所有功能。下面代碼實現這些功能:
CComPtr<IDispatch> pDisp;
HRESULT hr = m_spWebBrowser2->get_Document(&pDisp);
CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2> spHTML;
spHTML = pDisp;
if (spHTML) {
// 獲取文檔內容并予以顯示
}
else {
// disable the Code Window controls
}
如果IHTMLDocument2接口查詢失敗,spHTML指針將是NULL。
  現在考慮如何獲得當前顯示窗口的源代碼。正如一個HTML頁把它所有的內容封裝在標簽<BODY>中,DHTML對象模型要求你取得一個指向Body對象的指針:
CComPtr<IHTMLElement> m_pBody;
hr = spHTML->get_body(&m_pBody);
  奇怪的是,DHTML對象模型不讓你取得標簽<BODY>之前的原始內容,如<HEAD>。其內容被處理并存于一些屬性中,但你還是不能從HTML原始文件中提取這部分的RAW文本。這過,僅從BODY部分取得的內容足夠了。為了取得包含在<BODY>…</BODY>間的HTML代碼部分,可以把outerHTML屬性內容讀取到一個BSTR變量中:
BSTR bstrHTMLText;
hr = m_pBody->get_outerHTML(&bstrHTMLText);
  在此基礎上,在代碼窗口中顯示源碼就是一種簡單的事情了:生成一個窗口,進行字符的UNICODE至ANSI轉化和設置編輯框控件的問題。下面代碼實現這些功能:
HRESULT CViewSource::GetDocumentContent()
{
USES_CONVERSION;
// 獲取 WebBrowser的文檔對象
CComPtr<IDispatch> pDisp;
HRESULT hr = m_spWebBrowser2->get_Document(&pDisp);
if (FAILED(hr))
return hr;
// 確保我們取得的是一個IHTMLDocument2接口指針
//讓我們查詢一下 IHTMLDocument2 接口 (使用靈敏指針)
CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2> spHTML;
spHTML = pDisp;
// 抽取文檔源代碼
if (spHTML)
{
// 取得BODY 對象
hr = spHTML->get_body(&m_pBody);
if (FAILED(hr))
return hr;
// 取得HTML 文本
BSTR bstrHTMLText;
hr = m_pBody->get_outerHTML(&bstrHTMLText);
if (FAILED(hr))
return hr;
// 進行文本的Unicode到 ANSI的轉換
LPTSTR psz = new TCHAR[SysStringLen(bstrHTMLText)];
lstrcpy(psz, OLE2T(bstrHTMLText));
// 文本進行相應的調整
HWND hwnd = m_dlgCode.GetDlgItem(IDC_TEXT);
EnableWindow(hwnd, true);
hwnd = m_dlgCode.GetDlgItem(IDC_APPLY);
EnableWindow(hwnd, true);
// 設置代碼窗口中的文本
m_dlgCode.SetDlgItemText(IDC_TEXT, psz);
delete [] psz;
}
else   // 文檔不是一個 HTML 頁
{
m_dlgCode.SetDlgItemText(IDC_TEXT, "");
HWND hwnd = m_dlgCode.GetDlgItem(IDC_TEXT);
EnableWindow(hwnd, false);
hwnd = m_dlgCode.GetDlgItem(IDC_APPLY);
EnableWindow(hwnd, false);
}
return S_OK;
}
  因為我要運行這段代碼來響應DocumentComplete事件通知,每個新的頁自動地而且敏捷地被處理。DHTML對象模型使你能夠隨意修改網頁的結構,但這一變化在按F5刷新后全部復原。你還要處理一下DownloadComplete事件以刷新代碼窗口 (注意, DownloadComplete 事件發生在 DocumentComplete事件之前)。你應該忽略網頁的首次DownloadComplete事件,而是在執行刷新動作時才關注這一事件。布爾成員變量m_bDocumentCompleted正是用來區別這兩種情形的。
十一、管理代碼窗口
  用來顯示當前HTML頁原始碼的代碼窗口涉及另外一個ATL 基本編程問題-對話框窗口,它位于ATL對象向導的"Miscellaneous"選項卡下。
  我調整了代碼窗口的大小來響應WM_INITDIALOG消息,使它占居桌面空間的下部區域,正好是在任務欄的上面。在瀏覽器啟動時你可以選擇顯示或不顯示這個窗口。缺省情況下是顯示的,但這可以通過清除"Show window at startup"復選框項來實現。當然喜歡的話,你可以隨時關閉。按鍵F12即可重新顯示代碼窗口。F12是通過在SetSite()中安裝的鍵盤鉤子實現的。啟動環境存于WINDOWS注冊表中,我選擇外殼庫文件shlwapi.dll中函數SHGetValue來實現注冊表的讀寫操作。這同使用Reg開頭的Win32函數操作相比,簡單極了。請看:
DWORD dwType, dwVal;
DWORD dwSize = sizeof(DWORD);
SHGetValue(HKEY_CURRENT_USER, _T("Software\\MSDN\\BHO"), _T("ShowWindowAtStartup"), &dwType, &dwVal, &dwSize);
這個DLL文件是同Internet Explorer 4.0 和活動桌面的誕生一起產生的,是WIN98及以后版本的標準組成,你可以放心使用。
十二、注冊BHO對象
  因為BHO 是一個COM 服務器,所以既應該作為COM 服務器注冊又應該作為BHO對象注冊。ATL向導自動生成.rgs文件,第一種情況的注冊就免除了。下面的文件代碼段是用來實現作為BHO對象注冊的(CLSID為例中生成)。
HKLM {
SOFTWARE {
Microsoft {
Windows {
CurrentVersion {
Explorer {
''BHO'' {
ForceRemove {1E1B2879-88FF-11D2-8D96-D7ACAC95951F}
}}}}}}}
  注意ForceRemove一詞能夠實現在卸載對象時刪除這一行相應的鍵值。BHO鍵下聚集了所有的BHO對象。對于這么多的一串家伙是從來不作緩沖調用的。這樣以來,安裝與測試BHO就是不費時的事情了。
十三、總結
  本文描述了BHO對象,通過它你可以把自己的代碼注入瀏覽器的地址空間中。你必須做的事情是寫一個支持IObjectWithSite 接口的COM 服務器。在這一點上,你的BHO對象可以實現瀏覽器機制范圍內的各種合法目的。本文所及示例涉及了COM事件,DHTML對象模型以及WEB瀏覽器編程接口。雖然內容稍寬一些,但它正顯示了現實世界中的BHO對象的應用。如,你想知道瀏覽器在顯示什么,那么您就需要了解接收事件并要熟悉WEB瀏覽器才行。
  另外:Windows資源管理器也是與BHO對象交互的,這一點在編程時要特別注意。本文所附源程序為MSDN所帶,在Windows2000/VC6下調試通過(編譯通過后,重新啟動IE即得到結果).

posted on 2009-07-26 19:43 expter 閱讀(565) 評論(0)  編輯 收藏 引用

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精品日本| 性刺激综合网| 欧美激情精品久久久| 在线免费不卡视频| 快she精品国产999| 另类激情亚洲| 宅男66日本亚洲欧美视频| 日韩视频在线观看免费| 国产精品wwwwww| 欧美亚洲免费电影| 欧美与黑人午夜性猛交久久久| 国产在线观看一区| 欧美fxxxxxx另类| 欧美日韩精品一区二区| 欧美亚洲免费| 巨乳诱惑日韩免费av| 亚洲九九九在线观看| 亚洲一区二区成人在线观看| 在线亚洲一区二区| 99精品国产高清一区二区| 欧美日韩性生活视频| 香港久久久电影| 久久理论片午夜琪琪电影网| 一区二区三区视频在线看| 亚洲欧美日韩国产综合| 亚洲国产日韩精品| 亚洲一区国产精品| 亚洲国产日韩一区二区| 亚洲视频在线一区| 最近中文字幕mv在线一区二区三区四区 | 麻豆久久精品| 欧美日韩一区成人| 美国三级日本三级久久99| 欧美日韩日韩| 欧美国产丝袜视频| 国产欧美不卡| 一区二区不卡在线视频 午夜欧美不卡在 | 狠狠色伊人亚洲综合成人| 日韩视频三区| 最新国产の精品合集bt伙计| 亚洲欧美制服另类日韩| 一本久道久久综合中文字幕 | 亚洲国产日韩欧美综合久久| 欧美啪啪一区| 欧美 日韩 国产在线| 国产精品午夜电影| 99精品免费网| 一本大道av伊人久久综合| 久久久久久一区二区| 欧美怡红院视频| 国产精品久久久对白| 亚洲国产综合视频在线观看| 在线精品福利| 久久成人国产| 久久精品免费电影| 国产精品男女猛烈高潮激情| 亚洲精品网址在线观看| 亚洲国产欧美一区| 久久综合免费视频影院| 久久这里有精品视频| 一区二区三区在线高清| 久久国产日本精品| 久久午夜av| 欲色影视综合吧| 久久久久久久综合| 免费观看国产成人| 亚洲福利视频免费观看| 久久综合给合久久狠狠色| 欧美 日韩 国产 一区| 在线观看亚洲精品| 蜜臀久久99精品久久久画质超高清| 久久一区二区三区av| 影音先锋中文字幕一区二区| 久久久不卡网国产精品一区| 美女在线一区二区| 亚洲激情国产| 欧美精品一区三区在线观看| 99精品视频免费全部在线| 国产精品美女久久久久av超清| 一区二区三区精品在线 | 亚洲精选在线观看| 中文一区二区| 国产精品爽爽ⅴa在线观看| 亚洲欧美中文日韩v在线观看| 欧美一区国产在线| 狠狠入ady亚洲精品经典电影| 久久蜜臀精品av| 亚洲激情中文1区| 亚洲一区二区三区高清不卡| 国产欧美日韩视频一区二区三区| 久久成人精品无人区| 亚洲国产精品毛片| 国产精品99久久久久久人| 国产啪精品视频| 久色婷婷小香蕉久久| 亚洲视频每日更新| 久久嫩草精品久久久久| 亚洲美女啪啪| 国产欧美精品| 欧美激情片在线观看| 亚洲一区二区精品在线观看| 美女主播一区| 亚洲欧美日韩一区| 亚洲国产色一区| 国产欧美精品在线播放| 欧美超级免费视 在线| 亚洲欧美日韩网| 亚洲区免费影片| 久久色在线观看| 亚洲一区成人| 亚洲国产成人精品视频| 国产精品亚洲不卡a| 欧美成人第一页| 欧美在线短视频| 亚洲影院在线| 亚洲人成免费| 欧美1区视频| 久久精品99国产精品| 一区二区av在线| 亚洲电影成人| 国产一区二区精品丝袜| 国产精品久久久久91| 欧美高清在线视频观看不卡| 欧美一区二区三区四区在线观看 | 亚洲精品日日夜夜| 免费一级欧美片在线播放| 欧美一区二区三区在| 一区二区三区视频观看| 亚洲青涩在线| 在线日韩欧美视频| 激情伊人五月天久久综合| 国产日韩欧美成人| 国产乱码精品一区二区三区五月婷 | 91久久国产自产拍夜夜嗨| 国产在线不卡| 国产一区二区日韩精品欧美精品| 国产精品国产三级国产普通话三级| 欧美成人三级在线| 免费永久网站黄欧美| 久久亚洲精品一区二区| 久久精品欧美日韩精品| 欧美一区综合| 久久成人免费| 久久亚洲高清| 91久久在线播放| 亚洲国产免费| 亚洲精品一区二区三区樱花| 亚洲高清视频在线| ●精品国产综合乱码久久久久| 黑人一区二区三区四区五区| 黄网动漫久久久| 亚洲国产高清在线观看视频| 亚洲第一在线视频| 亚洲美女av在线播放| 亚洲免费观看视频| 中日韩美女免费视频网站在线观看| 亚洲午夜精品久久| 亚洲欧美日韩专区| 欧美中文在线视频| 久久一本综合频道| 亚洲激情中文1区| 一区二区三区四区五区视频| 亚洲一区在线免费| 久久久久久网站| 欧美风情在线观看| 国产精品乱码一区二三区小蝌蚪| 国产精品一区免费在线观看| 极品av少妇一区二区| 亚洲美女诱惑| 欧美中文在线免费| 欧美韩日一区| 亚洲一区久久久| 久久久一二三| 欧美日韩中文| 精品69视频一区二区三区| 亚洲免费成人av电影| 欧美亚洲在线观看| 欧美成人综合| 亚洲在线黄色| 欧美黄色成人网| 国产美女在线精品免费观看| 亚洲国产另类久久久精品极度| 亚洲一区二区黄| 美女国产一区| 亚洲专区一区二区三区| 老司机久久99久久精品播放免费 | 久久久777| 欧美性猛交xxxx乱大交退制版| 伊人狠狠色j香婷婷综合| 国产精品99久久久久久久女警 | 免费成人黄色片| 亚洲一区网站| 欧美了一区在线观看| 一区二区三区在线视频免费观看 | 亚洲高清不卡在线观看| 亚洲欧美国产毛片在线| 亚洲第一天堂av| 欧美在线一二三四区| 国产精品高精视频免费| 亚洲日本在线观看|