首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > CSS >

当IHTMLTxtRange:findText Method查寻不到字符串的时候

2013-09-28 
当IHTMLTxtRange::findText Method查找不到字符串的时候/*程序中的源码*/HRESULTCContentBehavior::Intern

当IHTMLTxtRange::findText Method查找不到字符串的时候

/*程序中的源码*/

HRESULT    CContentBehavior::InternalFindTextImpl(CComBSTR bstrText, DWORD dwFlag, BOOL  bSelected, DWORD *dwRet, BOOL bReplaceFind)
{
 if( dwRet)
  *dwRet =0;

 CStringW strText(bstrText);
 BOOL bBlankExists= strText.Find(L' ') >=0;


 FXE::CXMLPointerUtil tools(this); 
 CComPtr<IMarkupPointer> pStart, pEnd, pEndConst;

 tools.GetSelectedPointer(&pStart, &pEnd, NULL);

 if ( (pStart == NULL) || (pEnd == NULL))
  return E_FAIL;

 BOOL bAreEqual  = FALSE;
 pStart->IsEqualTo(pEnd, &bAreEqual);

 CComPtr<IHTMLElement> pElem;
 GetContentElement(&pElem);
 ASSERT(pElem);

 long nStep = 1L;
 MARKUP_CONTEXT_TYPE type = CONTEXT_TYPE_Text;

    long nCount = bstrText.Length();
 DWORD dwFlagTmp = dwFlag;
 if( dwFlag & FR_DOWN)
 {
  pEnd->MoveAdjacentToElement(pElem,  ELEM_ADJ_BeforeEnd );
  if( dwFlag & FR_LOOPFIND)
   pStart->MoveAdjacentToElement(pElem, ELEM_ADJ_AfterBegin);


   if((!bAreEqual)&&(!bReplaceFind))
      pStart->Right(TRUE, &type, NULL, &nCount, NULL);
 }
 else
 { //替换的时候,调用查找函数,是永远不会进入该else的。
  pStart->MoveAdjacentToElement(pElem, ELEM_ADJ_AfterBegin);
  if( dwFlag & FR_LOOPFIND)
   pEnd->MoveAdjacentToElement(pElem,  ELEM_ADJ_BeforeEnd );

  
   if((!bAreEqual)&&(!bReplaceFind))
      pEnd->Left(TRUE, &type, NULL, &nCount, NULL);
  nCount = -nCount;
 }

 
 dwFlag &= (~FR_DOWN);
 dwFlag &= (~FR_LOOPFIND);

    CComPtr<IHTMLDocument2> spDoc;
 GetHTMLDocument(&spDoc);
 if( spDoc == NULL)
  return E_FAIL;
 CComPtr<IHTMLElement> spBodyElement; 
 spDoc->get_body(&spBodyElement);
 ASSERT(spBodyElement);

 CComQIPtr<IHTMLBodyElement> spBody(spBodyElement);
 CComPtr<IHTMLTxtRange> spRange;
 spBody->createTextRange(&spRange);
 ASSERT(spRange);

 //选中范围
 CComQIPtr<IMarkupServices> pServices(spDoc); 

 pServices->CreateMarkupPointer(&pEndConst);
 pEndConst->MoveToPointer(pEnd);

 pServices->MoveRangeToPointers(pStart,pEnd,spRange);
 ASSERT(spRange);


 {
  VARIANT_BOOL   bRet = VARIANT_FALSE;
  HRESULT hr = spRange->findText( bstrText, nCount, dwFlag, &bRet);  //没有查找到并不代表spRange中真的没有bstrText这个字符串


  
  CComBSTR bstrTextR;
  spRange->get_text(&bstrTextR);
  
  CStringW strTextR(bstrTextR);
  
  CStringW strSearch(bstrText);
  strTextR.Replace(L"\r\n",L"\r");//避免换行导致的误差
  
  int n = -1;
  if (!(dwFlag & FR_MATCHCASE))
  {
   strTextR.MakeLower();
   strSearch.MakeLower();
  }

  if (dwFlagTmp & FR_DOWN)
  {
   n = strTextR.Find(strSearch);
  }
  else
  {
   std::wstring stdstrTextR = strTextR.GetBuffer(0);
   n = stdstrTextR.rfind(strSearch.GetBuffer(0));
   
  }
  

  bool bFind = false;
  if( bRet)
  {
   bFind = true;
  }
  else if (-1 != n && 0 == bRet)//如果n != -1,说明文档中是有这个字符串的,IHTMLTxtRange::findText查找不到,但是CStringW的查找方式可以查找到

//那么我们需要解决的一个问题那就是如果通过CStringW查找到的位置,来定位这个字符串在DOM中的位置
  {  

   while(true)
   {

    long nRealMoved = -1;
    HRESULT hrMove = S_OK;
    hrMove = spRange->move(CComBSTR(L"character") ,n, &nRealMoved);//IE给我们提供了这么一个接口,那就是IHTMLTxtRange::move函数,其可以在折叠Range后,移动空Range所在的位置,从Range最初的起始位置开始移动,第一个参数CComBSTR(L"character")表示要移动的字符数,但是你一定要记住,这个字符数并非指文本字符的个数,而是指的光标移动的个数,如果期间有图片,表格等非文本元素的时候,一样会占用移动个数。

 

//好了,如果能通过CStringW查找到的位置,用来移动Range的开始位置,是不是我们就定位到了字符串在文档中的位置了呢?

//关键也就在解决非文本字符暂用移动次数的问题了


    if (FAILED(hrMove) || n != nRealMoved)
    {
     bFind = false;
     break;
    }

    pServices->MovePointersToRange(spRange, pStart,pStart);
    nCount = abs(nCount);
    hrMove = spRange->move(CComBSTR(L"character") ,nCount, &nRealMoved);
    if (FAILED(hrMove) || nCount != nRealMoved)
    {
     bFind = false;
     break;
    }

    pServices->MovePointersToRange(spRange, pEnd, pEnd);

    pServices->MoveRangeToPointers(pStart, pEnd, spRange);


    //为了避免非文本格式(图片,音频,视频,表格)造成的误差

//这里也就是解决非文本元素暂用移动次数的解决方式,首先,如果有非文本元素,那么我们移动的次数就会被消耗掉一些,那么我们在还没有将Range移动到应该移动的位置,也就已经消耗完了移动次数,起初的时候,我将图片一类的非文本元素进行次数消耗记录,但是表格这样的非文本元素却非常难以统计,对此,我用了一个方法,那就是循环定位,所谓循环定位,就是在定位后的位置,继续查找要查找的字符串(刚才已经说了,非文本元素只会消耗掉移动次数,而不会凭空减少,所以我们定位不准确只有一种可能,那就是还没有移动到需要定位的字符串,而不可能已经超过了我们要定位的字符串所在的位置),如果刚好查找到,需要移动的次数为0,那也就说明我们刚好定位到了字符串,也就不需要移动了,我们也就在DOM中精确定位到了我们要查找到的字符串
    CComPtr<IHTMLTxtRange> spRangeTmp;
    spRange->duplicate(&spRangeTmp);
    
    pServices->MoveRangeToPointers(pStart, pEndConst, spRangeTmp);

    CComBSTR bstrTextRInner;
    spRangeTmp->get_text(&bstrTextRInner);

    CStringW strTextRInner(bstrTextRInner);

    n = strTextRInner.Find(strSearch);

    if (-1 == n)
    {
     bFind = false;
     break;
    }

    if (0 == n)
    {
     bFind = true;
     break;
    }

   }
   
  }

  if (bFind)
  {
   pServices->MovePointersToRange(spRange, pStart,pEnd);
   if( bSelected)
   { 
    spRange->select();
    tools.MoveCaretToPointer(pStart);
    spRange->scrollIntoView(); 
   }
   else
   {
    pServices->MoveRangeToPointers(pEnd,pEnd,spRange);  
    spRange->select();
    tools.MoveCaretToPointer(pEnd);
    spRange->scrollIntoView(); 
   }
   if( dwRet)
    *dwRet = 1;

  } 
  else
  {
   if( dwRet)
    *dwRet =2;
  }
 }

 return S_OK;
}

热点排行