HRESULT CViewSource::Connect(void) { HRESULT hr; CComPtr spCP; //为Web浏览器事件而接收(receive)连接点 hr = m_spCPC->FindConnectionPoint(DIID_DWebBrowserEvent2, &spCP); if (FAILED(hr)) return hr; // 把事件处理器传递到容器。每次事件发生容器都将激活我们实现的IDispatch接口上的相应的函数。 hr = spCP->Advise( reinterpret_cast(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 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 pDisp; HRESULT hr = m_spWebBrowser2->get_Document(&pDisp); CComQIPtr spHTML; spHTML = pDisp; if (spHTML) { // 获取文档内容并予以显示 } else { // disable the Code Window controls }
如果IHTMLDocument2接口查询失败,spHTML指针将是NULL。 现在考虑如何获得当前显示窗口的源代码。正如一个HTML页把它所有的内容封装在标签中,DHTML对象模型要求你取得一个指向Body对象的指针:
CComPtr m_pBody; hr = spHTML->get_body(&m_pBody);
奇怪的是,DHTML对象模型不让你取得标签之前的原始内容,如。其内容被处理并存于一些属性中,但你还是不能从HTML原始文件中提取这部分的RAW文本。这过,仅从BODY部分取得的内容足够了。为了取得包含在…间的HTML代码部分,可以把outerHTML属性内容读取到一个BSTR变量中:
BSTR bstrHTMLText; hr = m_pBody->get_outerHTML(&bstrHTMLText);
在此基础上,在代码窗口中显示源码就是一种简单的事情了:生成一个窗口,进行字符的UNICODE至ANSI转化和设置编辑框控件的问题。下面代码实现这些功能: HRESULT CViewSource::GetDocumentContent() { USES_CONVERSION; // 获取 WebBrowser的文档对象 |