RichEdit

The Windows supplied RichEdit component can be used to display formatted text, i.e. text where each character can be formatted independent of all the others.

As of 12-2003, I know of several versions of this control

Because Windows 2000 and Windows XP replace Riched32.dll with a wrapper to Riched20.dll, some applications (in particular, one that I wrote) will work perfectly on one operating system and fail on another. This behavior is known as DLL Hell.


Visual Basic 6.0

Basically, the RichEdit control is not documented. Only a small number of the ActiveX parameters and functions are available to the user unless you want to use Windows Messages.

The built-in help is completely worthless ... except for the sections on how to manipulate selected text.

Scrollbar control is very responsive.

There is no obvious way to disable word wrap!! (give me a break!)
It appears that the RightMargin property controls this. 0 (the default) forces word wrap. Since the value is in twips, use a large value (like 500000) to disable word wrap.
A related example from some c-code supplied with VB

  SendMessage(predoc->hwndRE, EM_SETTARGETDEVICE,
    (WPARAM) predoc->hdcTarget, (LPARAM) xWidth);

Parameters

Parameters and functions related to selecting text, modifying its font, and copying it to the clipboard seem to work ok. Use SelFontName, SelFontSize, and SelFontColor to Set Font Attributes

The help says to use SelFontColor in one section and SelColor in another section.


Related Windows Messages

In order to use these, you need to include the SendMessage function prototype and related constants in your program. Basically, this is
fairly simple, except that most of the documented capabilities don't work. In general, the Borland C++ RichText Control help is much better than the VB help because it actually explains things. However, the help on the constants is identical.

Search the help for EM_ (Windows messages) and ES_ (Edit Styles)

' Edit Control Messages - from WIN32API.TXT
Const EM_GETSEL              = &HB0
Const EM_SETSEL              = &HB1  ' Selects all text
Const EM_GETRECT             = &HB2
Const EM_SETRECT             = &HB3
Const EM_SETRECTNP           = &HB4
Const EM_SCROLL              = &HB5  ' Scrolls one page or one line up or down
Const EM_LINESCROLL          = &HB6  ' Goes to end of file only
Const EM_SCROLLCARET         = &HB7  ' Seems ok
Const EM_GETMODIFY           = &HB8
Const EM_SETMODIFY           = &HB9
Const EM_GETLINECOUNT        = &HBA  ' Works
Const EM_LINEINDEX           = &HBB
Const EM_SETHANDLE           = &HBC
Const EM_GETHANDLE           = &HBD  ' Fails - the Borland help explains why
Const EM_GETTHUMB            = &HBE  ' Fails
Const EM_LINELENGTH          = &HC1
Const EM_REPLACESEL          = &HC2
Const EM_GETLINE             = &HC4  ' 
Const EM_LIMITTEXT           = &HC5
Const EM_CANUNDO             = &HC6
Const EM_UNDO                = &HC7
Const EM_FMTLINES            = &HC8
Const EM_LINEFROMCHAR        = &HC9
Const EM_SETTABSTOPS         = &HCB
Const EM_SETPASSWORDCHAR     = &HCC
Const EM_EMPTYUNDOBUFFER     = &HCD
Const EM_GETFIRSTVISIBLELINE = &HCE  ' Works
Const EM_SETREADONLY         = &HCF
Const EM_SETWORDBREAKPROC    = &HD0
Const EM_GETWORDBREAKPROC    = &HD1
Const EM_GETPASSWORDCHAR     = &HD2
EM_GETTHUMB - to retrieve the position of the scroll box (thumb) - Fails
EM_SCROLL - to scroll the text vertically - up or down one page or line
EM_LINESCROLL - to scroll the text vertically or horizontally - Fails
The following always returns zero

The EM_SCROLL messages only uses 4 of the 17 ScrollBar constants
(yes, I tried all 8 unique codes).

Const SB_LINEUP   = 0  ' Scrolls  up  one line
Const SB_LINEDOWN = 1  ' Scrolls down one line
Const SB_PAGEUP   = 2  ' Scrolls  up  one page
Const SB_PAGEDOWN = 3  ' Scrolls down one page


Delphi

This Delphi 5 code fragment is from comctrls.pas

The LoadLibrary function explains why Depends does NOT list either Riched32.dll or Riched20.dll as one of the required modules.

Notice that this actually selects different controls depending on which operating system is used. Specifically,

This is one of the reasons why some programs that work perfectly under Windows 98 crash under Windows XP (and others).


