News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

RichEd20.DLL bugs

Started by jj2007, September 24, 2017, 08:14:04 PM

Previous topic - Next topic

jj2007

Searching the forum, I just realised that we do not yet have a dedicated thread on bugs in Microsoft's RichEdit control. So I hope we can collect observations here, and I kindly ask you for real contributions, not philosophical observations.

If you have a bug to report, please modify the title of the post, and try to be very brief and to the point.

jj2007

Let's start with a really exotic bug: The way the RichEdit control stores tables. I stumbled over this one when trying to create a "serial letter" application. It uses a template wirh tags:
This file was created on #date#
#column1# #column2# #column3#
#value11# #value12# #value13#
#value21# #value22# #value23#


In the RTF file (attached), it is a nice table. You can read the whole file into a string, replace the tags with appropriate values, save the result, and voilà, there is a RTF file ready for printing. Code:

include \masm32\MasmBasic\MasmBasic.inc         ; download
  Init
  Let esi=FileRead$("TemplateHashes.rtf")       ; read a template into a buffer
  Let esi=Replace$(esi, "#date#", Date$)        ; replace tags
  Let esi=Replace$(esi, "#column1#", "First column")
  Let esi=Replace$(esi, "#column2#", "Second column")
  Let esi=Replace$(esi, "#column3#", "Third column")
  FileWrite "LetterHashes.rtf", esi             ; save result
  ShEx "LetterHashes.rtf"                       ; and open it in the default editor
EndOfCode


The line "This file was created on #date#" works fine. Always.

