Internet Explorer 編程簡述(十)響應來自HTML Element的事件通知——幾個好用的類

來源:互聯網
上載者:User

關鍵字:HTML Element, Sink

 1、概述實現了對Webbrowser的resuing之後我們便會發現有時候我們還需要處理瀏覽器中的元素(HTML Element)。這種處理包括主動和被動兩個方面,像《FAQ:如何訪問WebBrowser的捲軸》、《FAQ:操縱下拉式清單》、《FAQ:兩種方法訪問多層嵌套的frame》等文章所示範的就是主動的處理。通常我們從Webbrowser獲得一個Web文檔介面(IHTMLDocumentx),從它出發便可訪問到瀏覽器所包含的一切HTML元素。而被動的處理則是在COM技術中稱為Sink的技術,我更喜歡的說法是事件通知。當文檔的下載進度發生變化時,我們可以獲得ProgressChange通知,當Webbrowser下載完HTML文檔時,我們可以獲得DocumentComplete的通知,而當連結被點擊,或圖片被拖動時,我們如何獲得通知呢?本文希望能夠給出部分的答案。 2、HtmlObj Template如何Sink一個HTML Element並不是本文的重點,其理論我不是太瞭解,也懶得去搞透徹,所以使用現成的庫來實現。CodeProject上的一篇文章《CHtmlObj Template》給出的一個模板類CHtmlObj就非常好用。下面的例子是針對Html Anchor Element的一個執行個體化。 
#include "HtmlObj.h" class CHtmlAnchorElement : public CHtmlObj<IHTMLAnchorElement, &DIID_HTMLAnchorEvents> {public:CHtmlAnchorElement(CHtmlDocument2* pParentDoc2);virtual ~CHtmlAnchorElement(); virtual HRESULT OnInvoke(DISPID dispidMember,REFIID riid, LCID lcid, WORD wFlags,DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr);};HRESULT CHtmlAnchorElement::OnInvoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,DISPPARAMS * pdispparams, VARIANT * pvarResult,EXCEPINFO * pexcepinfo, UINT * puArgErr){HRESULT hr = E_NOTIMPL;switch(dispidMember){case DISPID_HTMLELEMENTEVENTS_ONMOUSEOVER :{//當滑鼠經過連結時,我們在這裡獲得通知hr = S_OK;      // TODO: add code to handle on mouse over eventsbreak;}case DISPID_HTMLELEMENTEVENTS_ONMOUSEOUT :{//當滑鼠從連結上移開時,我們在這裡獲得通知,其它的Dispatch ID可根據需要添加hr = S_OK;      // TODO: add code to handle on mouse out eventsbreak;}default: {break;}} return hr;}
 當我們得到某個連結的HTML介面指標,便可調用CHtmlAnchorElement繼承自CHtmlObj的SetSite(IUnknown *pUnkSite)成員函數傳入該介面指標。在CHtmlObj類內部用一個智能指標m_spHtmlObj來儲存相應的HTML Element介面指標,所以當上面的ONMOUSEHOVER和ONMOUSEOUT兩個事件通知到達時,從m_spHtmlObj就可以訪問IHTMLAnchorElement的所有成員,如從href獲得連結的Url等,此處不再贅述。 3、CHtmlElements類有了CHtmlObj之後我們又會發現實踐中常常會需要多個相同類型的CHtmlObj。比如包含Frame的網頁中每個Frame的HTML Document都需要一個CHtmlObj來Sink其事件。所以我們還需要有效地管理這些相同類型的CHtmlObj。下面是我寫的一個簡單的模板類CHtmlElements,它通過CMap來管理多個CHtmlObj對象。 
template<class THtmlElement> class CHtmlElements{ typedef CMap<LPDISPATCH, LPDISPATCH, THtmlElement*, THtmlElement*> CMapDispToHtmlElement;CMapDispToHtmlElement m_htmlElements;BOOL IsSiteConnected( LPDISPATCH pDisp ){THtmlElement *pElement; return m_htmlElements.Lookup( pDisp, pElement );} public:CHtmlElements( void){}~CHtmlElements( void){} public: void SetSite( LPDISPATCH pDisp ){if ( IsSiteConnected( pDisp ) ) //檢查以避免多餘的Sink{ return;}THtmlElement *pElement = new THtmlElement; //通過模板類型建立相應的類的執行個體進行串連pElement->SetSite( pDisp );m_htmlElements.SetAt( pDisp, pElement );} 

//在合適的地方調用Clear釋放所管理的記憶體

void Clear(void)

{

POSITION pos = m_htmlElements.GetStartPosition();

THtmlElement *pElement = NULL;

LPDISPATCH pDisp = NULL;

while (pos != NULL)

{

m_htmlElements.GetNextAssoc( pos, pDisp, pElement );

m_htmlElements.RemoveKey( pDisp );

delete pElement;

}

}

};

 假設我們有一個象CHtmlAnchorElement那樣派生自CHtmlObj的類CHtmlDocument2,使用CHtmlElements時這樣聲明: 
typedef CHtmlElements<CHtmlDocument2> CHtmlDocuments; typedef CHtmlElements<CHtmlAnchorElement> CHtmlAnchors;  class CMyView : public CHtmlView{ private:CHtmlDocuments m_htmlDocs;CHtmlAnchors m_htmlAnchors;}
 在DocumentComplete時就可以這樣串連到瀏覽器的文檔對象:
void CMyView ::OnDocumentComplete(LPDISPATCH pDisp, LPCTSTR lpszURL){m_htmlDocs.SetSite(pDisp);}
 如果想一次性串連上文檔中所有的Anchor Element,可以通過IHTMLDocument2::get_anchors獲得包含所有IHTMLAnchorElement介面指標的IHTMLElementCollection,再遍曆其中的每個元素,分別調用m_htmlAnchors.SetSite即可。當然,一次性的Sink全部連結可能並不是個好注意,我更願意在CHtmlDocument2中響應事件再通過其它手段來訪問當前位置的HTML Element。 4、結論響應HTML Element的事件通知對於瀏覽器編程來說是一個非常強大的手段,它可以更深入細化地控制瀏覽器中的文檔及其HTML元素,實現更為進階的功能,比如所謂的“超級拖放”(許多多視窗瀏覽器都提供了該功能,但實際上沒有哪個瀏覽器完美地實現了對URL、文字及圖片的拖放)。 5、參考資料Codeproject: HtmlObj Template 引用地址:《Internet Explorer 編程簡述(十)響應來自HTML Element的事件通知——幾個好用的類》
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.