Internet Explorer 編程簡述(八)實現瀏覽曆史菜單

來源:互聯網
上載者:User
編程|菜單

關鍵字: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 == 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,以便在任何地方調用。然後在適當的地方,如CMainFrame的TBN_DROPDOWN訊息(工具條菜單下拉訊息)處理函數OnDropDown中,添加下面的代碼,用以建立瀏覽曆史菜單:

//GetActiveWebBrowserPtr返回活動的瀏覽器IWebBrowser2介面指標

IETravelLog.SetWebBrowser( GetActiveWebBrowserPtr );

//bForward為true則建立“前進”菜單,否則建立“後退”菜單

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_FIRST到ID_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 Explorer的Travel Log自然而然地就被整合到了我們的應用程式中。君不見,我們每天在資源管理員和瀏覽器上完成的工作,不就是在Travel Log中來來回回地跑嗎?如果所有的應用程式都嵌入到Internet Explorer中運行,那麼我們在應用程式中所作的操作便自然得到了記錄,“前進”和“後退”也就很Easy了。

很多軟體都已經或多或少地開始採用基於Internet Explorer的模式,如Microsoft Money、Microsoft Encarta、Visual Studio.net的安裝程式等等,都是很好的範例。所以,就目前來說,將我們的應用程式按這種模式編寫(可參考《利用瀏覽器實現程式介面與實現的分離》),不是可以早一點獲得“訪問日誌的體驗”嗎?何樂而不為。



聯繫我們

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