Using Rich Edit Controls

The following topics are discussed in this section.

Creating a Rich Edit Control

To create a rich edit control, call the CreateWindowEx function, specifying the rich edit window class. If you are using Microsoft Rich Edit 1.0 (Riched32.dll), specify RichEdit for the window class parameter. If you are using Rich Edit 2.0 or later (Riched20.dll or Msftedit.dll), specify RICHEDIT_CLASS for the window class parameter. For more information, see Versions of Rich Edit.

Rich edit controls support most of the window styles used with edit controls as well as additional styles. You should specify the ES_MULTILINE window style if you want to allow more than one line of text in the control. For more information, see Rich Edit Control Styles.

Note   To use visual styles with these controls, an application must include a manifest and must call InitCommonControls at the beginning of the program. For information on visual styles, see Visual Styles. For information on manifests, see Enabling Visual Styles.

The following example function creates a rich edit control and initializes it with some text.

HWND CreateRichEdit(
    HWND hwndOwner,        // Dialog box handle.
    int x, int y,          // Location.
    int width, int height, // Dimensions.
    HINSTANCE hinst)       // Application or DLL instance.
{
    LoadLibrary(TEXT("Msftedit.dll"));
    HWND hwndEdit= CreateWindowEx(0, RICHEDIT_CLASS, TEXT("Type here"),
        ES_MULTILINE | WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP, 
        x, y, width, height, 
        hwndOwner, NULL, hinst, NULL);
    return hwndEdit;
}

In Microsoft Visual Studio 2005 and later, it is possible to add a rich edit control into a dialog template by dragging the control from the toolbox. However, doing this in the dialog editor does not ensure that the required library will be loaded before the control is created. It is necessary to call the LoadLibrary function to load Riched32.dll, Riched20.dll, or Msftedit.dll before the dialog is created.

Text Formatting

An application can send messages to a rich edit control to format characters and paragraphs to retrieve formatting information. Paragraph formatting attributes include alignment, tabs, indents, numbering, and simple tables. For characters, you can specify font name, size, color, and effects such as bold, italic, and protected.

You can apply paragraph formatting by using the EM_SETPARAFORMAT message. To determine the current paragraph formatting for the selected text, use the EM_GETPARAFORMAT message. The PARAFORMAT or PARAFORMAT2 structure is used with both messages to specify paragraph formatting attributes.

You can apply character formatting by using the EM_SETCHARFORMAT message. To determine the current character formatting for the selected text, you can use the EM_GETCHARFORMAT message. The CHARFORMAT or CHARFORMAT2 structure is used with both messages to specify character attributes.

You can also use EM_SETCHARFORMAT and EM_GETCHARFORMAT messages to set and retrieve the character formatting of the insertion point, which is the formatting applied to any subsequently inserted characters. For example, if an application sets the default character formatting to bold and the user then types a character, that character is bold.

The character formatting of the insertion point is applied to newly inserted text only if the current selection is empty (if the current selection is an insertion point). Otherwise, the new text assumes the character formatting of the text it replaces. If the selection changes, the default character formatting changes to match the first character in the new selection.

The protected character effect is unique in that it does not change the appearance of text. If the user attempts to modify protected text, a rich edit control sends its parent window an EN_PROTECTED notification message, allowing the parent window to allow or prevent the change. To receive this notification message, you must enable it by using the EM_SETEVENTMASK message.

Foreground color is always a character attribute. In Rich Edit 1.0, background color is only a property of the rich edit control. To set the default background color, use the EM_SETBKGNDCOLOR message. Note, Rich Edit does not support the WM_CTLCOLOREDIT message.

Current Selection in a Rich Edit Control

The user can select text in a rich edit control by using the mouse or the keyboard. The current selection is the range of selected characters, or the position of the insertion point if no characters are selected. An application can get information about the current selection, set it, determine when it changes, and show or hide the selection highlight.

To determine the current selection in a rich edit control, use the EM_EXGETSEL message. To set the current selection, use the EM_EXSETSEL message. The CHARRANGE structure is used with both messages and specifies a range of characters. To retrieve information about the contents of the current selection, you can use the EM_SELECTIONTYPE message.

