日期:2010-07-02  浏览次数:20364 次

关键字:ITravelLogStg, IEnumTravelLogEntry, ITravelLogEntry

1、概述

Internet Explorer的浏览历史菜单在4.0版本开始出现,但直到5.5之前,微软都未公布用于访问浏览历史的COM接口,如今已是IE6.0大行其道的年代,用于访问浏览历史的接口也早已公布多时,本文的目的则是试图抛砖引玉,简单介绍用于访问浏览历史的Travel Log接口,并用一个小小的类CIETravelLog来实现对Travel Log的封装。

2、IOmHistory接口

在早些时候的MSDN中,我们能够查阅到关于浏览历史的接口仅有IOmHistory,而该接口实际上对应的是浏览器中可以通过脚本访问的“history”对象。对于“history”对象,MSDN中是这样说的:

For security reasons, the history object does not expose the actual URLs in the browser history. It does allow navigation through the browser history by exposing the back, forward, and go methods. A particular document in the browser history can be identified as an index relative to the current page. For example, specifying -1 as a parameter for the go method is the equivalent of clicking the Back button.

This object is available in script as of Microsoft Internet Explorer 3.0.

即为了安全的原因,IOmHistory接口仅提供了有限的几个方法来完成在浏览器中前进、后退等操作,并没有提供访问历史列表Url的能力。这也难怪,该接口在IE 3.0时代已经存在,而当时IE并不成熟,可编程能力也不甚强大。一直到IE 4.0通过与Windows 98捆绑销售一统天下之后,相关的文档才逐渐丰富,多窗口浏览器等基于Internet Explorer/WebBrowser Control的应用软件也才铺天盖地开来。但在IE 5.5接口公布之前,要完全模拟IE的Travel Log行为,并不是一件容易的事。最容易想到的方法就是在BeforeNavigate、DocumentComplete等事件发生之时记录/修改Url并加以保存(我在早些时候也这样做过),但是效果不甚理想,尤其是浏览包含Frame的网页时,处理更是麻烦。当然,要完全模拟亦非难事,只不过开发人员都知道微软公布接口是早晚的事,所以也没有人花大力气在模拟IE的Travel Log行为上。

3、Travel Log简介

Internet Explorer 5.5推出以后,Travel Log接口也就开始出现在MSDN中,它是专门为OLE嵌入WebBrowser Control的应用程序设计的,其目的是“提高和加强用户的访问日志体验”(improve and enhance the user's travel log experience)。事实上,稍后我会提到,Travel Log接口正日益成为应用程序中的重要接口之一。

微软公布的Travel Log共包含三个接口:ITravelLogStg, IEnumTravelLogEntry和ITravelLogEntry。

ITravelLogStg——该接口提供了用于在Travel Log中添加、删除、枚举日志(浏览历史)的方法,本文需要用到的几个方法列举如下:
方法名     用途

EnumEntries 为访问日志项创建枚举器(IEnumTravelLogEntry接口指针)

GetRelativeEntry 返回一个日志项

TravelTo 访问一个日志项

IEnumTravelLogEntry——该接口提供用于枚举日志项所必需的方法,本文只用到一个方法:
方法名     用途

Next   枚举下一个日志项(返回ITravelLogEntry接口指针)

ITravelLogEntry——该接口只有两个方法,分别用于返回日志项的Title和Url:
方法名     用途

GetTitle 返回日志项的Title

GetURL 返回日志项的Url

接口准备好了,我们也就很容易得知它们之间的关系:

要得到相对于当前页面的日志项列表,首先应通过ITravelLogStg接口创建一个枚举器(IEnumTravelLogEntry接口)。
通过IEnumTravelLogEntry枚举器的Next方法枚举出一个个的日志项(ITravelLogEntry接口)。
由ITravelLogEntry接口获取日志项所代表的网页的Title和Url并加以处理。
访问相对于当前页面的某个日志项时,首先由ITravelLogStg的GetRelativeEntry方法根据与当前页的距离得到ITravelLogEntry接口,再将后者传入ITravelLogStg的TravelTo方法以达到访问日志项的目的(如前进和后退)。

也许不是太恰当,我对UML也不熟悉,借用一个伪UML序列图表示其关系如下:

4、封装Travel Log

接下来,我们就用一个简单的类来完成对Travel Log的封装。如下所示,tlogstg.h包含了Travel Log的相关接口声明,该头文件可以在Platform SDK中找到。

#include "tlogstg.h"
class CIETravelLog
{
private:
ITravelLogStg *m_pTravelLogStg;
IEnumTravelLogEntry *m_pEnumLogEntry;
ITravelLogEntry *m_pTravalLogEntry;
IWebBrowser2* m_pWebBrowser;
public:
CIETravelLog(void);
~CIETravelLog(void);
void SetWebBrowser(IWebBrowser2* pWebBrowser);
void BuildHistoryMenu(CMenu * pMenu, unsigned char nCount, bool bForward);
void TravelTo(int nPosition);
};
CIETravelLog::CIETravelLog(void)
: m_pTravelLogStg(NULL), m_pEnumLogEntry(NULL), m_pTravalLogEntry(NULL), m_pWebBrowser(NULL)
{
}
CIETravelLog::~CIETravelLog(void)
{
if ( m_pTravelLogStg != NULL )
{
m_pTravelLogStg->Release();
}
if ( m_pEnumLogEntry != NULL )
{
m_pEnumLogEntry->Release();
}
if ( m_pTravalLogEntry != NULL )
{
m_pTravalLogEntry->Release();
}
if ( m_pWebBrowser != NULL )
{
m_pWebBrowser->Release();
}
}
//将浏览器的IWebBrowser2接口指针赋予CIETravelLog的实例
void CIETravelLog::SetWebBrowser(IWebBrowser2* pWebBrowser)
{
if ( (m_pWebBrowser == pWebBrowser) || (m_pWebBrowser ==