• <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>

            旅途

            如果想飛得高,就該把地平線忘掉

            Internet Explorer 編程簡述(九)在自己的瀏覽器中嵌入Google工具條

            關(guān)鍵字:Google Toolbar, Explorer Bars, ToolBands, IObjectWithSite, IDeskBand

             

            1、概述

              Internet Explorer強大而方便的可編程能力和可擴展能力為其搶占瀏覽器市場可謂是立下了汗馬功勞。可編程主要體現(xiàn)兩方面:

            • 實現(xiàn)瀏覽功能的部分被包裝成一個控件——WebBrowser Control,開發(fā)人員可以在自己的應(yīng)用程序中嵌入它從而使程序具有訪問Internet上網(wǎng)頁的能力,同時WebBrowser Control也能夠被靈活地自定義以滿足不同的需要。
            • 可對Microsoft Internet Explorer應(yīng)用程序本身嵌入的瀏覽器控件編程,一般通過BHO(Browser Helper Object)來實現(xiàn)。

             

              可擴展能力則體現(xiàn)在幾個方面:

            • 嵌入式面板型擴展,包括Explorer Bars(如收藏夾、搜索、歷史等嵌入IE主窗口的大型面板), Tool Bands(如Google Toolbar、MSN Toolbar等嵌入IE的工具條), 和Desk Bands(如快速啟動這類嵌入任務(wù)欄的面板,實際上是Explorer外殼的擴展)。這幾種面板的編寫方法相差無幾,不同之處主要在于向系統(tǒng)注冊方式的不同。

             

            Explorer bars

             

            Tool bands

            Desk band

             

             

            • 是參數(shù)型擴展,包括為瀏覽器增加上下文菜單項(調(diào)用腳本)、為瀏覽器主菜單增加菜單項、為瀏覽器“標準按鈕”工具條添加按鈕等。
            • 其他擴展,如文件下載的擴展(Custom Download Manager)、地址欄擴展(搜索擴展)等。

             

              隨著IE的發(fā)展,各種類型的擴展遍地開花,其中最為引人注目的,當屬地址欄擴展和工具條擴展(幾乎成了兵家必爭之地)。本文討論的主題,正是工具條的擴展。

             

            2、問題的提出

              兩個原因促成了Google Toolbar的流行,一是廣告窗口的泛濫、二是Google Search。Google“簡單”(實則一點都不簡單,沒有搜索引擎的強力支持,Toolbar的用途就大受限制)地抓住了這兩點,迅速占領(lǐng)了市場。

              插件的一大好處在于可以不修改主程序,只需換一個樣子差不多但功能更強的東西就可以使得整個應(yīng)用程序功能增強,所以IE不升級大家也覺得Google Toobar越來越好用。于是利用WebBroser Control編寫瀏覽器的開發(fā)人員就想,如果能像IE一樣支持上述這些擴展,不就能把Google Toolbar拿過來用了嗎?其他的事交給Google去做就行了。這就是我們要討論的問題,“如何在自己的瀏覽器中嵌入Google Toolbar”。

             

            3、分析

              微軟并未在MSDN中說明如何將Google Toolbar這類IE的工具條插件嵌入自己的應(yīng)用程序,但其基于COM的設(shè)計方法實際上給予了我們這個能力(創(chuàng)建嵌入式的工具條的方法并不是本文的重點,此處略去,有興趣的朋友可以參考MSDN)。我們知道,除了IUnknown接口外,Bands和Bars(以下簡稱Band對象)還需要實現(xiàn)三個接口:IObjectWithSite,IPersistStream和IDeskBand。當用戶選擇工具條或面板時,其容器(如IE的外殼框架)就會調(diào)用Band對象的IObjectWithSite::SetSite方法(該方法僅需要一個IUnknown類型的指針),將自己實現(xiàn)的IUnknown指針傳遞給Band對象。這就是整個插件開始真正激活的入口,也是我們的著手點。

              MSDN中說到,一般來說,Band對象對于SetSite方法的實現(xiàn)需要完成以下幾件事:

            1. 如果當前Band對象持有另外的Site指針,則首先釋放該指針。
            2. 如果容器向SetSite方法傳入的是一個空指針,則表示要刪除該Band對象,此時SetSite返回S_OK即可。
            3. 如果容器傳入的不是空指針,則需要設(shè)置新的Site:
              1. 對此IUnknown指針所指的新Site調(diào)用QueryInterface查詢得到其IOleWindow接口。
              2. 調(diào)用得到的IOleWindow接口的GetWindow方法獲取父窗口的句柄(此窗口即是Band對象的棲身之處)并保存下來。如果以后不會再用到IOleWindow接口的話就對其調(diào)用Release。
              3. 現(xiàn)在可以創(chuàng)建Band對象的窗口了,當然,要以第2步得到的窗口為父窗口來創(chuàng)建,并且該窗口目前只能以不可見狀態(tài)存在。
              4. 如果Band對象實現(xiàn)了IInputObject接口,即需要接收鍵盤輸入,則還需要向容器傳來的Site查詢(QueryInterface)IInputObjectSite接口,此接口指針也需要保存下來。
              5. 上述步驟完成后即可返回S_OK,否則應(yīng)返回OLE-defined的error code告知容器什么地方出了錯。

             

              顯然,就我們要討論的問題而言,只需換個角度(編寫IE外殼的的角度)來考慮即可。首先,我們需要一個IUnknown接口(即Band對象所需的Site),其次需要一個IInputObjectSite接口,用以和Band對象的IInputObject接口交互,處理輸入焦點轉(zhuǎn)移的情況。接下來就可以通過Band對象的IDeskBand接口來顯示、隱藏Band對象了(注意IDeskBand接口派生自IDockingWindow接口,后者又派生自IOleWindow接口)。

             

            4、實現(xiàn)

              實現(xiàn)分為兩個部分,其一是一個簡單的類,用以模擬IE外殼,我取名為CIESimulator。其二是一個管理IE擴展的類CIEBandPlugInManager,用以管理Band對象的方方面面。

             

            class CIESimulator : public IInputObjectSite

            {

            private:

            IWebBrowser2 *m_pwb; //保存WebBrowser Control的接口指針

            public:

            CIESimulator(void){};

            ~CIESimulator(void){};

             

            void SetIWebBrowser2(IWebBrowser2* pwb);

             

            //IUnknown methods

            STDMETHODIMP QueryInterface(REFIID, void **);

            STDMETHODIMP_(ULONG) AddRef(void);

            STDMETHODIMP_(ULONG) Release(void);

             

            //IInputObjectSite specific methods

            STDMETHOD(OnFocusChangeIS)(THIS_ IUnknown* punkObj, BOOL fSetFocus);

            };

             

            //IUnknown methods

            STDMETHODIMP CIESimulator::QueryInterface( REFIID riid, void **ppv )

            {

            if ( riid == IID_IInputObjectSite )  //這個接口需要自己處理

            {

            *ppv = static_cast<IInputObjectSite*>(this);

            }

            else if ( m_pwb )  //其它的交給WebBrowser Control去處理

            {

            m_pwb->QueryInterface( riid, ppv );

            }

            return S_OK;

            }

             

            //IInputObjectSite specific methods

            STDMETHODIMP CIESimulator::OnFocusChangeIS(IUnknown* punkObj, BOOL fSetFocus)

            {

            return S_OK;  //此處我們簡單地返回

            }

             

            void CIESimulator::SetIWebBrowser2(IWebBrowser2* pwb)

            {

            m_pwb = pwb;

            }

             

              注意這里我們并沒有實現(xiàn)IOleWindow接口來向Band對象傳遞父窗口對象(窗口的宿主可以更改,所以Band對象創(chuàng)建的窗口的父窗口我們并不關(guān)心,Band對象查詢IOleWindow接口的動作實際上是向WebBrowser Control查詢),而是在稍后的CIEBandPlugInManager類中通過調(diào)用IDeskBand的GetWindow方法獲得Band對象的窗口句柄,再手動將其嵌入我們指定的窗口中。

             

              首先我們定義一個結(jié)構(gòu)用以保存Band的信息:

            enum eBANDTYPE

            {

            btVertical = 0,

            btHorizontal = 1

            };

             

            enum eBANDSTATE

            {

            bsUnInitialized = -1,

            bsVisible = 0,

            bsInVisible = 1,

            bsUnLoaded = 2

            };

             

            typedef struct tagIEBANDINFO

            {

            char

             

            szCLSID[39];

            char

             

            szName[MAX_PATH];

            IUnknown

            *puk;

            HWND

             

            hBand;

            UINT

             

            uMinHeight;

            UINT

             

            uBandID;

            eBANDTYPE

            eBandType;

            eBANDSTATE

            eBandState;

            } IEBANDINFO, *LPIEBANDINFO;

             

              再用一個函數(shù)來獲取所有Band的信息(以下代碼為示例,具體實現(xiàn)是可從注冊表把所有Band的信息一一讀出)

            void CIEBandPlugInManager::GetAllBandCLSID(void)

            {

            LPIEBANDINFO pIEBandInfo;

             

            pIEBandInfo = new IEBANDINFO();

            strcpy( pIEBandInfo->szCLSID, "{2318C2B1-4965-11d4-9B18-009027A5CD4F}\0");  //Google Toolbar的CLSID

            strcpy( pIEBandInfo->szName, GetDisplayName(pIEBandInfo->szCLSID) );

            pIEBandInfo->uMinHeight = 22;

            pIEBandInfo->uBandID = m_BandCtrlID++;

            pIEBandInfo->eBandType = btHorizontal;

            pIEBandInfo->eBandState = bsUnInitialized;

            m_oaBand.Add( (CObject*)pIEBandInfo );//m_oaBand是一個CObArray

             

            //根據(jù)CLSID從注冊表獲取Band的名稱

            CString CIEBandPlugInManager::GetDisplayName(CString strCLSID)

            {

            TCHAR

             

            sz[MAX_PATH];

            HKEY

             

            hKey;

            DWORD

             

            dwSize;

             

            strCLSID = "CLSID\\" + strCLSID;

            if(RegOpenKey(HKEY_CLASSES_ROOT, strCLSID, &hKey) != ERROR_SUCCESS)

            {

            return _T("");

            }

             

            RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)sz, &dwSize);

            RegCloseKey(hKey);

             

            return sz;

            }

             

            //通過Band的CLSID激活Band

            bool CIEBandPlugInManager::ActivateBand( CString strCLSID )

            {

            LPIEBANDINFO pIEBandInfo = GetBandInfo( strCLSID ); //從m_oaBand中找到符合條件的Band的信息

            if ( !pIEBandInfo )

            {

            return false;

            }

             

            WCHAR wsz[MAX_PATH]; 

            ::MultiByteToWideChar(CP_ACP, 0, strCLSID, -1, wsz, MAX_PATH);

             

            CLSID

            clsid;

            HRESULT hr2 = CLSIDFromString( wsz, &clsid);

            if ( hr2 != NOERROR )

            return false;

             

            HRESULT hr = ::CoCreateInstance(clsid, NULL, LSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pIEBandInfo->puk); //創(chuàng)建Band對象的實例

            IUnknown* puk = pIEBandInfo->puk;

            if (FAILED(hr))

            return false;

             

            DoQueryBandInfo( pIEBandInfo );  //查詢Band對象實例的信息

             

            switch( pIEBandInfo->eBandType )

            {

            case btVertical:

            break;

            //我們不處理Vertical的面板

            case btHorizontal:

            {

            g_pMainFrame->m_wndReBar.AddBar2( pIEBandInfo->hBand, pIEBandInfo->uBandID, pIEBandInfo->uMinHeight, 0, 0); //將Band嵌入主窗口的ReBar中

             

            REBARBANDINFO rbbi;

            rbbi.cbSize = sizeof(rbbi);

            rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_SIZE;

            rbbi.cxMinChild = 0;

            rbbi.cyMinChild = pIEBandInfo->uMinHeight;

            rbbi.cx = rbbi.cxIdeal = 250;

            UINT nCount = g_pMainFrame->m_wndReBar.GetReBarCtrl().GetBandCount();

            g_pMainFrame->m_wndReBar.GetReBarCtrl().SetBandInfo(nCount-1, &rbbi);

            break;

            }

            default:

            break;

            }

            pIEBandInfo->eBandState = bsVisible;

            return true;

            }

             

            //查詢Band對象實例的信息

            void CIEBandPlugInManager::DoQueryBandInfo(LPIEBANDINFO pIEBandInfo)

            {

            IObjectWithSite *pOWS;

            //查詢IObjectWithSite接口

            HRESULT hr = pIEBandInfo->puk->QueryInterface(IID_IObjectWithSite, (void**)&pOWS);

            if (SUCCEEDED(hr))

            {     //設(shè)置Site

            pOWS->SetSite( (IUnknown *)&m_IESimulator ); //m_IESimulator是CIESimulator的一個實例對象,對Band對象而言,它就像IE

            }

             

            IDeskBand *pdb;

            hr = pIEBandInfo->puk->QueryInterface(IID_IDeskBand, (void**)&pdb);

            if (SUCCEEDED(hr))

            {     //查詢得到Band對象窗口的句柄,稍候通過該句柄將Band對象的窗口嵌入我們指定的窗口

            pdb->GetWindow(&pIEBandInfo->hBand);

            }

             

            ShowBand(pIEBandInfo, TRUE);//顯示Band

            }

             

            bool CIEBandPlugInManager::ShowBand(LPIEBANDINFO pIEBandInfo, bool bShow)

            {

            IDockingWindow *pdw;

            HRESULT hr = pIEBandInfo->puk->QueryInterface(IID_IDockingWindow, (void**)&pdw);

            if (SUCCEEDED(hr))

            {

            pdw->ShowDW(bShow);

            }

            else

            {

            return false;

            }

            return true;

            }

             

              下面是我測試的一個截圖,Google的搜索、廣告窗口攔截均可正常工作。

            嵌入Google toolbar演示

             

            5、總結(jié)

              上述的原理看來很簡單,但具體實現(xiàn)的時候仍然需要作較多的測試和考慮,Band對象的管理和緩存、接口的AddRef和Release等。時間有限,代碼也很亂,不過只要原理交待清楚,相信會對有興趣的朋友有所幫助。

             

            6、參考資料

            MSDN:Creating Custom Explorer Bars, Tool Bands, and Desk Bands

             

            引用地址:《Internet Explorer編程簡述(九)在自己的瀏覽器中嵌入Google工具條



            Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=550698


            posted on 2007-07-29 15:25 旅途 閱讀(1024) 評論(0)  編輯 收藏 引用 所屬分類: BHO

            久久午夜无码鲁丝片秋霞| 久久精品国产亚洲AV无码偷窥 | 久久久91精品国产一区二区三区| 久久久久99精品成人片直播| 亚洲精品国产成人99久久| 精品国产91久久久久久久a | 久久精品这里热有精品| 亚洲国产高清精品线久久| 日本久久久久亚洲中字幕 | 77777亚洲午夜久久多喷| 久久精品中文字幕久久| 久久精品a亚洲国产v高清不卡| 久久AⅤ人妻少妇嫩草影院| 久久久老熟女一区二区三区| 久久国产精品免费| 久久免费精品视频| 色欲久久久天天天综合网| 久久综合伊人77777麻豆| 亚洲国产精品久久久久久| 少妇内射兰兰久久| 亚洲精品国产字幕久久不卡 | 日本久久久久亚洲中字幕| 久久亚洲天堂| 久久免费观看视频| 国内精品久久久久久久影视麻豆| 久久精品一区二区三区不卡| 国产精品久久久久AV福利动漫| 国产精品免费久久久久久久久 | 久久久久波多野结衣高潮| 久久精品中文字幕一区| 国产精品99久久久久久www| 国产成人综合久久综合| 亚洲愉拍99热成人精品热久久| 亚洲国产精品狼友中文久久久 | 久久无码AV中文出轨人妻| 久久福利青草精品资源站免费| 99国产欧美久久久精品蜜芽 | 麻豆AV一区二区三区久久| 香蕉久久av一区二区三区| 国产精品美女久久久久| 精品国产乱码久久久久久郑州公司|