用Socket和MSHTML物件模型建立自己的瀏覽器

來源:互聯網
上載者:User
HTTP協議和WEB瀏覽器的誕生給我們的網路增加了更多的精彩。但在實際應用中我們可能會有不同的需要而不是單純的使用瀏覽器,譬如在我們的應用程式中加入瀏覽互連網的功能。微軟的ChtmlView類很方便的實現了網頁瀏覽。但是它很不靈活,無法使使用者動態地在網頁上修改自己想要的元素。本文探討一些方法使用Socket傳輸Html文檔,利用微軟的動態MSHTML物件模型實現一些瀏覽器的內部機制。
大家知道HTML文檔是由標記語言構成,即俗稱的Tag。微軟的瀏覽器IE對於這些標記實現了一一對應的物件模型(objectmodel),由MSHTML.DLL封裝。IE瀏覽器的實現也是由MSHTML.DLL來實現的。通過MSHTML.DLL我們可以直接操作物件模型的屬性,方法。MSHTML的物件模型是基於COM組件對象的,對象的介面是基於Idispatch,操作MSHTML物件模型必須通過Idispatch介面。MSHTML中封裝了許多這樣的介面,例如,IhtmlAnchorElement介面對應與HTML文檔中的超串連標記<A>,IHtmlHRElement介面對應<HR>標記,IhtmlTable介面對應<table>標記。其中最重要的是IhtmlDocument2介面,它對應Document組件。Document組件既相當於HTML文檔。使用過Javascript的人對它應比較熟悉。
下面我們舉例來講解MSHTML的應用。在舉例之前我先講述一下Socket和HTTP協議。HTTP協議通過TCP串連伺服器和Client,它工作在80連接埠。HTTP通過Client和Server之間的請求/應答機制進行通訊。HTTP訊息分為Request和Response。每一種訊息由開始行,訊息頭和訊息體組成。形式如下:
generic-message = start-line
*message-header
CRLF
[ message-body ]
   
start-line的形式如下:
start-line = Request-Line | Status-Line
Request-Line為Client向Server發出的請求,形式如下:
Request-Line = Method SP Request-URI SP HTTP-Version CRLF
Method 包括GET,POST等,在本例中我們只簡單的使用GET向伺服器發出請求。  
詳細的HTTP協議請參考RFC2068。
在VC++中建立新的單文檔EXE工程檔案,為了使用MSHTML我們的視圖類繼承自ChtmlView。ChtmlView類封裝了MSHTML介面。給工程中加入Socket類。
class CHttpSocket : public CSocket
{
………………
   
protected:
CWnd * m_pParentWnd;
}
其中m_pParentWnd指向我們的視圖類,用於傳送訊息。在視圖類中定義Socket。
class CSkhttpView : public CHtmlView
{
protected: // create from serialization only
CSkhttpView();
DECLARE_DYNCREATE(CSkhttpView)
…………….
protected:
CHttpSocket m_socket;
IHTMLDocument2 * phmDoc2;
……..
}
phmDoc2為IHTMLDocument2介面。初始化Socke,串連我們欲登入的網站,假設為www.163.net。
CSkhttpView::CSkhttpView()
{
// TODO: add construction code here
BOOL bRet=m_socket.Create(0,SOCK_STREAM,NULL);  
if(!bRet)
MessageBox("socket create error",NULL,MB_OK);
m_socket.SetParentWnd(this);  
if(!m_socket.Connect(www.163.net,80))
MessageBox(“socket connect error”,NULL,MB_OK);
}
下面我們取得IhtmlDocument2的介面。此介面的獲得一般有兩種方法。一是使用CoCreateInstance,然後調用QueryInterface。另一種是使用MSHTML控制項對象的get_Document,在ChtmlView類中封裝了這個介面。我們使用後一種。需要注意的是,我們需要在ChtmlView產生IhtmlDocument對象後才能獲得它的介面。
void CSkhttpView::OnInitialUpdate()  
{
Navigate2(“about:blank”);
}
void CSkhttpView::OnDocumentComplete(LPCTSTR lpszURL)
{
LPDISPATCH lpdisp;
HRESULT hr;
lpdisp=GetHtmlDocument();
hr=lpdisp->QueryInterface(IID_IHTMLDocument2,(void **)&phmDoc2);
}
在ChtmlView初始化時調用Navigate2()產生空文檔,文檔產生後調用GetHtmlDocument獲得一個Idispatch()介面,調用QueryInterface獲得IHTMLDocument2介面。
void CSkhttpView::OnReceiveMessage(WPARAM wParam,LPARAM lParam)
{
HRESULT hr;
char buf[5000];
int inum;
IHTMLElement * pEleBody;
if(wParam==0)
{
inum=m_socket.Receive(buf,sizeof(buf),0);
buf[inum]=0;
_bstr_t bsrBody(buf);
hr=phmDoc2->get_body(&pEleBody);
hr=pEleBody->put_innerHTML(bsrBody);  
}
}  
   
void CSkhttpView::OnControlSend()  
{
// TODO: Add your command handler code here
char buf[1000];
wsprintf(buf,"GET http://www.163.net HTTP/1.1/r/n/r/n");
int iRet=m_socket.Send(buf,lstrlen(buf),0);
if(iRet==SOCKET_ERROR)
MessageBox(“socket send error”,NULL,MB_OK);
}
我們向伺服器發送HTTP協議的請求”GET http://www.163.net HTTP/1.1/r/n/r/n”,它取回指定URI地址的網頁。伺服器發出回應我們通過Socket接受。IhtmlDocument2內含許多個物件借口,通過許多的put_,get_方法我們可以獲得這些對象的屬性,事件,方法。本例中我們獲得body對象,它對應於HTML文擋中<body></body>對象。通過IhtmlDocument2的get_body()得到指定body對象的IHTMLElement介面,調用IHTMLElement介面的put_innerHTML()將接受到的內容放入Document中。此時在我們的視圖中就會顯示網頁。
本文只是簡略的介紹了一下MSHTML對象,它裡面實際包含了許多的介面和函數,通過這些介面我們可以任意設計我們自己風格的瀏覽器。有興趣的同志可以參閱MSDN文檔。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.