На этом шаге мы рассмотрим пример программы, иллюстрирующей доступ к объектной модели DHTML.
Как Вы помните, доступ к DHTML-объектам, таким, как window или document, очень прост, если сценарий размещен непосредственно в HTML-документе. Ссылаться на эти объекты разрешается просто по имени, как показано в следующем коде на JavaScript:
document.bgColoг = "hotpink";
Такая возможность обусловлена тем, что интерпретатор сценариев Internet Explorer анализирует строки Вашего сценария и преобразует их в вызовы интерфейсов Internet Explorer Automation. В C++ к объектной модели DHTML обращаются напрямую, вызывая соответствующие интерфейсы Automation.
Объектная модель DHTML доступна через набор СОМ-интерфейсов, имена которых начинаются с префикса IHTML (IHTMLDocument, IHTMLWindow, IHTMLElement и т. п.). Класс CHtmlView предоставляет функцию GetHtmlDocument(), возвращающую указатель IDispatch на текущий HTML-документ. Зная его, Вы можете вызвать QueryInterface() и получить указатели на IHTML-интерфейсы. А это в свою очередь позволит Вам управлять документом, работая со свойствами и методами этих интерфейсов.
Ниже мы посмотрим, как обращаться к элементам HTML-страницы, отображенной в приложении MyHtmlApp. Мы напишем код, создающий в отдельном диалоговом окне список всех анкеров (ссылок) текущей страницы со значениями их HREF-атрибутов (URL или пути к файлу). Пользователь сможет открыть любую из этих ссылок в браузере.
Рис.1. Диалоговое окно View Links
Рис.2. Создание класса CLinkDialog
Идентификатор | Категория | Тип переменной | Имя переменной ресурса |
---|---|---|---|
IDC_LINK_LIST | Переменная | CString | m_strLink |
IDC_LINK_LIST | Элемент управления | CListBox | m_lbLinkList |
Рис.3. Результат добавления переменных
Рис.4. Перегрузка функции OnInitDialog()
BOOL CLinkDialog::OnInitDialog() { CDialog::OnInitDialog(); // Получаем указатель на вид CFrameWnd * pFrame = dynamic_cast<CFrameWnd *>( AfxGetMainWnd()); ASSERT_VALID( pFrame ); CHtmlView * pHtmlView = dynamic_cast<CHtmlView *> ( pFrame->GetActiveView()); ASSERT_VALID( pHtmlView ); // Получаем указатель на диспетчерский интерфейс // объекта документа IDispatch * pDisp = pHtmlView->GetHtmlDocument(); if( pDisp != NULL ) { // Получаем указатель на интерфейс IHTMLDocument2 // для доступа к свойствам и методам объекта IHTMLDocument2 * pHTMLDocument2; HRESULT hr; hr = pDisp->QueryInterface( IID_IHTMLDocument2, (void**)&pHTMLDocument2 ); if( hr == S_OK ) { // Получаем указатель на набор анкеров IHTMLElementCollection * pColl = NULL; hr = pHTMLDocument2->get_anchors( &pColl ); if( hr == S_OK && pColl != NULL ) { LONG nElem; hr = pColl->get_length( &nElem ); if( hr == S_OK ) { // Просматриваем набор анкеров for( long i = 0; i < nElem; i++ ) { _variant_t vIndex( i ); _variant_t vName = vIndex; IDispatch * pDisp2; hr = pColl->item( vName, vIndex, &pDisp2 ); if( hr == S_OK ) { // Получаем указатель на каждый // из элементов <Anchor> для // получения URL-адреса и его // включения в список HTMLAnchorElement * pAnchElem; hr = pDisp2->QueryInterface( IID_IHTMLAnchorElement,(void**) &pAnchElem ); if( hr == S_OK ) { BSTR bstrHref = 0; pAnchElem->get_href( &bstrHref ); CString strLink( bstrHref ); if( !strLink.IsEmpty() ) m_lbLinkList.AddString( strLink ); SysFreeString( bstrHref ); pAnchElem->Release(); } pDisp2->Release(); } } } pColl->Release(); } pHTMLDocument2->Release(); } pDisp->Release(); } return TRUE; // Возвращаем TRUE, если только фокус // не на элементе управления // ИСКЛЮЧЕНИЕ: OCX-страницы свойств // должны возвращать FALSE }
#include <mshtml.h> #include <comdef.h>
Рис.5. Создание функции-обработчика CMyHtmlAppView::OnViewLinks
void CMyHtmlAppView::OnViewLinks() { CLinkDialog aDlg; if(aDlg.DoModal() == IDOK) // (Кнопка "Go to link") { // Если в списке есть выбранная ссылка - переходим на нее if (! aDlg.m_strLink.IsEmpty()) Navigate2(aDlg.m_strLink, NULL, NULL); } }
#include "LinkDialog.h"
Рис.6. Пример работы приложения
Рис.7. Установка флажка Enable Run-Time Type Information (RTTI)
Созданное приложение можно взять здесь (45,3 Кб).
На следующем шаге мы рассмотрим ресурсы HTML.