Internet Explorer 编程简述(八)实现浏览历史菜单

原创 2005年03月03日 00:36:00

 

关键字:ITravelLogStg, IEnumTravelLogEntry, ITravelLogEntry

 

1、概述

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

 

2IOmHistory接口

在早些时候的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接口公布之前,要完全模拟IETravel Log行为,并不是一件容易的事。最容易想到的方法就是在BeforeNavigateDocumentComplete等事件发生之时记录/修改Url并加以保存(我在早些时候也这样做过),但是效果不甚理想,尤其是浏览包含Frame的网页时,处理更是麻烦。当然,要完全模拟亦非难事,只不过开发人员都知道微软公布接口是早晚的事,所以也没有人花大力气在模拟IETravel Log行为上。

 

3Travel 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, IEnumTravelLogEntryITravelLogEntry

 

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

方法名     用途

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

GetRelativeEntry 返回一个日志项

TravelTo 访问一个日志项

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

方法名     用途

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

  • ITravelLogEntry——该接口只有两个方法,分别用于返回日志项的TitleUrl

方法名     用途

GetTitle 返回日志项的Title

GetURL 返回日志项的Url

 

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

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

 

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

 

 

 Travel Log

 

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 == NULL) )

{

return;

}

if ( m_pWebBrowser != NULL )

{

m_pWebBrowser->Release();

}

m_pWebBrowser = pWebBrowser;

 

IServiceProvider *pSP;

HRESULT hr = m_pWebBrowser->QueryInterface(IID_IServiceProvider, (LPVOID*)&pSP);

m_pWebBrowser->Release();

if (SUCCEEDED(hr))

{

hr = pSP->QueryService(SID_STravelLogCursor, IID_ITravelLogStg, (LPVOID*)&m_pTravelLogStg);

pSP->Release();

}

}

 

//创建浏览历史菜单,bForward指明是前进还是后退菜单

void CIETravelLog::BuildHistoryMenu(CMenu * pMenu, unsigned char nCount, bool bForward)

{

if ( m_pTravelLogStg == NULL )

{

return;

}

TLENUMF eFlag = bForward ? TLEF_RELATIVE_FORE : TLEF_RELATIVE_BACK;

if ( FAILED(m_pTravelLogStg->EnumEntries( eFlag, &m_pEnumLogEntry ) ) )

{

return;

}

 

ULONG uFetched;

int i=0;

if ( m_pEnumLogEntry !=NULL )

{

while ( SUCCEEDED( m_pEnumLogEntry->Next( 1, &m_pTravalLogEntry, &uFetched ) ) &&

m_pTravalLogEntry && i<10 )//我们最多只需要10条历史菜单,可根据实际情况修改

{

LPOLESTR pszTitle;

m_pTravalLogEntry->GetTitle( &pszTitle );

CString strTitle = pszTitle;

if ( bForward )

{

//ID_IEHISTORY_MIDDLE是预定义的某个菜单项ID,从该ID开始前后可以创建10个菜单项,参见下一节

pMenu->InsertMenu( 0, MF_STRING, ID_IEHISTORY_MIDDLE + ++i, strTitle );

}

else

{

pMenu->InsertMenu( 0, MF_STRING, ID_IEHISTORY_MIDDLE - ++i, strTitle );

}

CoTaskMemFree( pszTitle );

m_pTravalLogEntry->Release();

}

}

}

 

//根据与当前页面的相对距离来访问历史网页

void CIETravelLog::TravelTo(int nPosition)

{

if ( m_pTravelLogStg == NULL )

{

return;

}

if SUCCEEDED(m_pTravelLogStg->GetRelativeEntry( nPosition, &m_pTravalLogEntry ))

{

m_pTravelLogStg->TravelTo( m_pTravalLogEntry );

}

}

 

5、使用CIETravelLog

假设是在我们自己编写的多窗口浏览器中使用Travel Log。为简单起见,我们声明一个CIETravelLog的全局对象g_IETravelLog,以便在任何地方调用。然后在适当的地方,如CMainFrameTBN_DROPDOWN消息(工具条菜单下拉消息)处理函数OnDropDown中,添加下面的代码,用以创建浏览历史菜单:

//GetActiveWebBrowserPtr返回活动的浏览器IWebBrowser2接口指针

IETravelLog.SetWebBrowser( GetActiveWebBrowserPtr );

//bForwardtrue则创建“前进”菜单,否则创建“后退”菜单

IETravelLog.BuildHistoryMenu( &Menu, 10, bForward);

 

以下定义为菜单项ID的范围,前后共可以容纳10个菜单项,可根据实际情况修改。

#define ID_IEHISTORY_FIRST  60200

#define ID_IEHISTORY_MIDDLE 60210

#define ID_IEHISTORY_LAST   60220

 

添加命令处理函数OnTravelHistoryUrl用以响应从ID_IEHISTORY_FIRSTID_IEHISTORY_LAST的菜单命令。

 

ON_COMMAND_RANGE(ID_IEHISTORY_FIRST, ID_IEHISTORY_LAST, OnTravelHistoryUrl)

 

void CMainFrame::OnTravelHistoryUrl(UINT nID /* Command ID */)

{

//nID - ID_IEHISTORY_MIDDLE即为要访问的浏览历史到当前页面的距离

g_IETravelLog.TravelTo( nID - ID_IEHISTORY_MIDDLE );

}

 

