Solved

RichEd20 Problem: RTF Text insertion too slow

Posted on 2004-08-12
20
614 Views
Last Modified: 2012-08-13
Hello all.  I'm currently writing a code editor that I'm trying to make as close to the VB IDE as possible.  One thing it will have is colored keywords, comments, and strings.  I already have a function that goes through the text, determines what needs to be colored, and spits out the appropriate RTF code.  For my tests, I'm using 5000 lines, each with 4 color words.  The line checking goes through all of them and returns one big string containing all 5000 lines with an RTF header and tags in the appropriate places.

Here's were the bottleneck happens.  I can't seem to get this RTF text into the box without it taking WAY too long.  At first I was using the standard RichTextBox control and inserting via .SelRTF.  Later, I ditched that for vbAccelerator's RichEdit control and tried using the EM_STREAMIN method.  The gain was minimal at best.  The single line that inserts the text takes approximately 19 seconds to execute on my P4 1.7GHz machine.  This is unacceptable.

VB's IDE is able to color the same 5000 lines in the blink of an eye... There has to be a faster way.  Does anyone know how I can speed this up?
0
Comment
Question by:MasamuneXGP
  • 11
  • 9
20 Comments
 
LVL 15

Expert Comment

by:ameba
ID: 11785981
Hi MasamuneXGP,
> The line checking goes through all of them and returns one big string
> containing all 5000 lines with an RTF header and tags in the appropriate places.

Concatenation in VB isn't optimized, producing a string using '&' will be very slow.  There are few solutions for faster string operations, e.g. there is a StringBuilder class by Karl E. Peterson, which uses byte array internally, but for your purpose Join() will work:

    S2RTF = rtfhdr & Join(sLines(), vbCrLf & "\par ") & rtftail

where sLines() is array containing rtf code for each line.
That should work well for cases when editor is opening a file, or user is pasting a big block to editor.

Cheers!
0
 

Author Comment

by:MasamuneXGP
ID: 11786150
Erm... let me clarify.  It is not my function that is lagging.  I am well aware of the & operator's suckiness, and am using some pretty advanced techniques to generate the string quickly (the SafeArray hack for example).  The lagging comes when I try to actually insert the text.  It is this one line, where RTFBuild is the variable containing the string:

(VB's Rich TextBox)
.SelRTF = RTFBuild

(vbAccel's RichEdit)
.InsertContents SF_RTF, RTFBuild

Both of those take upwards of 19 seconds to execute.  Hense my problem.
0
 

Author Comment

by:MasamuneXGP
ID: 11786282
I apologize for doubleposting, but this may be relevent.  Here is what RTFBuild looks like before I insert it.  Keep in mind it's just for testing purposes, so don't expect it to make sense or anything =p  As you can see, each line has four color words in it, and that's definately what's slowing it down.  Removing the color words has the text inserted much quicker (although still a tad laggy).  I know my test is a little above the standard, but I'd really not like to compromise, as I do expect large amounts of code to be entered into it.  I am a bit of a performance freak, and it bugs me to see the rest of my program so heavily optimized but slowed down by this one huge bottleneck... Anyway, here it is:

{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Courier New;}}
{\colortbl ;\red0\green0\blue128;\red0\green128\blue0;\red128\green0\blue0;\red255\green0\blue0;}
\viewkind4\uc1\pard\cf0\lang1033\f0\fs20
\cf1 For\cf0  x = 2 + 1 \cf1 To\cf0  Len(\cf3 "Testing"\cf0 ) - 1 ^ 2 \cf1 Mod\cf0  1 + 2\cf2  'Comment\cf0
\par \cf1 For\cf0  x = 2 + 1 \cf1 To\cf0  Len(\cf3 "Testing"\cf0 ) - 1 ^ 2 \cf1 Mod\cf0  1 + 2\cf2  'Comment\cf0
\par \cf1 For\cf0  x = 2 + 1 \cf1 To\cf0  Len(\cf3 "Testing"\cf0 ) - 1 ^ 2 \cf1 Mod\cf0  1 + 2\cf2  'Comment\cf0
\par \cf1 For\cf0  x = 2 + 1 \cf1 To\cf0  Len(\cf3 "Testing"\cf0 ) - 1 ^ 2 \cf1 Mod\cf0  1 + 2\cf2  'Comment\cf0
....5000 of these....
\par \cf1 For\cf0  x = 2 + 1 \cf1 To\cf0  Len(\cf3 "Testing"\cf0 ) - 1 ^ 2 \cf1 Mod\cf0  1 + 2\cf2  'Comment\cf0
\par \cf1 For\cf0  x = 2 + 1 \cf1 To\cf0  Len(\cf3 "Testing"\cf0 ) - 1 ^ 2 \cf1 Mod\cf0  1 + 2\cf2  'Comment\cf0
}
0
 