An application can detect when the current selection changes by processing the EN_SELCHANGE notification message. The notification message specifies a SELCHANGE structure containing information about the new selection. A rich edit control sends this notification message only if you enable it by using the EM_SETEVENTMASK message.

By default, a rich edit control shows and hides the selection highlight when it gains and loses the focus. You can show or hide the selection highlight at any time by using the EM_HIDESELECTION message. For example, an application might provide a Search dialog box to find text in a rich edit control. The application might select matching text without closing the dialog box, in which case it must use the EM_HIDESELECTION message to highlight the selection.

As with edit controls, you can specify the ES_NOHIDESEL window style to prevent a rich edit control from hiding the selection highlight when it loses the focus.

As an alternative to using the EM_EXGETSEL and EM_EXSETSEL messages, you can retrieve and set the current selection by using the EM_GETSEL and EM_SETSEL edit control messages. The EM_GETSEL message packs two 16-bit character indexes into its 32-bit return value and therefore, works only for selections that fall entirely within the first 64K. However, a rich edit control will never contain more than 32K characters of text, unless you extend this limit by using the EM_LIMITTEXT or EM_EXLIMITTEXT message. For selections that extend beyond the first 64KB of text, the EM_GETSEL message returns – 1. In such a case you can still use the values returned in wParam and lParam to find the start and end characters of the selection.

Rich Edit Text Operations

An application can send messages to retrieve or find text in a rich edit control. You can retrieve either the selected text or a specified range of text.

To get the selected text in a rich edit control, use the EM_GETSELTEXT message. The text is copied to the specified character array. You must ensure that the array is large enough to hold the selected text plus a terminating null character.

To retrieve a specified range of text, use the EM_GETTEXTRANGE message. The TEXTRANGE structure used with this message specifies the text range to retrieve and points to a character array that receives the text. Here again, the application must ensure that the array is large enough for the specified text plus a terminating null character.

You can search for a string in a rich edit control by using the EM_FINDTEXT or EM_FINDTEXTEX messages, or their Unicode equivalents, EM_FINDTEXTW and EM_FINDTEXTEXW. The FINDTEXT structure used with the nonextended versions specifies the text range to search and the string to search for. The extended versions use a FINDTEXTEX structure, which specifies the same information and also receives the start and end points of the character range of the found text. You can also specify such options as whether the search is case sensitive.

The following example function finds the specified text within the selected text in a rich edit control that supports Unicode. If the target is found, it becomes the new selection.

BOOL FindTextInSelection(HWND hRich, WCHAR* target)
{
    CHARRANGE selectionRange;
    SendMessage(hRich, EM_EXGETSEL, 0, (LPARAM)&selectionRange);
    FINDTEXTEX ftex;
    ftex.lpstrText = target;
    ftex.chrg.cpMin = selectionRange.cpMin;
    ftex.chrg.cpMax = selectionRange.cpMax;
    LRESULT lr = SendMessage(hRich, EM_FINDTEXTEXW, (WPARAM)FR_DOWN, (LPARAM) &ftex);
    if (lr >= 0)
    {
        LRESULT lr1 = SendMessage(hRich, EM_EXSETSEL, 0, (LPARAM)&ftex.chrgText);
        SendMessage(hRich, EM_HIDESELECTION, (LPARAM)FALSE, 0);
        return TRUE;
    }
    return FALSE;
}

Rich Edit 3.0 also supports the HexToUnicode Input Method Editor (IME), which allows a user to convert between hexadecimal and Unicode by using hot keys. For more information, see HexToUnicode.

Word and Line Breaks

A rich edit control calls a function called a word-break procedure to find breaks between words and to determine where it can break lines. The control uses this information when performing word-wrap operations and when processing CTRL+LEFT ARROW key and CTRL+RIGHT ARROW key combinations. An application can send messages to a rich edit control to replace the default word-break procedure, to retrieve word-break information, and to determine what line a given character falls on.

