На этом шаге мы рассмотрим пример программы, иллюстрирующей доступ к объектной модели 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 или пути к файлу). Пользователь сможет открыть любую из этих ссылок в браузере.
- Создание диалогового окна View Links.
- В редакторе диалогов создайте диалоговое окно View Links с идентификатором IDD_LINK_DIALOG (рисунок 1).
Оно должно содержать большой список под названием IDC_LINK_LIST, а также стандартные кнопки ОК и Cancel. После этого
ОК переименуйте в Go to link.
Рис.1. Диалоговое окно View Links - В редакторе ресурсов нажмите CTRL+W, чтобы создать класс диалога CLinkDialog для диалогового окна View Links.
Рис.2. Создание класса CLinkDialog
На странице Member Variables мастера ClassWizard добавьте переменные, перечисленные в таблице 1.Таблица 1. Переменные диалогового окна View Links
Идентификатор Категория Тип переменной Имя переменной ресурса IDC_LINK_LIST Переменная CString m_strLink IDC_LINK_LIST Элемент управления CListBox m_lbLinkList
Рис.3. Результат добавления переменных - На вкладке Message Maps мастера ClassWizard перегрузите функцию OnInitDialog()
класса CLinkDialog (для обработки сообщения WM_INITDIALOG). Щелкните Edit Code для
редактирования тела функции.
Рис.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 }
Проанализируйте текст этой функции, чтобы понять, как она работает. Указатель на диспетчерский интерфейс HTML-документа извлекается вызовом
функции CHtmlView::GetHtmlDocument(). Далее он применяется для получения указателя на интерфейс
IHTMLDocument2, а функция IHTMLDocument2::get_anchors() вызывается для получения указателя на
набор DHTML-анкеров. Функция InitDialog() последовательно просматривает набор анкеров, извлекая
на каждом этапе указатель на текущий элемент IHTMLAnchorElement и добавляя в список значение его HREF-атрибута. - В начало файла LinkDialog.cpp рядом с другими директивами #include добавьте следующие строки:
#include <mshtml.h> #include <comdef.h>
В файле mshtml.h содержатся определения IHTML-интерфейсов. Comdef.h содержит определение
вспомогательного СОМ-класса _variant_t. - Создайте в меню View новую команду Links с выбранным по умолчанию идентификатором
ID_VIEW_LINKS. Средствами ClassWizard создайте для него функцию-обработчик
CMyHtmlAppView::OnViewLinks.
Рис.5. Создание функции-обработчика CMyHtmlAppView::OnViewLinks - В тело функции 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); } }
- В начале файла MyHtmlAppView.cpp рядом с другими директивами #include добавьте следующую строку:
#include "LinkDialog.h"
- Теперь Вы можете собрать и запустить приложение. Работая с ресурсами Web или локальными HTML-файлами, убедитесь, что
при выборе команды Links меню View приложение отображает в диалоговом окне все ссылки текущей
страницы. Выберите ссылку из этого списка и щелкните Go to link, чтобы проверить корректность перехода по
ссылке. На рисунке 6 приведен пример работы приложения.
Рис.6. Пример работы приложения
Примечания.
View Links заменяются Esc-последовательностями. Причина в том, что Internet Explorer применяет функцию
API InternetCanonicalizeUrl() и преобразует URL в формат, гарантирующий корректное разрешение
ссылки. Чтобы отобразить адреса в более привычном виде, Вы можете использовать эту же функцию.
на вкладке C/C++ в категории C++ Language установить флажок Enable
Run-Time Type Information (RTTI)
Рис.7. Установка флажка Enable Run-Time Type Information (RTTI)
Ознакомьтесь с содержанием файла MyPage.htm, который находится в архиве приложения.
Созданное приложение можно взять здесь (45,3 Кб).
На следующем шаге мы рассмотрим ресурсы HTML.