LVL 15

Expert Comment

by:ameba
ID: 11786283
If you are opening file, you'll use .TextRTF not .SelRtf; you shouldn't use multiple .SelRtf calls to insert multiple lines.
Any insertion will be followed by:
- internal optimization/reduction of rtf code - to avoid this, plan everything, no duplicate colors etc.
- formatting - it depends on right margin property and length (line length) of inserted text.  Make sure there is no wrapping (like in VB code editor).
0
 
LVL 15

Expert Comment

by:ameba
ID: 11786482
To check if there was some internal optimization check rtf code after the insertion - if cf5 is cf4, control did something.
Maybe you have code in SelChange or Change event which is executed during insertion. Use flags to exit those events:
    ' set flags
    bIgnoreInChange = True
    bIgnoreInSelChange = True
    resetundo
   
    rtbText.TextRTF = S2RTF(x, True)
   
    ' reset flags
    bIgnoreInChange = False
    bIgnoreInSelChange = False
0
 

Author Comment

by:MasamuneXGP
ID: 11786514
As you can see from my last post, I am indeed inserting them all in one fell swoop and with the best color optimization.  And I have the RightMargin prop set to the max possible value, so word wrapping isn't an issue either.
0
 
LVL 15

Expert Comment

by:ameba
ID: 11786649
Try TextRtf it should be faster than SelRtf.
0
 

Author Comment

by:MasamuneXGP
ID: 11787343
Alrighty, upon analyzing the RTF code output, it appears that my color tags are indeed being reordered.  After much tweaking, I finally got the expression (RTFBuild = .TextRTF) to equal True.  The end result: it saved me about 2.5 seconds.  So now we're down to around 16 seconds instead of 19.  Yay~~ =p

That event locking thing I am already doing, and I am using LockWindowUpdate to prevent it to refreshing as well.  Experimenting shows .TextRTF to be no faster than .SelRTF.  Since it appears this question isn't as easy to answer as I was hoping it would be, this is now 500 point question.
0
 
LVL 15

Expert Comment

by:ameba
ID: 11788783
' Form1, add MS RichTextbox, do not change any property
Option Explicit
Private Declare Function GetTickCount Lib "kernel32" () As Long

Private Sub Form_Click()
    Dim hdr As String, sLines() As String, tail As String, i As Long, tim0 As Long
   
    ' start timer
    tim0 = GetTickCount
   
    hdr = "{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Courier New;}}" & vbCrLf _
        & "{\colortbl ;\red0\green0\blue128;\red0\green128\blue0;\red128\green0\blue0;\red255\green0\blue0;}" & vbCrLf _
        & "\viewkind4\uc1\pard\cf0\lang1033\f0\fs20" & vbCrLf
    tail = "}"
   
    ' fill array of lines
    ReDim sLines(0 To 5000)
    For i = 0 To UBound(sLines)
        sLines(i) = "\cf1 For\cf0  x = 2 + 1 \cf1 To\cf0  Len(\cf3 ""Testing""\cf0 ) - 1 ^ 2 \cf1 Mod\cf0  1 + 2\cf2  'Comment\cf0"
    Next
   
    Me.RichTextBox1.RightMargin = 60000
    Me.RichTextBox1.TextRTF = hdr & Join(sLines, vbCrLf & "\par ") & tail
   
    ' show time
    Caption = (GetTickCount - tim0) / 1000 & " seconds, length=" & Len(Me.RichTextBox1.Text)
End Sub
0
 

Author Comment

by:MasamuneXGP
ID: 11790617
I started a new project, added an RTB, copied and pasted this exact code, compiled, ran, clicked the form.  After finishing, the titlebar read "17.172 seconds, length=300058"

Have you tried this code on your own system?  If so what processer speed do you have?
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 15

Expert Comment

by:ameba
ID: 11790863
0.484 seconds on old 666 MHz Celeron, MS Rich Textbox 6.0 (SP4). If I increase window size, or change some properties I can make it 2-3 times slower.  I'll put a temporary zip with .exe http://www.geocities.com/ameba_vb/temp/rtftest/rtftest.html
0
 
LVL 15

Expert Comment

by:ameba
ID: 11790949
Maybe you can try different header:
    hdr = "{\rtf1\ansi\deff0\deftab480{\fonttbl{\f0\fnil MS Sans Serif;}{\f1\fswiss\fcharset238 Fixedsys;}}" & _
        "{\colortbl\red0\green0\blue0;\red192\green192\blue192;\red0\green143\blue0;\red255\green0\blue0;\red0\green0\blue127;\red170\green0\blue0;}" & vbCrLf _
        & "\deflang1050\pard\plain\f1\fs18 "
0
 

Author Comment

by:MasamuneXGP
ID: 11790996
It takes 17 seconds on my P4 1.7GHz machine, 11 seconds on my P4 2.4GHz machine, and 48 seconds on my PIII 650MHz laptop.

Seeing as I am also using MS Rich Textbox 6.0 (SP4), I guess it must be something to do with file versions....  Would you mind sending me whatever copy of RichTx32.ocx and RichEd20.dll you have on that 666 Mhz machine?
0
 

Author Comment

by:MasamuneXGP
ID: 11791008
Tried the new header.  Font was different, time was the same =\
0
 
LVL 15

Accepted Solution

by:
ameba earned 500 total points
ID: 11791142
I have updated the page - there is a setup file, it will install RichEd20.dll to installation directory.
Please do not replace dll in your system32 directory - each OS has different version installed, you shouldn't change that.
Ocx will be installed to system32, it isn't OS dependant, but it seems you have the correct version.
0
 
LVL 15

Expert Comment

by:ameba
ID: 11791207
You can find info on versions installed (to system32 directory) at http://support.microsoft.com/default.aspx?scid=/servicedesks/fileversion/dllinfo.asp&SD=MSDN&FR=0
type dll name: RichEd20.dll
0
 

Author Comment

by:MasamuneXGP
ID: 11791241
*GASP* It worked!  It was indeed RichEd20.dll that was slowing it down.  The confusing part is... the RichEd20.dll in my sys32 folder is actually a newer version than the one you sent me... but who cares, I'm just happy it finally works!  One last question though: I'm going to be distributing this program.  Should I just have the installer place this copy of RichEd20.dll in the installation folder?  Or does it have to be regsvr32'd or something?
0
 
LVL 15

Expert Comment

by:ameba
ID: 11791281
I suggest placing to installation directory - that's what installer does.
If you replaced newer version with older one in your System dir, that might not be good idea.  Maybe MS has the reason, e.g. it is more secure, or something.
If you are sure your dll was debug version for some beta product, I guess manually removing it and replacing/registering is OK.
0
 

Author Comment

by:MasamuneXGP
ID: 11791320
Thank you very much for your help ameba!  Enjoy your 500 points =)
0
 
LVL 15

Expert Comment

by:ameba
ID: 11791326
Thanks :-)
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
LINQ return type for nested group query 6 74
DO Loop not working 4 72
ms access #TYPE! error on report when no data 4 68
vbModal 12 38
Most everyone who has done any programming in VB6 knows that you can do something in code like Debug.Print MyVar and that when the program runs from the IDE, the value of MyVar will be displayed in the Immediate Window. Less well known is Debug.Asse…
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

863 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

21 Experts available now in Live!

Get 1:1 Help Now