IE里的探索之定制浏览器好助手(下)
(作者:青苹果工作室编译 2001年02月08日 14:00)
访问文档对象
文章整理:西部数码--专业提供域名注册、虚拟主机服务
现在 BHO 引用了 Internet Explorer 的 WebBrowser 控件并已连接到浏览器 以接收他产生的事件。在 Web 页面被完全下载并被正确地初始化之后,现在终于能够通过 DHTML 文档对象模型访问他了。WebBrowser 的 Document 属性返回一个指向文档对象的 IDispatch 接口的指针:
CComPtr
HRESULT hr = m_spWebBrowser2->get_Document(&pDisp);
get_Document() 方法提供的只是个指向接口的指针。我们需要确定在 IDispatch 指针后面确实是个 HTML 文档对象。假如使用 Visual Basic,以下是等价的代码:
Dim doc As Object
Set doc = WebBrowser1.Document
If TypeName(doc)="HTMLDocument" Then
' Get the document content and display
Else
' Disable the display dialog
End If
现在我们需要判断 get_Document() 返回的 IDispatch 指针的实质。Internet Explorer 不但是个 HTML 浏览器,还能处理任何 ActiveX 文档 ;即任何有作为 ActiveX 文档服务程式的应用程式支持的文档。这样一来,就不能确保查看的文档的确是个 HTML 页面。
有一个解决办法就是查看 URL 并检查 URL 的扩展名。但该如何处理 Active Server Pages (ASP) 或一个暗含指向 HTML 页面的 URL?假如您使用了像 about 或 res 这样的定制协议又该如何?
我们决定采取另一种方式,他和上面的 Visual Basic 代码性质相同。这种想法就是,假如 IDispatch 指针确实指向一个 HTML 文档,对 IHTMLDocument2 接口的访问就能成功地返回。IHTMLDocument2 是综合了 DHTML 对象模型为 HTML 页面实现的所用功能的接口。以下代码片断说明如何进行这样的判断:
CComPtr
HRESULT hr = m_spWebBrowser2->get_Document(&pDisp);
CComQIPtr
spHTML = pDisp;
if (spHTML) {
// 取得文档的内容并显示他
}
else {
// 禁止代码窗口控件
}
假如访问 IHTMLDocument2 接口失败,spHTML 指针为 NULL。否则,我们就能够正常访问 DHTML 对象模型的方法和属性了。
现在的问题是如何获得已显示的页面的源代码。幸好,基本的 DHTML 知识就足以做到这一点。由于 HTML 页面将他任何的内容包含在 标记中,DHTML 对象模型需要您首先获得指向 Body 对象的指针:
CComPtr
hr = spHTML->get_body(&m_pBody);
奇特的是,DHTML 对象模型不让您知道在 之前的标记,例如 的原始内容。这些内容已被处理并被保存到一系列属性中了,但您依然不能得到一个最初的 HTML 文档的原始内容。然而,现在 body 能告诉我们的就足够了。我们需要将 outerHTML 属性的内容读取到一个 BSTR 变量里以获得包含在 和 之间的 HTML 代码。
BSTR bstrHTMLText;
hr = m_pBody->get_outerHTML(&bstrHTMLText);
现在,在代码窗口中显示文本的工作就是创建窗口、将字符串从 Unicode 转换为 ANSI,并如图 3 中所示配置编辑框。以下是完成这些工作的全部代码:
HRESULT CViewSource::GetDocumentContent()
{
USES_CONVERSION;
// 获得 WebBrowser 文档对象
CComPtr
HRESULT hr = m_spWebBrowser2->get_Document(&pDisp);
if (FAILED(hr))
return hr;
// 验证我们得到了一个指向 IHTMLDocument2 接口的指针
// 我们查询 IHTMLDocument2 接口 (通过灵巧指针)
CComQIPtr
spHTML = pDisp;
// 获得文档的源代码
if (spHTML)
{
// 获得 BODY 对象
hr = spHTML->get_body(&m_pBody);
if (FAILED(hr))
return hr;
// 获得 HTML 文本
BSTR bstrHTMLText;
hr = m_pBody->get_outerHTML(&bstrHTMLText);
if (FAILED(hr))
return hr;
// 将文本从 Unicode 转换为 ANSI
LPTSTR psz = new TCHAR[SysStringLen(bstrHTMLText)];
lstrcpy(psz, OLE2T(bstrHTMLText));
// 允许修改文本
HWND hwnd = m_dlgCode.GetDlgItem(IDC_TEXT);
EnableWindow(hwnd, true);
hwnd = m_dlgCode.GetDlgItem(IDC_APPLY);
EnableWindow(hwnd, true);
// 配置代码窗口的文本
m_dlgCode.SetDlgItemText(IDC_TEXT, psz);
delete [] psz;
}
else // 文档不是 HTML 页面
{
m_dlgCode.SetDlgItemText(IDC_TEXT, "");
HWND hwnd = m_dlgCode.GetDlgItem(IDC_TEXT);
EnableWindow(hwnd, false);
hwnd = m_dlgCode.GetDlgItem(IDC_APPLY);
EnableWindow(hwnd, false);
}
return S_OK;
}
由于我们运行这段代码以响应 DocumentComplete 通知,每个新页面都会迅速地自动处理。DHTML 对象模型允许您修改显现的页面的结构,但在您按 F5 键或浏览器的 Refresh 按钮刷新视图后,任何的修改会立即丢失。通过对 DownloadComplete 事件进行处理您能同时刷新代码窗口。(注意 DownloadComplete 事件比 DocumentComplete 事件先到达) 这时,您应该忽略第一次下载页面时产生的 DownloadComplete 而只考虑刷新时产生的事件。一个简单的布尔成员例如 m_bDocumentCompleted 能够用来区分这两种情况。
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!