Some Basic Examples

  UIRichEdit.SelAttributes.color := clGreen;
  UIRichEdit.WordWrap := false;
  BoldButton.Down := fsBold in RichEdit1.SelAttributes.Style;
    (in is not in the regular help index, search delphi.hlp 
      This example is from the SelAttributes example)
  Memo1.Font.Style := [fsBold]; // Style is a set
                                // The square bracket syntax is not explained
                                //  but it is required for sets
  RichEdit1.Perform(EM_SCROLLCARET, 0, 0); // Directly send a Windows message

   procedure TWinControl.DefaultHandler(var Message);
        Result := CallWindowProc(FDefWndProc, FHandle, Msg, WParam, LParam);


  property WordWrap: Boolean;
  procedure ScrollBy(DeltaX, DeltaY: Integer); // Values are in pixels
   // Set the selection to the beginning of a line
  with RichEdit1 do begin
    SelStart := perform(em_LineIndex, spinedit1.value, 0);


Paste From Clipboard

When you copy text to the clipboard, several different formats may be saved.

When you paste from the clipboard, TRichEdit decides which format to use and how to render it.

The default functionality can be observed by simply placing a TRichEdit component on a blank form and running the application.

Bold, underline, and hyperlinks are rendered - even if TRichEdit.PlainText = true (unfortunately, this property only affects streaming, not pasting).

I have one web page that actually displays html tags (which I use to copy and paste to pages I write using notepad). When these are pasted, the tags are interpreted (kind of defeats the purpose).

The problem is that I just want the clipboard pasted as text with bold, italic and other crap removed. (In this case, I am using TRichEdit as a replacement for TMemo which has a size limitation - ~32K)

While I was not able to find any obvious way to control this (the ability to set a preferred clipboard format would have been nice), I was able to develop a work around. Simply deriving a new component based on TRichEdit does not work because most of the functionality is based on RICHED32.DLL (that is why copy and paste work without adding any additional code.) Instead, I used 2 menu selections and the TEditPaste action to capture the Paste keystrokes and to paste the clipboard data as text.

The following code shows how the TEditPaste action normally works - WM_PASTE instructs the dll to do whatever it wants.

The solution is to

Normally, Actions are written to determine their targets at runtime. However, since that is not possible when code is attached to OnExecute, RichEdit1.Handle is used instead. If you need that functionality, then derive a new action from TEditPaste.

I tried several other approaches, but these did not work. For instance

Notes: When copying from notepad or a TMemo, the clipboard contained 3 formats (1, 16, 7). When pasting these, html code was not interpreted. When copying from Internet Explorer, the clipboard contained 8 formats (51906, 1, 13, 53478, 52434, 51949, 16, 7), 4 of them not defined. When pasting these, html code was interpreted.


Other

When you save to a file, and wordwrap is on, the new linebreaks are saved (have not "recently" verifed this)

****

Use this to search the text

From EM_FINDTEXTEX in the Windows SDK help

fuFlags

FT_MATCHCASE
FT_WHOLEWORD

FR_DOWN is new to version 2, It must be added for a version 2 search
        to be the same as a version 1 search

Microsoft SDK

****
Copying rtf text from one RichEdit control to another works fine in Windows 98, but causes a "resource error" in Windows XP because it converts the rtf codes and does not place them in the Text property. XP RichEdit Design Problem presents a solution using streams.

How to insert a Smiley image into a TRxRichEdit? shows how to do this with streams and a callback function.


Windows XP Problems

Windows XP is a complete disaster - the RichEdit control was rewritten.

This is unbelievable - I wrote a program using Delphi 5 that used the Microsoft RichEdit control (via TRichEdit).

These are the problems I currently know about. They are all related to the fact that the default changed from treating an rtf input as plain text to processing the tags and displaying formatted text.

One of the things that bothers me about this is that I was not able to find any information related to these problems by searching the internet.

This line of code works perfectly in Windows 98, but fails in Windows 2000 (and Windows XP).

It is executed in Controls.pas via Here is one way to work around the problem, this method converts the string to a stream and then loads the RichEdit control from the stream - when this is done the PlainText property controls the rtf conversion. Another option is to tell the RichEdit control not to interpret the text as rtf - this code should work with RichEdit v2 and is ignored by the old version. To use the constants, add richedit to your uses clause. Well, it doesn't exactly work - in Windows XP, it interprets the rtf codes and displays the formatted text ... except that the "hidden" text is not displayed and there is no documented method to display it. CFE_HIDDEN is defined in CHARFORMAT2 and implemeted in Rich Edit 3.0.

There is no difference using TM_PLAINTEXT or TM_RICHTEXT - though the help files say that there is supposed to be.

Do not confuse these


References


Author: Robert Clemenzi - clemenzi@cpcug.org
URL: http:// cpcug.org / user / clemenzi / technical / Languages / RichEdit.htm