[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 645
  • Last Modified:

RichEd20 Problem: RTF Text insertion too slow

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
MasamuneXGP
Asked:
MasamuneXGP
  • 11
  • 9
1 Solution
 
amebaCommented:
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
 
MasamuneXGPAuthor Commented:
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
 
MasamuneXGPAuthor Commented:
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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
amebaCommented:
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
 
amebaCommented:
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
 
MasamuneXGPAuthor Commented:
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
 
amebaCommented:
Try TextRtf it should be faster than SelRtf.
0
 
MasamuneXGPAuthor Commented:
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
 
amebaCommented:
' 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
 
MasamuneXGPAuthor Commented:
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
 
amebaCommented:
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
 
amebaCommented:
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
 
MasamuneXGPAuthor Commented:
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
 
MasamuneXGPAuthor Commented:
Tried the new header.  Font was different, time was the same =\
0
 
amebaCommented:
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
 
amebaCommented:
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
 
MasamuneXGPAuthor Commented:
*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
 
amebaCommented:
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
 
MasamuneXGPAuthor Commented:
Thank you very much for your help ameba!  Enjoy your 500 points =)
0
 
amebaCommented:
Thanks :-)
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 11
  • 9
Tackle projects and never again get stuck behind a technical roadblock.
Join Now