Word-break procedures for rich edit controls are similar to those for edit controls, but they have additional capabilities: word-break procedures for both kinds of controls can determine whether a character is a delimiter and can find the nearest word break before or after the specified position. A delimiter is a character that marks the end of a word, such as a space. Usually, in an edit control, a word break occurs only after delimiters. However, different rules apply to most Asian languages.

Word-break procedures for rich edit controls also group characters into character classes, each identified by a value in the range 0x00 through 0x0F. Breaks occur either after delimiters or between characters of different classes. Thus, a word-break procedure with different classes for alphanumeric and punctuation characters would find two word breaks in the string "Win.doc" (before and after the period).

A character's class can be combined with zero or more word-break flags to form an 8-bit value. When performing word-wrap operations, a rich edit control uses word-break flags to determine where it can break lines. Rich Edit uses the following word-break flags.

FlagsDescription
WBF_BREAKAFTERLines may be broken after the character.
WBF_BREAKLINEThe character is a delimiter. Delimiters mark the ends of words. Lines may be broken after delimiters.
WBF_ISWHITEThe character is a white-space character. Trailing white-space characters are not included in the length of a line when wrapping.

The WBF_BREAKAFTER value is used to allow wrapping after a character that does not mark the end of a word, such as a hyphen.

You can replace the default word-break procedure for a rich edit control, with your own procedure by using the EM_SETWORDBREAKPROC message. For more information about word-break procedures, see the description of the EditWordBreakProc function.

Note  This replacement is not recommended for Rich Edit control 2.0 and later, due to the complexity of multilingual word breaking.

For Rich Edit 1.0, you can use the EM_SETWORDBREAKPROCEX message to replace the default extended word-break procedure with an EditWordBreakProcEx function. This function provides additional information about the text, such as the character set. You can use the EM_GETWORDBREAKPROCEX message to retrieve the address of the current extended word-break procedure. Note that Rich Edit 2.0 and later do not support EditWordBreakProcEx, EM_GETWORDBREAKPROCEX, and EM_SETWORDBREAKPROCEX.

You can use the EM_FINDWORDBREAK message to find word breaks or to determine a character's class and word-break flags. In turn, the control calls its word-break procedure to get the requested information.

To determine which line a given character falls on, you can use the EM_EXLINEFROMCHAR message.

Rich Edit Clipboard Operations

An application can paste the contents of the clipboard into a rich edit control using either the best available clipboard format or a specific clipboard format. You can also determine whether a rich edit control is capable of pasting a clipboard format.

As with an edit control, you can copy or cut the contents of the current selection by using the WM_COPY or WM_CUT message. Similarly, you can paste the contents of the clipboard into a rich edit control by using the WM_PASTE message. The control pastes the first available format that it recognizes, which presumably is the most descriptive format.

To paste a specific clipboard format, you can use the EM_PASTESPECIAL message. This message is useful for applications with a Paste Special command that enables the user to select the clipboard format. You can use the EM_CANPASTE message to determine whether a given format is recognized by the control.

You can also use the EM_CANPASTE message to determine whether any available clipboard format is recognized by a rich edit control. This message is useful when processing the WM_INITMENUPOPUP message. An application might enable or gray its Paste command depending on whether the control can paste any available format.

Rich edit controls register two clipboard formats:

  • Rich Text Format (RTF)
  • RichEdit Text and Objects

An application can register these formats by using the RegisterClipboardFormat function, specifying the CF_RTF and CF_RETEXTOBJ values.

Streams

You can use streams to transfer data into or out of a rich edit control. A stream is defined by an EDITSTREAM structure, which specifies a buffer and an application defined–callback function.

To read data into a rich edit control (that is, stream in the data), use the EM_STREAMIN message. The control repeatedly calls the application's callback function, which transfers a portion of the data into the buffer each time.

To save the contents of a rich edit control (that is, stream out the data), you can use the EM_STREAMOUT message. The control repeatedly writes to the buffer and then calls the application's callback function. For each call, the callback function saves the contents of the buffer.

The following code example shows how to read an .rtf file into a rich edit control. The file handle is passed to the callback function through the dwCookie member of the EDITSTREAM structure.

DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE lpBuff,
                                  LONG cb, PLONG pcb)
{
    HANDLE hFile = (HANDLE)dwCookie;
    if (ReadFile(hFile, lpBuff, cb, (DWORD *)pcb, NULL)) 
    {
        return 0;
    }
    return -1;
}

BOOL FillRichEditFromFile(HWND hwnd, LPCTSTR pszFile)
{
    BOOL fSuccess = FALSE;
    HANDLE hFile = CreateFile(pszFile, GENERIC_READ, 
        FILE_SHARE_READ, 0, OPEN_EXISTING,
        FILE_FLAG_SEQUENTIAL_SCAN, NULL);
    if (hFile != INVALID_HANDLE_VALUE) 
    {
        EDITSTREAM es = { 0 };
        es.pfnCallback = EditStreamCallback;
        es.dwCookie = (DWORD_PTR)hFile;
        if (SendMessage(hwnd, EM_STREAMIN, SF_RTF, (LPARAM)&es) 
            && es.dwError == 0) 
        {
                fSuccess = TRUE;
        }
        CloseHandle(hFile);
    }
    return fSuccess;
}

Bottomless Rich Edit Controls

An application can resize a rich edit control as needed so that it is always the same size as its contents. A rich edit control supports this so-called bottomless functionality by sending its parent window an EN_REQUESTRESIZE notification message whenever the size of its content changes.

When processing the EN_REQUESTRESIZE notification message, an application should resize the control to the dimensions in the specified REQRESIZE structure. An application might also move any information near the control to accommodate the control's change in height. To resize the control, you can use the SetWindowPos function.

You can force a bottomless rich edit control to send an EN_REQUESTRESIZE notification message by using the EM_REQUESTRESIZE message. This message can be useful when processing the WM_SIZE message.

To receive EN_REQUESTRESIZE notification messages, you must enable the notification by using the EM_SETEVENTMASK message.

Miscellaneous Notification Messages

A rich edit control's parent window can process notification messages to monitor events affecting the control. Rich edit controls support all of the notification messages used with edit controls as well as several additional ones. You can determine which notification messages a rich edit control sends its parent window by setting its event mask.

To set the event mask for a rich edit control, use the EM_SETEVENTMASK message. You can retrieve the current event mask for a rich edit control by using the EM_GETEVENTMASK message. For a list of event mask flags, see Rich Edit Control Event Mask Flags.

A rich edit control's parent window can filter all keyboard and mouse input to the control by processing the EN_MSGFILTER notification message. The parent window can prevent the keyboard or mouse message from being processed or can change the message by modifying the specified MSGFILTER structure.

An application can process the EN_PROTECTED notification message to detect when the user attempts to modify protected text. To mark a range of text as protected, you can set the protected character effect. For more information, see Text Formatting.

You can enable the user to drop files in a rich edit control by processing the EN_DROPFILES notification message. The specified ENDROPFILES structure contains information about the files being dropped.

Font Binding

Rich Edit 3.0 will assign a character set to plain-text characters depending on their context. Some examples are:

  • Hangul symbols get HANGUL_CHARSET
  • Non-neutral ANSI characters get ANSI_CHARSET in any event
  • Chinese characters get SHIFTJIS_CHARSET if kana characters are found nearby or GB2312_CHARSET if no kana are found nearby.
  • Greek characters get GREEK_CHARSET
Note  The Rich Edit control uses Unicode internally, so this use of character sets differs from the original one used in font specifications. But CHARFORMAT has a well-defined place for the character set.

Neutral characters like blanks and digits are assigned a character set depending on their context. For example, a blank surrounded by characters of the same character set gets that character set. Neutrals and digits used for bidirectional text are assigned character sets in a way based on the Unicode bidirectional algorithm.

After character sets are assigned, Rich Edit scans the text around the insertion point forward and backward to find the nearest fonts that have been used for the character sets. If no font is found for a character set, rich edit uses the font chosen by the client for that character set. If the client hasn't specified a font for the character set, rich edit uses the default font for that character set. If the client wants some other font, the client can always change it, but this approach will work most of the time. The current default font choices are based on the following table. Note that the default fonts are set per-process, and there are separate lists for user interface (UI) usage and for non-UI usage.

