Solved

Why CRichEditCtrl::FindText failed to work occasionally in Win2k?

Posted on 2001-09-05
15
588 Views
Last Modified: 2013-11-20
I had a program written for Win95 which use a Rich edit control to read several RTF files to search and replace text.
It worked well until I recompiled and ran the code on Win2k. In Win2k environment, I found that function FindText always failed to see the search string (even 1-character string, eg. "[" ) when it reaches to a specific point in some files bigger than 100K. It always return -1, even there are many occurances of the searched string existed in the remaining parts.
This specific point is different for different files, but it looks like to be about 50% of the file size

Any idea about this would be very appreciatd
0
Comment
Question by:hung2k
  • 7
  • 7
15 Comments
 
LVL 49

Expert Comment

by:DanRollins
ID: 6459383
I see nothing about a 100K limitation in the search fns. It should work.  Post the code that you use to call the FindText fn.

-- Dan
0
 

Author Comment

by:hung2k
ID: 6460066
Thanks Dan,
Here is the code, it works for most of my RTF files, except some big ones when I recompiled it in Win2k Prof
-------------

CRichTextCtrl inherits from CRichEditCtrl
This function starts finding an open bracket ([)
IsCode just check whether 2 letters follow the bracket
is in the list of untilCode to stop searching

The function FindText will return -1 immediately when the main program calls this function with a specific value of 'pos' eg. at pos=52686 in this file, but 188678 in another file

/*-------------------------------------------
* Skip the text and [dc  codes
*/
DWORD CRichTextCtrl::SkipVerse(long& pos, LPCTSTR untilCode )
{
     DWORD verseLen = 0L;
     FINDTEXTEX ft;
     long newpos = 0L;

     memset((void*)&ft, 0, sizeof(FINDTEXTEX));
     ft.chrg.cpMin = pos;
     ft.chrg.cpMax = GetTextLength() - 1;
     ft.lpstrText = "[";

     while ((newpos = FindText(0, (FINDTEXTEX*)&ft)) != -1L)
     {
          verseLen += (DWORD)(newpos - pos);
          pos = newpos;
          if (IsCode(pos + 1, untilCode))
               return verseLen;
          else
          {
                        verseLen++;
               ft.chrg.cpMin = ++pos;
          }
     }
     verseLen += (DWORD)(GetTextLength() - pos);
     pos = ft.chrg.cpMax;
     
     return verseLen;
}
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6461709
There are subtle differences in the RetchEdit common control that comes with Win2K, but I've not heard of this one.

One obvious Q is: Is there any chance that it is returning -1 correctly?  That is, perhaps there are no more "[" characters in the file...

Is there anything unusual about your text?  Is it a mixture of DBCS and regular ANSI text?  Dose it contain a lot of formatting such as italics, styles, etc?  If so, your verseLen calculations may be off.

It may be possible that GetTextLength() is returning the wrong value.  Does it make any difference if you use

   ft.chrg.cpMax= - 1;

Some problems can relate to the use of UNICODE.  There are actually two different versions of the EM_FINDTEXTEX message and two versions of the FINDTEXTEX structure.  One test to try:

   ft.lpstrText= _T( "[" ) ;

In attempting to isolate this problem, I would try using
    FINDTEXTEXW rFT;
    ...
    SendMessage( EM_FINDTEXTEXW,0,(LPARAM)&rFT)
and
    FINDTEXTEXA rFT;
    ...
    SendMessage( EM_FINDTEXTEXA,0,(LPARAM)&rFT)

-- Dan
0
 
LVL 3

Expert Comment

by:cypherljk
ID: 6461742
listening...
0
 

Author Comment

by:hung2k
ID: 6462656
Dan,
I've tried to debug to that point for several times, in all case, the "GetTextLength()-pos" returns a correct number of characters left from pos to the end of the text, say 2000 chars, and I know that within these 2000 chars left, there are many '['. But FindText returns -1 right in the first iteration of while loop, make my verseLen to be 2000.

My text is actually containing text only, nearly no formats, but because it has Vietnamese accents characters accompaning the vowels so there are many escape strings for them. An extract may be seen here can reflect the whole text for all the files:
---------------------------------------------------
{\b [11;}{ba\'f8n vo\'f8o nha\'f8, tha\'e1y tra\'fb cu\'f8ng me\'ef ngu\'f8i, ch\'ec sa\'e1p m\'ecnh huo\'e1ng ma\'f8 th\'f4\'f8 la\'efy va\'f8ng, nhu\'f5 h\'f6\'f4ng va\'f8 mo\'e4t d\'f6\'f4\'efc. }{\b [12;}{\'d1oa\'efn, ho\'ef \'f1\'f6\'f4\'efc [dc 1; Ghu\'f9t i \'f1\'f6\'f4\'f8ng nha\'f9c ka\'f8 ve\'e0 x\'f6\'f9 m\'ecnh.
\par [td S\'f6\'ef gho\'e1n qui n\'f6\'f4\'f9c ta\'e4p;
\par }
----------------------------------------------------
In Win95, I never saw any such failure searching thru this
I didn't use UNICODE for the moment. I will try to test the search with your suggestions.
Thank you for your time
0
 

Author Comment

by:hung2k
ID: 6469418
With some further debug to the point, I noticed that at the point this function failed to search, the rich text control did not load for all full texts, ie. even when GetTextLength return 2000 bytes, the SetSel and attempt to GetText for the remaining text always return some first characters, which doesnot get enough to the first '['. That's why FindText failed to search.

The question now is why does the control not load all of the text available for the search ?
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6469644
hmmm... So I was on the right track when I said... : Is there any chance that it is returning -1 correctly?  That is, perhaps there are no more "[" characters...

Does the file end on a particular sequence of bytes?  To find this out, first, note exactly where the file stops loading.  Then use the VC++ IDE to open the file as a binary file (File/Open and set Open As... to "Binary") and scroll down to that place in the file.

Examine that sequence that the RE control is considering to be the end of the file.  Post what you learn here.

Next, what technique to you use to read the file?  Please post your code here.  Thanks

Finally, what tool do you use to create the RTF file?  Perhaps it is creating a malformed file.

-- Dan
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:hung2k
ID: 6469798
I couldn't figure out which sequence of bytes may cause an unexpected end, since I'd try to move some sentences up or down just 1 sentence, the ending position will become a little further, eg. it can process many more sentences than the initial one, and stop at another unexpected point. Is there any sequence that worked with old RE control but not with the new one ?

One more point to see is that beside using above function SkipVerse with FindText to look for a sentence, in another place I also used Replace to replace some short texts in the sentence with more text then repeat to call the SkipVerse for the next sentence, of course with correct calculation for the pos of the next. I knew it worked well for old Win98. That's what cause headache.

I sent window message to load and write stream in call back function to read file.
------------------------------------------------
// Load the whole RTF file
docType = SF_RTF;
bRet = (BOOL)pRText->SendMessage(RT_LOADFROMFILE, (WPARAM)docType, (LPARAM)lpszFileName);
--------------------------------------------------


I declared
  ON_MESSAGE(RT_LOADFROMFILE, OnLoadFromFile)
-----------------------------------

DWORD CALLBACK CRichTextCtrl::FileStreamCallBack(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
  CRichTextFileCookie* pCookie = (CRichTextFileCookie*)dwCookie;
     
  CFile* pFile = (CFile*)pCookie->m_Data;
  DWORD dwResult = 0L;
  BYTE *llBuffer, *curPtr = pbBuff;

  TRY
  {     llBuffer = new BYTE[ cb+1];
      // If write into file
     if (pCookie->m_StoreFlag)
     {     pFile->Write(curPtr, cb);
          *pcb = cb;
     }
     else // Read from file
     {     curPtr = llBuffer;
          cb = pFile->Read(curPtr, cb);
          *pcb = cb;
     }
     CATCH(CFileException, e)
     {
          *pcb = 0;
          pCookie->m_dwError = (DWORD)e->m_cause;
          dwResult = 1L;
     }
     AND_CATCH_ALL(e)
     {
          *pcb = 0;
          pCookie->m_dwError = (DWORD)CFileException::generic;
          dwResult = 1L;
     }
     END_CATCH_ALL
     delete llBuffer;
     return dwResult;
}

//-------------------------------
BOOL CRichTextCtrl::LoadFromFile(LPCTSTR lpszFileName, int nFormat)
{
  long num;
  ASSERT(lpszFileName != NULL);

  DeleteContents();
     
  OFSTRUCT of;
  memset((void*)&of, 0, sizeof(OFSTRUCT));
  if (OpenFile(lpszFileName, &of, OF_EXIST) == HFILE_ERROR)
     return FALSE;
     
  CFile f;
  CRichTextFileCookie cookie;
  EDITSTREAM es = {0, 0, CRichTextCtrl::FileStreamCallBack};
  TRY
  {
     f.Open(lpszFileName, CFile::modeRead | CFile::shareDenyWrite);
  }
  CATCH(CFileException, e)
  {
     cookie.m_dwError = (DWORD)e->m_cause;
     goto MessageError;
  }
  END_CATCH
  cookie.m_Data = (DWORD)&f;
  es.dwCookie = (DWORD)&cookie;
  num = StreamIn(SF_RTF, es);
     
MessageError :
     if (cookie.m_dwError != 0)
     {
          ::AfxThrowFileException(cookie.m_dwError);
          return FALSE;
     }

     return TRUE;
}

//----------------------------------------------------


I used WinWord2000 to write the document, save it down
it couldn't be malformed since I had used them quite a longtime with old Windows98
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6471899
>>it couldn't be malformed since I had used them quite a longtime with old Windows98

The RE Common control is subtly different in Win2K, so it is quite possible that something that caused not problem in the older version causes a problem in the newer one.

One way to test this would be to read the RTF into WON on the Win2K machine and then save it back out.  See if the result is different.

-==-=-=-=-=-=-
The StreamIn fn will stop the process in a number of situations.  It will stop requesting data if the RE control thinks that it sees the end of the file (a closing curly brace to match the opening one {\rtf1

Also check the styles for the RE control itself.  Make certain that it contains the ES_MULTILINE style.  Documentations says that on a single-line RE control, the Stream is terminated by LF(0x0a), CR(0x0d), VT(0x0b), LS(???), or PS(???).  I don't know what LS and PS are.  

=-=-=-=-=--=

To diagnose this problem, place breakpoint in each of your CATCH blocks and see if any is hit.  Also place a breakpoint in FileStreamCallBack and observe when the final call is made to

   cb = pFile->Read(curPtr, cb);

cb should be 0 to indicate the end of the physical file.  If that never happens, then something in the file is signaling "all done."  You will need to LOOK THROUGH THE FILE to find where this is.  I can't do it for you.  Open the file in the IDE as a Binary file and scroll down to the point where the problem occurs.

-- Dan
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6471929
>>it couldn't be malformed since I had used them quite a longtime with old Windows98

The RE Common control is subtly different in Win2K, so it is quite possible that something that caused not problem in the older version causes a problem in the newer one.

One way to test this would be to read the RTF into WON on the Win2K machine and then save it back out.  See if the result is different.

-==-=-=-=-=-=-
The StreamIn fn will stop the process in a number of situations.  It will stop requesting data if the RE control thinks that it sees the end of the file (a closing curly brace to match the opening one {\rtf1

Also check the styles for the RE control itself.  Make certain that it contains the ES_MULTILINE style.  Documentations says that on a single-line RE control, the Stream is terminated by LF(0x0a), CR(0x0d), VT(0x0b), LS(???), or PS(???).  I don't know what LS and PS are.  

=-=-=-=-=--=

To diagnose this problem, place breakpoint in each of your CATCH blocks and see if any is hit.  Also place a breakpoint in FileStreamCallBack and observe when the final call is made to

   cb = pFile->Read(curPtr, cb);

cb should be 0 to indicate the end of the physical file.  If that never happens, then something in the file is signaling "all done."  You will need to LOOK THROUGH THE FILE to find where this is.  I can't do it for you.  Open the file in the IDE as a Binary file and scroll down to the point where the problem occurs.

-- Dan
0
 

Author Comment

by:hung2k
ID: 6473113
I'd reviewed, and tried to see whether the loading mechanism had problems. I commented out all the process code on the RE. Just only load it into the control and then write back out. And it appeared that actually my RE control always loaded only maximum 32k of characters into the control, so for my big file, the data has been truncated right on the loading process. After loading that number of characters, the RE can accomodate for replacement or changes to expand the content more, but because the loaded content has been truncated, I hadnot been able to find out text far upon the truncated point.

The limit of 32k is new to me. Is it true that in Win2k, the RE control now will have such a limit ?
I will try to test LimitText to a bigger number. I  thought that by default, this limit is 0x7FFFFFFF, which is far big enough for all my need.
0
 
LVL 49

Accepted Solution

by:
DanRollins earned 70 total points
ID: 6473318
Here is a version of RE callback handling.  It is simplified to the bare minimum, having removed all TRY...CATCH code (by the way, when I start looking for problems, the *first* thing I do is remove the TRY...CATCH blocks because they mask the true error).  It also removes the CRichTextFileCookie nonsense and gets rid of other code bloat, including the unnecessary buffer allocation in your FileStreamCallBack() f.:

Anyway, this works perfectly in Win98 and Win2K
=-=-=-=-=-=-=-=-=-=-=-=-

DWORD CALLBACK FileStreamCbRead(DWORD dwCookie, LPBYTE pbBuf, LONG cb, LONG *pcb)
{
    CFile* pFile = (CFile*)dwCookie;
    DWORD dwResult = 0L;
    *pcb= pFile->Read( pbBuf, cb );
    return dwResult;
}
DWORD CALLBACK FileStreamCbWrite(DWORD dwCookie, LPBYTE pbBuf, LONG cb, LONG *pcb)
{
    CFile* pFile = (CFile*)dwCookie;
    DWORD dwResult = 0L;
    pFile->Write( pbBuf, cb );
    *pcb= cb;
    return dwResult;
}
void CD7REDlg::OnButton1()
{
    m_ctlRichEd.SetSel(0,-1);
    m_ctlRichEd.Clear();
    m_ctlRichEd.LimitText( 200000 );

    LPCSTR pszFile= "c:\\temp\\junk.rtf";

    CFile f;
    EDITSTREAM es = {0, 0, FileStreamCbRead };
    f.Open( pszFile, CFile::modeRead | CFile::shareDenyWrite);

    es.dwCookie = (DWORD)&f;
    long  num= m_ctlRichEd.StreamIn(SF_RTF, es);
    f.Close();
}

void CD7REDlg::OnButton2()
{
    LPCSTR pszFile= "c:\\temp\\junkSaved.rtf";

    CFile f;
    EDITSTREAM es = {0, 0, FileStreamCbWrite };
    f.Open( pszFile, CFile::modeCreate | CFile::modeWrite );

    es.dwCookie = (DWORD)&f;
    long num= m_ctlRichEd.StreamOut(SF_RTF, es);

    f.Close();
}
=-=-=-=-=-=-=-=-=-=-=-=-
One thing I did add was a call to
   
    m_ctlRichEd.LimitText( 200000 );

because without it, I found that I could not add new text to the end of a large file.

-- Dan
0
 

Author Comment

by:hung2k
ID: 6475504
Thank you Dan,
The problem has been solved with LimitText.
Your code is very clean, I will revise my code
Actually, there were some extra processing codes in my own version to process other options too. But your suggestions are appreciated

Because you had followed it and suggested me to the solution of the issue, you should have the point.

Thank you once more

Hung
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6475949
Hi hung2k,
Thanks for accepting my comment as an answer.

As an expert here at EE, I am striving to obtain a "4.0" grade point average.  You have awarded me a "B" which degrades my average.  I'm sure that you intended no harm, but I would appreciate it if you would answer a few questions -- to help me attain my goal:

1) Was my comment unclear?  Is my use of the English language inadequate?

2) What could I have added that would bring my comment up from a "B" to an "A" ?

3) Did I offend you in any way?

4) Are you aware that it costs you the same number of points to award an Excellent (A)?  Do you understand that Experts prefer getting an A's and we will often spend more time helping users who have a history of awarding A's?

Here at EE, experts get no payment beyond the "pat on the back" when an answer is accepted.   So when you give a "B" it is a bit like saying "If you were a little smarter, you could have solved my problem sooner.  Next time try harder."  

-- Dan
0
 

Author Comment

by:hung2k
ID: 6486770
Dear Dan,
Sorry that I've made a mistake that the granting of a B grade is degrading your average.
I did not mean anything to offend you. I was not quite familiar to the grading process in EE. Just thinking that the points would be worthful to you, and that the rating for the answer would be worthful to other readers only. Because of my bad perception upon the bug, your answers and my focus didn't get into the main point after so many trials. I thought that my question was not a good question and the last answer is not for it but rather for another thing.
That's why I graded it as B. Not mean anything about your skill personally.

Sorry one more time, Dan. If you think that I can do something here to regrade it back. I will do.
Thank you very much for your comments

Hung
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now