6、再谈Travel Log

前面我提到“Travel Log接口正日益成为应用程序中的重要接口之一”,此处加以说明。从微软平台的开发模式及导向来看,基于Internet Explorer/WebBrowser Control的应用势必会成为主流。在下一代的操作系统Longhorn中,应用程序界面的描述将完全由XML的一个特化——XAML来完成,而XAML的解析将由浏览器完成。微软说未来应用程序的部署将会十分容易,本地应用和基于浏览器的应用之间的差异将会被逐渐淡化,而实现这一目标的一个重要表现就是,在将来的操作系统平台上,应用程序实际上时刻都将运行在Internet Explorer中,Internet Explorer在某种程度上来说变成了一个容器。

于是,扎根于Internet ExplorerTravel Log自然而然地就被整合到了我们的应用程序中。君不见,我们每天在资源管理器和浏览器上完成的工作,不就是在Travel Log中来来回回地跑吗?如果所有的应用程序都嵌入到Internet Explorer中运行,那么我们在应用程序中所作的操作便自然得到了记录,“前进”和“后退”也就很Easy了。

很多软件都已经或多或少地开始采用基于Internet Explorer的模式,如Microsoft MoneyMicrosoft EncartaVisual Studio.net的安装程序等等,都是很好的范例。所以,就目前来说,将我们的应用程序按这种模式编写(可参考《利用浏览器实现程序界面与实现的分离》),不是可以早一点获得“访问日志的体验”吗?

何乐而不为。

 

引用地址:《Internet Explorer 编程简述(八)实现浏览历史菜单

JQuery练习-静态web菜单管理

 前面简单介绍了下JQuery是什么,这里用JQuery简单实现了一个静态网页版的菜单编辑器,重点是为了加深对JQuery对数据访问及数据操作的理解。 代码如下,注释我写的很详细,有些地方还是...
  • u012882327
  • u012882327
  • 2015-09-09 11:42:34
  • 593

菜单的使用

android一共有三种形式的菜单:              1.选项菜单(optinosMenu)              2.上下文菜单(ContextMenu)            ...
  • LGGisKing
  • LGGisKing
  • 2015-04-13 01:58:22
  • 384

WindowsExplorer 和 InternetExplorer 中缺少工具栏 / 菜单栏解决方案

[HKEY_CURRENT_USER/Software/Microsoft/Internet Explorer/Toolbar/Explorer]"ITBarLayout"解决方案警告 : 如果注册表...
  • CQP
  • CQP
  • 2006-09-22 21:22:00
  • 1784

常见的浏览器的历史,netscape,ie,opera,mozilla,firefox,safari

 netscape navigator是最早流行的,其engine是基于mozilla的,其user-agent string声明为Mozilla/AppVersion (Platform; Secu...
  • yethyeth
  • yethyeth
  • 2007-04-02 14:00:00
  • 3963

每日练习

JavaScript 编程题 按照下列要求,用JavaScript写一个年,月,日的联动菜单。1、默认显示当前日期; 2、选择年才可以选择月,选择月才可以选择日,并且 2 月的天数要正确; ...
  • LJ1316796545
  • LJ1316796545
  • 2017-12-04 09:46:46
  • 17

有了这个列表,程序员不愁没练手的小项目了

我经常看有人发帖问关于项目点子的事,也看到了很多回帖,我自己也回了一些常见的项目。不过我觉得只列出三两个是远远不够的,因此就收集并这个项目列表,大家要找简单的编程项目学习练手的话,可以收藏并扩散本文。...
  • wo8553456
  • wo8553456
  • 2015-11-19 11:08:41
  • 3884

桌面上的Internet explorer图标删不掉

方法一:当我们在一些不太安全和不友好的网站上下一些安装软件之后,会发现在运行安装后,桌面上莫名其妙的多了一个IE快捷方式,无法删除!!点击这个多余的IE会默认打开某个网址导航等,当按右键删除命令会自动...
  • haosxianr
  • haosxianr
  • 2010-08-20 18:05:00
  • 1101

Internet Explorer 编程简述(序)

一直对Microsoft Internet Explorer编程非常感兴趣,曾花了不少时间琢磨,也与众多网友讨论过问题,2000年将心得写成一篇《TWebBrowser编程简述》,发表在自己的个人主页...
  • delphi99
  • delphi99
  • 2011-09-22 16:04:21
  • 214

C#开发实例大全(提高卷).软件开发技术联盟(带详细书签) PDF 下载

IE<em>浏览</em>器设置、加密与解密技术、数据库安全技术、...为文件新增右键<em>菜单</em>项实例082 修改计算机的默认打印机...<em>编程</em>修复Access数据库实例589 Access数据库备份与恢复...
  • 2018年04月14日 00:00

小程序 学习。。。[个人感觉吧 官方文档写的相当详细了。。]

作者:初雪 链接:https://www.zhihu.com/question/50907897/answer/128494332 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载...
  • zhangmengleiblog
  • zhangmengleiblog
  • 2017-09-14 11:37:05
  • 8084
收藏助手
不良信息举报
您举报文章:Internet Explorer 编程简述(八)实现浏览历史菜单
举报原因:
原因补充:

(最多只允许输入30个字)