ITextSevices -- Using the Windowless RichEdit for Drawing RTF

Environment: VC6 SP4, Platform SDK November 2001 recommended

Introduction to the Windowless RichEdit

It is a little-known fact that the RichEdit from version 2.0 onwards comes with a COM interface to drive it. To use this interface, you don't need to create a RichEdit window, so it is perfect for applications that don't need the extra handling required by having just another window. The example given here illustrates this point by providing a class that can draw RTF text anywhere you'd like.

The main COM interfaces involved are ITextHost, ITextServices, and ITextDocument. When you create a windowless RichEdit, you have to provide it with a class that implements ITextHost. This class is usually quite simple, even more so in my example because I just use it for drawing and don't provide editing capabilities. ITextServices is the main interface you use to communicate with RichEdit. It provides the functions for setting, getting, and drawing the text. Moreover, it lets you send messages to the RichEdit that's hidden behind it. So you can still use all the standard messages such as EM_SETCHARFORMAT. ITextDocument is the interface you can use to bypass the message passing. By using it, you can get an ITextSelection interface to the current selection—an ITextRange interface for any range, for example. These in turn let you get ITextFont objects and so on.

ITextDocument is not specific to the windowless RichEdit, though. When you have created a windowed RichEdit, you can use the EM_GETOLEINTERFACE message to retrieve a COM interface to the RichEdit, anyhow. This interface can be queried for ITextDocument and you will be able to use all its functionality.

Implementing ITextHost

This is where it gets a little complicated. The MSDN documentation on ITextHost is pretty much non-existant, so you have to work from the few indications you get. If you want to implement a fully editable ITextServices object, you will have to fill in all the functions I have left blank in my example. This is because, for the sole purpose of drawing RTF text, you don't need to provide much information to ITextServices, aside from the RTF text, the formatting rectangle, and the HDC. It is recommended that the class that implements ITextHost be a COM class because that's the way ITextServices communicates with it. To make my example easier, I left out the COM bits and provided myself the basic IUnknown functions. It is interesting to note that just after creating the TextServices object, it queries the TextHost for some other interface. I have not been able to figure out what this is, though.

Using the Example Code

All the windowless RichEdit functionality is provided by the CFormattedTextDraw class. It implements ITextHost minimally and also the custom interface (or rather purely abstract class) IFormattedTextDraw. The reason for using IFormattedTextDraw is that you should not call any functions on ITextHost directly; access should always be through IFormattedTextDraw instead of CFormattedTextDraw. The usage of the class can be seen in the Win32Test.cpp file. It is based on the sample "Hello World" Win32 project that VC6 generates. Here is the simplicity with which you use this class:

IFormattedTextDraw *g_Formatter;
BSTR               bstrText;
RECT               rt;
HDC                hdc;

g_Formatter = new CFormattedTextDraw;
// Fill in the Unicode text, the rectangle, and get an HDC
g_Formatter->Draw(hdc, &rt);


To use this code in your own projects, you will have to link with riched20.lib. Moreover, you will most probably get a linker error related to _IID_ITextServices and _IID_ITextHost. If this is the case, open your version of textserv.h (you will find it in the ..\Microsoft SDK\include directory) and comment out the two following lines:

//EXTERN_C const IID IID_ITextServices;
//EXTERN_C const IID IID_ITextHost;


Download demo project - 17 Kb
Download source - 13 Kb


Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Relying on outside companies to manage your network and server environments for your business and applications to meet the needs and demands of your users can be stressful. This is especially true as many Managed Hosting organizations fail to meet their service level agreements. Read this Forrester total economic impact report and learn what makes INetU different and how they exceed their customers' managed hosting expectations.

  • According to a 2014 Javelin Strategy & Research Study, there is a new victim of fraud every two seconds – and that's just in the U.S. With identity theft and consumer fraud rising, and more frequent and sizable data breaches in the news, financial institutions need to work harder than ever to protect their customers and their business. Download this white paper to learn how you can use multi-channel communications to minimize the costs of fraud while also increasing customer loyalty.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date