RichEdit Friendly Name Hyperlinks

This post is a companion to Automatic RichEdit Hyperlinks. As stated in that post, RichEdit has two kinds of hyperlinks, automatic hyperlinks (autoURLs) and friendly name hyperlinks. A friendly name hyperlink has a name, which is displayed, and a hidden instruction part that contains the actual URL. Such hyperlinks are commonly used when an author wants to display an informative name for a link rather than the URL itself. The present post describes RichEdit’s implementation of friendly name hyperlinks. It’s aimed at programmers, so if you’re not so inclined, you may want to skip it.

A friendly name hyperlink is essentially a field with two parts: an instruction part containing the URL and a result part containing the name. In fact that’s the way it appears in RTF, which has the syntax {\field{\*\fldinst {HYPERLINK "..."}}{\fldrslt{...}}}.

In RichEdit, the hyperlink field entity is represented by character formatting effects, as contrasted to delimiters which are used to structure math objects. As such, these hyperlinks cannot be nested, although in RichEdit 5.0 and later they can be adjacent to one another. The whole hyperlink has the character formatting effects of CFE_LINK and CFE_LINKPROTECTED, while autoURLs only have the CFE_LINK attribute. The CFE_LINKPROTECTED is included for the former so that the autoURL scanner skips over friendly name links. The instruction part, i.e., the URL, has the CFE_HIDDEN attribute as well, since it’s not supposed to be displayed. The URL itself is enclosed in ASCII double quotes and preceded by the string “HYPERLINK “. Since CFE_HIDDEN plays an integral role in friendly name hyperlinks, it cannot be used in the name.

For example, in WordPad, which uses RichEdit, a hyperlink with the name MSN would have the plain text

                HYPERLINK ""MSN

The whole link would have CFE_LINK and CFE_LINKPROTECTED character formatting attributes and all but the MSN would have the CFE_HIDDEN attribute.

In RichEdit 4.1, the only way to insert a friendly name hyperlink is to read in the corresponding RTF. For the example above, this RTF could be as simple as

{\rtf1{\field{\*\fldinst{ HYPERLINK ""}}{\fldrslt{ MSN} }}}.

Reading in the RTF can work well, but it’s convenient to have a more programmatic approach. Accordingly RichEdit 6.0 added the ITextRange2::SetURL(BSTR bstr) method, which uses the bstr as the URL for the range of text selected by the ITextRange2. The text in the bstr needs to start and end with ASCII double quotes. The word HYPERLINK is inserted in front of the URL by the SetURL() method. RichEdit 7.0 allows you to remove the link status from a friendly name hyperlink by calling SetURL() with a NULL bstr or one that has only the start and end quotes, signifying an empty string.

RichEdit doesn’t allow the CFE_LINKPROTECTED attribute to be set directly by programs. Maybe it will allow it someday after enough testing is completed to ensure that things cannot go awry. Programmatically you can use ITextRange::Expand(tomLink, pDelta) to select the whole friendly name link: hidden URL together with the friendly name. You can move from link to link using ITextRange::Move(tomLink, Count, pDelta).

As for autoURLs, the RichEdit client enables hyperlink notifications (EN_LINK) by sending RichEdit the ENM_LINK flag in the mask included with theEM_SETEVENTMASK message. A notification is sent if the user hits Enter, moves the mouse over it (not doing drag&drop), left clicks (or double clicks) on it. It is also sent if the message EM_HANDLELINKNOTIFICATION is received (OneNote uses this). The ENLINK notification structure contains a CHARRANGE with the start and end character positions of the actual URL (IRI, file path name, email address, etc.) that typically appears in a browser URL window. This doesn't include the "HYPERLINK " string nor the quotes in the hidden part. For the MSN link above, it identifies only the characters in the backing store.

In RichEdit 5.0 and later, the client can enable tooltips displaying the URLs by sending the EM_SETEDITSTYLE message with the SES_HYPERLINKTOOLTIPS (8) flag.