• <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>
            隨筆 - 47, 文章 - 10, 評論 - 8, 引用 - 0
            數(shù)據(jù)加載中……

            VC++開發(fā)BHO插件——定制你的瀏覽器

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

              BHO(Browser Help Objects),是實現(xiàn)了特定接口的COM組件。開發(fā)好的BHO插件在注冊表特定的位置注冊好后,每當微軟的瀏覽器啟動,BHO實例就會被創(chuàng)建。在瀏覽器工作的工程中,BHO會接收到很多事件,比如瀏覽器瀏覽新的地址、前進或后退、生成新的窗口、瀏覽器退出等等;BHO可以在這些事件的響應中實現(xiàn)與瀏覽器的交互。
             
              下面,我們首先來介紹一下BHO的工作原理。上面我們已經提到,BHO是COM組件,而且一定實現(xiàn)了IObjectWithSite接口。這些組件除了在注冊表中注冊為COM Server外,還必須將它們的CLSID在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\ CurrentVersion\Explorer\Browser Helper Objects下注冊為子鍵。微軟在設計瀏覽器的時候,已經給這些組件預留了空間。每當瀏覽器啟動時,瀏覽器會首先在上述注冊表位置查看是否有注冊的BHO CLSID;如果有則分別創(chuàng)建一個實例,并對BHO實例進行初始化,建立交互連接。(注:BHO實例只有在創(chuàng)建它的瀏覽器窗口銷毀時才被釋放。)下圖演示了BHO的創(chuàng)建過程:
            o_bho.jpg
              成功創(chuàng)建的BHO,不僅可以得到各種標準的瀏覽器操作事件,并做出響應;還可以定制瀏覽器的菜單、工具條等界面元素;更或者可以安裝鉤子函數(shù),監(jiān)視瀏覽器的一舉一動。值得注意的是,使用BHO插件,Internet瀏覽器要求在4.0以上版本;如果是文件瀏覽器,操作系統(tǒng)要求是Windows 95/98/2000或Window NT 4.0以上版本,并且Shell的版本在4.71以上。下面是支持BHO特性的系統(tǒng)一覽表:

            Shell版本 操作系統(tǒng)版本 支持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和文件瀏覽器

              接下去,筆者就來介紹一下如何開發(fā)BHO插件,開發(fā)環(huán)境為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,這個就是實現(xiàn)IObjectWithSite接口的模版類。

              第二步,實現(xiàn)IObjectWithSite的接口方法。在這之前,我們要先定義幾個成員變量:CComQIPtr<IWebBrowser2, &IID_IWebBrowser2> mWebBrowser2,(需要加入#include "ExDisp.h"),用以保存瀏覽器組件的指針;DWORD mCookie,用以保存與瀏覽器的連接ID。IObjectWithSite有兩個接口方法:SetSite和GetSite。我們只需重載SetSite就行了。在EyeOnIE.h中增加函數(shù)聲明STDMETHOD(SetSite)(IUnknown *pUnkSite),在EyeOnIE.cpp實現(xiàn)如下:

            ?1STDMETHODIMP?CEyeOnIE::SetSite(IUnknown?*pUnkSite)
            ?2{
            ?3 USES_CONVERSION;
            ?4
            ?5 if?(pUnkSite)
            ?6 {
            ?7  mWebBrowser2?=?pUnkSite;
            ?8  if?(mWebBrowser2)
            ?9  {
            10   return?RegisterEventHandler(TRUE);
            11  }

            12 }

            13 return?E_FAIL;
            14}

            15
            16HRESULT?CEyeOnIE::RegisterEventHandler(BOOL?inAdvise)
            17{
            18 CComPtr<IConnectionPoint>?spCP;
            19 //?Receives?the?connection?point?for?WebBrowser?events
            20 CComQIPtr<IConnectionPointContainer,?&IID_IConnectionPointContainer>?spCPC(mWebBrowser2);
            21 HRESULT?hr?=?spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2,?&spCP);
            22 if?(FAILED(hr))
            23  return?hr;
            24
            25 if?(inAdvise)
            26 {
            27  //?Pass?the?event?handlers?to?the?container
            28  hr?=?spCP->Advise(reinterpret_cast<IDispatch*>(this),?&mCookie);
            29 }

            30 else
            31 {
            32  spCP->Unadvise(mCookie);
            33 }

            34 return?hr;?
            35}
              我們可以看到,SetSite的參數(shù)實際上指向的是瀏覽器組件。在SetSite實現(xiàn)中,我們首先保存瀏覽器組件指針,然后將該BHO向瀏覽器注冊為事件處理器。

              第三步,實現(xiàn)IDispatch接口方法。事件處理也就在IDispatch::Invoke中實現(xiàn)(各個事件的ID在ExDispID.h中定義)。BHO可能會接收到很多事件,但我們只需要響應我們感興趣的那一部分。首先在EyeOnIE.h中增加該函數(shù)的聲明,在EyeOnIE.cpp的實現(xiàn)中,筆者試著響應瀏覽器瀏覽一個地址之前發(fā)出的事件DISPID_BEFORENAVIGATE2,以此來實現(xiàn)簡單的網(wǎng)址過濾功能,代碼參考如下:

            ?1STDMETHODIMP?CEyeOnIE::Invoke(DISPID?dispidMember,REFIID?riid,?LCID?lcid,?
            ?2WORD?wFlags,?DISPPARAMS?*?pDispParams,?
            ?3VARIANT?*?pvarResult,EXCEPINFO?*?pexcepinfo,?
            ?4UINT?*?puArgErr)
            ?5{?
            ?6 USES_CONVERSION;
            ?7
            ?8 if?(!pDispParams)
            ?9  return?E_INVALIDARG;
            10
            11 switch?(dispidMember)
            12 {
            13  //
            14  //?The?parameters?for?this?DISPID?are?as?follows:
            15  //?[0]:?Cancel?flag?-?VT_BYREF|VT_BOOL
            16  //?[1]:?HTTP?headers?-?VT_BYREF|VT_VARIANT
            17  //?[2]:?Address?of?HTTP?POST?data?-?VT_BYREF|VT_VARIANT?
            18  //?[3]:?Target?frame?name?-?VT_BYREF|VT_VARIANT?
            19  //?[4]:?Option?flags?-?VT_BYREF|VT_VARIANT
            20  //?[5]:?URL?to?navigate?to?-?VT_BYREF|VT_VARIANT
            21  //?[6]:?An?object?that?evaluates?to?the?top-level?or?frame
            22  //?WebBrowser?object?corresponding?to?the?event.?
            23  //
            24  case?DISPID_BEFORENAVIGATE2:
            25  {
            26   LPOLESTR?lpURL?=?NULL;
            27   mWebBrowser2->get_LocationURL(&lpURL);
            28   char?*?strurl;
            29   if?(pDispParams->cArgs?>=?5?&&?pDispParams->rgvarg[5].vt?==?(VT_BYREF|VT_VARIANT))
            30   {
            31    CComVariant?varURL(*pDispParams->rgvarg[5].pvarVal);
            32    varURL.ChangeType(VT_BSTR);
            33    strurl?=?OLE2A(varURL.bstrVal);
            34   }

            35   if?(strstr(strurl,?"girl.com"))
            36   {
            37    *pDispParams->rgvarg[0].pboolVal?=?TRUE;
            38    ::MessageBox(NULL,?_T("該網(wǎng)頁已被禁止!"),_T("Warning"),MB_ICONSTOP);
            39    return?S_OK;
            40   }

            41   break;
            42  }

            43
            44  case?DISPID_NAVIGATECOMPLETE2:
            45   break;
            46  case?DISPID_DOCUMENTCOMPLETE:
            47   break;
            48  case?DISPID_DOWNLOADBEGIN:
            49   break;
            50  case?DISPID_DOWNLOADCOMPLETE:
            51   break;
            52  case?DISPID_NEWWINDOW2:
            53   break;
            54  case?DISPID_QUIT:
            55   RegisterEventHandler(FALSE);
            56   break;
            57  default:
            58   break;
            59 }

            60
            61 return?S_OK;
            62}


              我們看到,當用戶瀏覽的新地址包含"girl.com"字符的時候,瀏覽器就會彈出一個警告對話框,并且停止進一步的動作。另外值得注意的是,在DISPID_QUIT事件(瀏覽器將要退出)的響應中,我們將BHO事件處理器進行了注銷。

              第四步,因為BHO可能會被文件瀏覽器加載。如果我們不想這樣,我們就要在DllMain中對加載者進行判斷,參考如下:

            ?1extern?"C"
            ?2BOOL?WINAPI?DllMain(HINSTANCE?hInstance,?DWORD?dwReason,?LPVOID?/*lpReserved*/)
            ?3{
            ?4 if?(dwReason?==?DLL_PROCESS_ATTACH)
            ?5 {
            ?6  //?Check?who's?loading?us.?
            ?7  //?If?it's?Explorer?then?"no?thanks"?and?exit
            ?8  TCHAR?pszLoader[MAX_PATH];
            ?9  GetModuleFileName(NULL,?pszLoader,?MAX_PATH);
            10  _tcslwr(pszLoader);
            11  if?(_tcsstr(pszLoader,?_T("explorer.exe")))?
            12   return?FALSE;
            13
            14  _Module.Init(ObjectMap,?hInstance,?&LIBID_BHOPLUGINLib);
            15  DisableThreadLibraryCalls(hInstance);
            16 }

            17 else?if?(dwReason?==?DLL_PROCESS_DETACH)
            18  _Module.Term();
            19  return?TRUE;?//?ok
            20}


              最后,別忘了修改注冊表文件,追加BHO的注冊信息。在EyeOnIE.rgs文件的下面增加如下代碼:

            ?1HKLM
            ?2{
            ?3 SOFTWARE
            ?4 {
            ?5  Microsoft
            ?6  {
            ?7   Windows
            ?8   {
            ?9    CurrentVersion
            10    {
            11     Explorer
            12     {
            13      'Browser?Helper?Objects'
            14      {
            15       {6E28339B-7A2A-47B6-AEB2-46BA53782379}
            16      }

            17     }

            18    }

            19   }

            20  }

            21 }

            22}


              注意,{6E28339B-7A2A-47B6-AEB2-46BA53782379}是筆者這個BHO的CLSID,如果你自己開發(fā)BHO,這里應該正確填寫你的CLSID。

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

            posted on 2006-12-11 15:49 編程之道 閱讀(949) 評論(0)  編輯 收藏 引用 所屬分類: C/C++開發(fā)相關

            色欲av伊人久久大香线蕉影院| 精品久久久久久久久久中文字幕 | 热99RE久久精品这里都是精品免费 | 久久亚洲中文字幕精品有坂深雪| 欧美噜噜久久久XXX| 香蕉久久夜色精品国产小说| 久久久精品波多野结衣| 欧美精品国产综合久久| 久久男人Av资源网站无码软件| 大蕉久久伊人中文字幕| 伊人久久大香线蕉综合热线| 日韩精品久久久久久免费| 久久综合综合久久狠狠狠97色88| 亚洲精品国精品久久99热| 久久国产免费观看精品3| 久久国产成人精品国产成人亚洲| 久久精品日日躁夜夜躁欧美| 亚洲国产精品久久久久| 狠狠精品久久久无码中文字幕| 99国内精品久久久久久久| 狠狠色婷婷久久综合频道日韩 | 韩国免费A级毛片久久| 欧美一级久久久久久久大| 伊人久久大香线蕉精品| 国产午夜免费高清久久影院| 一本久道久久综合狠狠躁AV| 激情久久久久久久久久| 久久99精品国产99久久6男男| 亚洲av日韩精品久久久久久a| 色婷婷综合久久久久中文字幕| 狠狠色噜噜狠狠狠狠狠色综合久久 | 国内精品久久久久伊人av| 99久久精品免费看国产一区二区三区 | 欧美成人免费观看久久| 久久国产综合精品五月天| 久久精品免费观看| 久久99热国产这有精品| 久久免费国产精品一区二区| 国产精品久久国产精品99盘| 国产精品久久久天天影视| 国产99久久精品一区二区|