基于ie内核的网页高亮查找

      采用ie内核做浏览器,很多时候需要增加一个查找网页内容,然后高亮的功能。这个功能可以采用微软的com接口来完成。

      最基本的步骤就是先通过IWebBrowser2获取到IHTMLDocument2,然后通过IHTMLDocument2获取到IMarkupContainer,IMarkupServices。通过IMarkupServices创建2个IMarkupPointer指针,这两个IMarkupPointer需要放到IMarkupContainer中去,调用接口IMarkupContainer的方法MoveToContainer即可。

     这些步骤准备好后,即可调用IMarkupPointer的FindText接口进行查找遍历的功能。对于查找到的元素,可以采取IMarkupServices接口的方法CreateElement来添加背景色STYLE="background-color:#00ff00“,添加完背景色后需要将查找到的元素显示到那个位置,采用如下方式:

 VARIANT var;
  var.vt = VT_BOOL;
  var.boolVal = VARIANT_FALSE;
  IHTMLElement->scrollIntoView( var );

 

     去除背景色可以采用IMarkupServices的方法RemoveElement(s);

 

 代码如下:

void SearchText(IHTMLDocument2* pDoc2,IMarkupContainer** pMarkupcontainer,IMarkupServices **pMarkSer,
        IMarkupPointer** pMarkPtrStart,IMarkupPointer** pMarkPtrEnd,int& dwCount)
{
 HRESULT hr = S_FALSE;


 if( *pMarkupcontainer == NULL )
 {
  hr = pDoc2->QueryInterface( IID_IMarkupContainer, (void **) pMarkupcontainer );
  if( hr != S_OK )
   return;
 }
 if( *pMarkSer == NULL )
 {
  hr = pDoc2->QueryInterface( IID_IMarkupServices, (void **) pMarkSer );
  if( hr != S_OK )
   return;
 }

 if( *pMarkPtrStart == NULL )
 {
  // need two pointers for marking
  hr = (*pMarkSer)->CreateMarkupPointer(  pMarkPtrStart );
  if( hr != S_OK )
   return;
 }
 if( *pMarkPtrEnd == NULL )
 {
  // beginning and ending position of text.
  hr = (*pMarkSer)->CreateMarkupPointer(  pMarkPtrEnd );
  if( hr != S_OK )
   return;
 }

 // Set gravity of this pointer so that when the replacement text
 // is inserted it will float to be after it.
 hr = (*pMarkPtrStart)->SetGravity( POINTER_GRAVITY_Right );
 if( hr != S_OK )
  return;
 hr = (*pMarkPtrEnd)->SetGravity( POINTER_GRAVITY_Left );
 if( hr != S_OK )
  return;

 // Start the search at the beginning of the primary container
 hr = (*pMarkPtrStart)->MoveToContainer( *pMarkupcontainer, TRUE );
 if( hr != S_OK )
  return;
 hr = (*pMarkPtrEnd)->MoveToContainer( *pMarkupcontainer, FALSE );
 if( hr != S_OK )
  return;

 DWORD dwFlags = 0;
 if( m_bMatchCase )
  dwFlags |= FINDTEXT_MATCHCASE;

 for( ; ;)
 { 
  hr = (*pMarkPtrStart)->FindText( m_bszSearchText, dwFlags, *pMarkPtrEnd, NULL );

  if (hr == S_FALSE) // did not find the text
   break;
  

  m_nCount ++;
  dwCount++;
  //pIHtmlElement->get_parentElement(&pParentElement);
  CComPtr<IHTMLElement> pIHtmlElement;
  bool bFlag = false;

  (*pMarkPtrStart)->CurrentScope(&pIHtmlElement);
  if( pIHtmlElement != NULL )
  {
  
   for ( ; ;)
   {
    CComQIPtr<IHTMLElement2, &IID_IHTMLElement2> pIHtmlElement2(pIHtmlElement);
    CComPtr<IHTMLElement> pParentElement = NULL;

    if (S_OK != pIHtmlElement->get_parentElement(&pParentElement) || NULL == pParentElement)
     break;

    CComPtr<IHTMLCurrentStyle> pHtmlStyle = NULL;

    pIHtmlElement2->get_currentStyle(&pHtmlStyle);

    CComBSTR bszDisplay, bszVisible;

    if( pHtmlStyle != NULL )
    {
     pHtmlStyle->get_display(&bszDisplay);
     pHtmlStyle->get_visibility(&bszVisible);
    }

    if (0 == StrCmpI( _T("none") , bszDisplay) || 0 == StrCmpI(_T("hidden") , bszVisible) )
    {
     bFlag = true;
     m_nCount --;
     dwCount--;
     break;
    }

    bFlag = false;
    pIHtmlElement = pParentElement;
   }
  }

  if( m_bHighlight && !bFlag )
  {
   InsertMarkup( *pMarkSer, *pMarkPtrStart, *pMarkPtrEnd, false, false );
  }

  // Continue searching
  (*pMarkPtrStart)->MoveToPointer( *pMarkPtrEnd);
 } 
}

 

 

      有些复杂的页面采取frame的方式,如csdn的论坛页面,这时候需要遍历出所有的frame中的document

网页的布局如下:

 

 

可以采用递归遍历frame的方式,然后遍历出document,再采用开头的方式即可查找

 

递归如下:

 

void SearchInFrame(IHTMLDocument2 *pDoc)
{
 CComPtr<IHTMLFramesCollection2> frames;
 HRESULT hr = pDoc->get_frames(&frames);

 if(SUCCEEDED(hr) && frames)
 {
  long p = 0;
  frames->get_length(&p);
  for(long f = 0;f<p;f++)
  {
   variant_t frame;
   frames->item(&_variant_t(f),&frame);
   if((IDispatch*)frame)
   {
    CComPtr<IHTMLWindow2>  elem;
    hr = ((IDispatch*)frame)->QueryInterface(IID_IHTMLWindow2, (void**)&elem);
    if(SUCCEEDED(hr) && elem)
    {
     CComPtr<IHTMLDocument2>  lpHtmlDocument;
     hr  = elem->get_document(&lpHtmlDocument);
     if (SUCCEEDED(hr) && lpHtmlDocument)
     {

      SEARCH_INFO _info = {0};
      SearchText(lpHtmlDocument,&_info.m_pContainer,&_info.m_pServices,&_info.m_pPointerStart,&_info.m_pPointerEnd,_info.m_TotalCount);
      _info.m_nCurPos = SEARCH_BEGIN;
      if (_info.m_TotalCount > 0)
      {
       m_listSearchInfo.push_back(_info);
      }

      SearchInFrame(lpHtmlDocument);
     }

     

    }
   }
  }
 }
}

 

在我们查找到相应的字符后需要高亮,并且让网页滚动到相应位置,如果采用IHTMLElement 接口的scrollIntoView 会导致某些页面发生页面布局变化错位的问题,这是的确非常棘手。还好,ie还有一套接口可以高亮查找,IHTMLTxtRange,采用IHTMLTxtRange的scrollIntoView 可以解决这个问题,所以如果要非常完美的实现高亮查找功能,需要两者结合用

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值