Доступ к объектной модели DHTML

   
На этом шаге мы рассмотрим пример программы, иллюстрирующей доступ к объектной модели 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. Пример работы приложения

   
Примечания.

  • Вы обнаружите, что пробелы в URL-адресах (таких как C:\Chapter 1\MyPage.htm) в окне
    View Links заменяются Esc-последовательностями. Причина в том, что Internet Explorer применяет функцию
    API InternetCanonicalizeUrl() и преобразует URL в формат, гарантирующий корректное разрешение
    ссылки. Чтобы отобразить адреса в более привычном виде, Вы можете использовать эту же функцию.
  • Перед компиляцией проекта нужно в установках проекта (пункт меню Project | Settings...)
    на вкладке C/C++ в категории C++ Language установить флажок Enable
    Run-Time Type Information (RTTI)


    Рис.7. Установка флажка Enable Run-Time Type Information (RTTI)

  • Приложение будет правильно работать только тогда, когда тэги <A> будут иметь параметр NAME или ID.
    Ознакомьтесь с содержанием файла MyPage.htm, который находится в архиве приложения.
  •    
    Созданное приложение можно взять здесь (45,3 Кб).

       
    На следующем шаге мы рассмотрим ресурсы HTML.



    Вы можете оставить комментарий, или Трекбэк с вашего сайта.

    Оставить комментарий