The table works fine if your template was saved with certain versions of RichEd20.dll, but it fails miserably if the template was saved with others :(

System32 ; OK (but C:\Windows\System32\RichEd20.dll is utterly slow and lacks many features)
Office15 ; OK (but has some other bugs)
Office14 ; bad
Office12 ; bad
Office11 ; OK


Why this?

A line of a table gets typically saved as follows:\pard\intbl\nowidctlpar\cf2\i0 #column1#\cell #column2#\cell #column3#\cell\row\trowd\trgaph70\trleft-30\trpaddl70\trpaddr70\trpaddfl3\trpaddfr3

The interesting part is\cell #column2#\cell #column3#
After the replacing of tags, it becomes
\cell Second column\cell Third column

Perfect :t

But it fails with the Office12 and Office14 versions of RichEd20.dll because these DLLs save the template as follows:[code]\cell#column2#\cell#column3#

No blank after the RTF tag! It's probably a feature 8), and it will hit you as a bug only in very exotic situations like the one outlined above: words starting with # in cells of a table. Same for words starting with $, btw, and maybe others.

Workaround: Use + instead of # or $.

Here is a list of tested delimiters. OK means even the buggy DLLs insert a space after the rtf tag, bad means they don't.

OK   +/-:@[^?
bad   $\#§*"'&|

jj2007

Here is a little program that loads text and rtf files into a RichEdit control when you click into the listbox (source & exe attached; extract the exe to a folder that contains asm and/or rtf files):

GuiParas equ "Dynamic Layout Demo", y100, w900, h600, m5, bGrey        ; y at 100px, width 900px, h600px, margins 5px, grey background
GuiMenu equ @File, &Open, &Save, -, E&xit, @Whatever, Добро пожаловать, مرحبا بكم, Functions not implemented   ; creates a menu -> Event Menu
include \masm32\MasmBasic\Res\MbGui.asm
  GetFiles *.as?|*.rc|*.rtf     ; collect asm, asc & rc sources, plus rich text files
  SortFiles date       ; most recent first
  GuiControl MyList, "listbox", Files$(), x0+288, w1000-288, h0+100    ; right-aligned, height 100px
  GuiControl MyLink, "syslink", "Download the MasmBasic library", w0+200, y0+100, h0+20
  GuiGroup "Groupbox (functions not implemented):", w0+266, h0+75, bcol LiteYellow
    GuiControl StatFind, "static", "Find:",        h0+22, w0+50            ; general syntax:
    GuiControl StatRepl, "static", "Replace:",         h0+22, w0+50, y0+32             ; guicontrol ID, "class", args "text", x, y, w, h, style
    GuiControl EditFind, "edit", "Gui", x0+62, w0+100, h0+22   ; args have a variable part plus an optional fixed one, example:
    GuiControl EditRepl, "edit", x0+62, w0+100, h0+22, y 0+30  ; x1000-90 means "at right border, i.e. 100.0%, minus 90 pixels"
    GuiControl Cis, "button", BS_AUTOCHECKBOX, h0+22, x0+170, w0+60, "Case"    ; args may appear in no particular order, e.g. "Case" at the end
    GuiControl Fw, "button", "Full word", h0+22, x0+170, w0+64, y0+28, BS_AUTOCHECKBOX
  GuiGroup end
  GuiControl BigEdit, "RichEdit", y0+120, h1000-120, bcol RgbCol(222, 255, 255), font -14
  GuiControl MySBar, "statusbar", "Добро пожаловать", parts=290/160      ; all GuiControls understand Unicode
  SetStatus$ ComCtl32$("Common controls version %3f"), 1                ; test if the manifest works
  SetStatus$ RichEditUsed, 2
Event Menu
  SetWin$ hMySBar=Str$("You clicked menu #%i", MenuID)
Event Notify
  If_ word ptr wParam_==MyLink && NotifyCode==NM_CLICK Then <ShEx "http://masm32.com/board/index.php?topic=94.0">
Event Command
  If_ word ptr wParam_==MyList && LbSel>=0 Then <SetWin$ hBigEdit=FileRead$(LbSel$)>
GuiEnd


It works fine but I noticed that some bigger files loaded extremely slowly. It took me a while to chase down the culprit, it's actually the EM_STREAMIN message. If the control has already content, it may take ages to replace that content with new one. With "ages" I mean 8 seconds and more for a file that normally loads in 100 milliseconds. Yes, it's a bug, and it is present in all versions tested.

Thanks to well over 10 years of experience with RichEdit bugs, I found a workaround (and it will be added to MasmBasic's SetWin$="..." today): clear the control before streaming in new text, and all is good  :cool:

jj2007

One more for the record: EM_GETTEXTLENGTHEX fails completely but not predictably if the control is in another process. In contrast, WM_GETTEXTLENGTH works fine, and has a non-documented feature: There is no 64kB limit for this message.

jj2007


jj2007

Normally, an invoke SendMessageW, hRichEdit, EM_FINDTEXTW, wParam, lParam works fine and is not even slow. But every now and then, once in a while, and impossible to reproduce in a stable way, the message takes 5 seconds instead of 50 milliseconds when parsing a 500kB source - roughly a factor 100 slower!

I noticed this weird behaviour with RichMasm's find listbox, and it drove me nutz. The relevant proc is pretty big, but I nailed the problem down to EM_FINDTEXTW and wrote a workaround [EM_GETTEXTEX plus Instr_(FAST, src, match)], which is now stable, a lot faster and implemented for RichMasm in the MasmBasic package of 15 September 2020.

jj2007

The way Micros**t treats people who inform them about problems with their software is remarkable - compliments, Redmond :thumbsup:

Anyway, here is a new bug: the line numbering feature is badly broken. Drag a RichEd20.dll over the attached exe, e.g.
- C:\Windows\System32\RichEd20.dll (this is the default if you start the exe without dragging a DLL over it)
- C:\Program Files (x86)\Common Files\microsoft shared\OFFICE11\RICHED20.DLL (simply the best...)
- C:\Program Files (x86)\Common Files\microsoft shared\OFFICE12\RICHED20.DLL (doesn't work)
- C:\Program Files (x86)\Common Files\microsoft shared\OFFICE14\RICHED20.DLL (see yourself...)

  SetGlobals fmt:PARAFORMAT2
  invoke SendMessage, hMyEdit, EM_SETTEXTMODE, TM_RICHTEXT or TM_MULTILEVELUNDO or TM_MULTICODEPAGE, 0
  m2m fmt.cbSize, PARAFORMAT2
  m2m fmt.dwMask, PFM_NUMBERING Or PFM_NUMBERINGSTART Or PFM_NUMBERINGSTYLE Or PFM_NUMBERINGTAB
  m2m fmt.wNumbering, 2
  m2m fmt.wNumberingStart, 1
  m2m fmt.wNumberingStyle, PFNS_PLAIN
  invoke SendMessage, hMyEdit, EM_SETPARAFORMAT, 0, addr fmt


P.S.: Peculiar behaviour of RichEdit when text begins with a table by Tomas Rylek

jj2007


jj2007


jj2007

line1
line2
line3

line4
line5
line6


When selecting line2 and pressing Ctrl 2, you get double line spacing, i.e. a space before the line.
When selecting line5 and going for PFM_SPACEBEFORE, you get the same effect, i.e. a space before the line.

In rtf codes, this translates like this:

\par
line1\par
\pard\sl480\slmult1\ line2\par
\pard\sl240\slmult1\ line3\par
\par
\par
line4\par
\pard\sb160\sl240\slmult1\ line5\par
\pard\sl240\slmult1\ line6\par
\par
\par


Now the issue is here that RichEdit50W (msftedit.dll) and RichEdit60W (Office RichEd20.dll) behave differently:
The C:\Windows\System32\msftedit.dll version inserts the space after the line,
while the MS Office versions inserts a space before the line

In practice, this leads to very ugly effects. If you had nicely formatted a document with 60W, with titles in double spacing, and you load that document into an editor with 50W, all your titles have the space afterwards but zero space before. In other words, it's a mess.

Fortunately, there is a relatively simple workaround for existing files:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Let esi=FileRead$(uCL$())
  .While 1
        .Break .if !Instr_(esi, "\slmult1\")
        mov byte ptr [eax+7], "0"
  .Endw
  FileWrite "~tmp.rtf", esi
  ShEx "~tmp.rtf"
EndOfCode


This snippet (source & exe attached - just drag your rtf file over the exe) translates slmult1 to slmult0. This rtf code produces the same behaviour in both RichEdit versions (see also TaW's answer here).

Greetings to Murray Sargent at Microsoft :biggrin: