Solved

RichEd20 Problem: RTF Text insertion too slow

Posted on 2004-08-12
20
611 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
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
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

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

I’ve seen a number of people looking for examples of how to access web services from VB6.  I’ve been using a test harness I built in VB6 (using many resources I found online) that I use for small projects to work out how to communicate with web serv…
Enums (shorthand for ‘enumerations’) are not often used by programmers but they can be quite valuable when they are.  What are they? An Enum is just a type of variable like a string or an Integer, but in this case one that you create that contains…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…

760 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