LanguageUI font nameUI font sizenon-UI font namenon-UI font size
Western, CE, ME, VietnameseTahoma8Arial10
JapaneseMS UI Gothic9MS P Gothic10
KoreanGulim9Gulim9
Simplified ChineseSimsun9SimSun10
Traditional ChinesePMingLiU9PMingLiU9
ThaiMS Sans Serif8Tahoma14
SymbolsWingdings8Wingdings10
DevanagariMangal8Mangal10
TamilLatha8Latha10
Georgian, ArmenianArial Unicode8Arial Unicode10

Therefore, in the default font-binding table (entries have a character set, font name, and size), Rich Edit allows ANSI_CHARSET to match several character sets, while the appropriate character set matches other fonts on a one-to-one basis. More precisely, rich edit uses the ANSI_CHARSET choice whenever no other alternative is found. You will be able to specify a finer granularity than this, for example: assign a specific ARABIC_CHARSET for Arabic runs, a specific Greek font for Greek runs, for example. This finer granularity will also be used if a font with the desired character set stamp is found somewhere in the document before the area being font-bound.

Note that Rich Edit does not currently handle a missing glyph in a font that claims to support a character set but is incomplete. At display time in a complex script, Rich Edit does end up knowing that such a glyph is missing, but it does not cause the backing store to use a new font. Normally, the underlying font linking of the OS will accomplish this.

Rich Edit 4.1: To set the default font for a script, call EM_SETCHARFORMAT with CHARFORMAT2, specifying yHeight, bCharSet, bPitchAndFamily, szFaceName, and lcid. Also, to get the default font for a specific code page, call EM_GETCHARFORMAT with CHARFORMAT2 specifying bCharSet and lcid.

Tags :


Community Content

Peter Donnelly - MSFT UE
How to instantiate Rich Edit 4.1 controls using MSFTEDIT_CLASS

As of March 2, 2008, the above documentation does not explain properly how to instantiate a Rich Edit 4.1 class using MSFTEDIT_CLASS. It only mentions using RICHEDIT_CLASS which only works for Rich Edit controls 3.0 and below. If you want your Rich Edit control to support fully the new Text Services Framework (input from speech recognition, etc.) you'll need to use a Rich Edit 4.1 control. Looking inside Richedit.h in the Platform SDK, one finds the following little tidbit:

#define MSFTEDIT_CLASS  L"RICHEDIT50W"
// NOTE: MSFTEDIT.DLL only registers MSFTEDIT_CLASS. If an application wants
// to use the following Richedit classes, it needs to load the riched20.dll.
// Otherwise, CreateWindow with RICHEDIT_CLASS would fail.
// This also applies to any dialog that uses RICHEDIT_CLASS, [sic]


Some code to illustrate creating a rich edit control depending on what is available (not intended for production use):

#include <Richedit.h>  // #defines MSFTEDIT_CLASS and RICHEDIT_CLASS
  
HWND CreateRichEditControl() {
  static HMODULE msft_mod = LoadLibrary("Msftedit.dll");
  if (msft_mod) {
    // Create a Rich Edit 4.1 control (requires Windows XP SP1 or later)
    return CreateWindowEx(exstyle, MSFTEDIT_CLASS, ...);
  }
  static HMODULE riched_mod = LoadLibrary("Riched20.dll");
  if (riched_mod) {
// Create a Rich Edit 2.0 (98/NT4) or 3.0 (Me/2K/XP) control.
    return CreateWindowEx(exstyle, RICHEDIT_CLASS, ...);
}
  // No suitable DLL found... time to upgrade Windows.
  return NULL;
}


The Platform SDK documentation doesn't seem to make any mention of MSFTEDIT_CLASS; the only place I found it mentioned on MSDN was this TSF blog post:

http://blogs.msdn.com/tsfaware/archive/2007/06/14/how-do-i-use-richedit-4-1.aspx

[ Good feedback, thanks. We'll add this info in the next update to "About Rich Edit Controls." -- Peter Donnelly MSFT ]


Page view tracker