Click here to Skip to main content
15,881,852 members
Articles / Desktop Programming / MFC
Article

Using Windowless RichEdit Controls

Rate me:
Please Sign up or sign in to vote.
4.81/5 (21 votes)
10 Oct 2006CPOL5 min read 126.8K   7.4K   66   18
How to use the windowless RichEdit control, one of Microsoft's less well-documented APIs.

Sample Image

Introduction

Windowless controls have been around since the dawn of ActiveX, and are very useful when you do not want (or cannot have) a separate HWND for every control element in your user interface. This article presents the class CRichDrawText, a simple wrapper around the windowless version of the RichEdit control, allowing formatted text to be sized and drawn on a device context.

Background

As part of an application I was working on (the Windows version of Inform 7), I had a need to draw sections of formatted text in a CScrollView derived class. As the application was already making heavy use of the RichEdit control, that seemed the perfect control to use. Experiments with the FormatRange and DisplayBand functions in CRichEditCtrl were not satisfactory: what I needed was a proper windowless control.

When I actually came to try to use the windowless RichEdit control, however, life became more interesting. The MSDN documentation in this area is very sparse. Most of the useful information I found buried away in an MSDN Knowledge Base article, Q270161, with the remainder determined by trial and error. Hopefully, if you need a windowless RichEdit control, you won't have to do as much searching as I did.

Using the code

To use the class in your code, include RichDrawText.h and declare an instance of the CRichDrawText class somewhere.

To find out how much vertical space is needed for the contents of the CRichDrawText, call SizeText, passing in a device context and a rectangle whose width is the width you want the text to be formatted for. To actually draw the text, call DrawText, passing in a device context and the bounding rectangle.

To actually set up the formatted text, CRichDrawText provides two methods. SetText replaces all the text in the windowless control with the given Unicode string, and Range returns an ITextRange COM interface pointer for a range of text in the windowless control. ITextRange is part of the TOM (Text Object Model) which is an under-appreciated part of the RichEdit control, providing faster and more functional text manipulation than is available through the usual RichEdit EM_ messages. A description of the TOM is outside of the scope of this article, but the example program provided with this article, along with the MSDN documentation, should be enough to get you started.

The ITextHost implementation

In the CRichDrawText constructor, we create a windowless RichEdit control by calling the CreateTextServices function, to which we have to pass an implementation of the ITextHost interface. The CRichDrawText class provides a minimal implementation, which does the least possible to be able to size and draw the rich text. Which methods to implement was determined simply by seeing which were called using the debugger. Most of these methods are straightforward, however:

HRESULT CRichDrawText::XTextHost::TxNotify(DWORD iNotify, void *pv)
{
  return S_OK;
}
The TxNotify implementation must return S_OK, even if it does nothing with the notification messages it is passed. If it returns an error code then the sizing and drawing calls will fail.

Another catch for the unwary is TxGetCharFormat which must return a pointer to a CHARFORMATW structure, not a CHARFORMAT: the Unicode version of the structure must be used, even on Windows 95.

What CreateTextServices returns

Having successfully called CreateTextServices we now have an IUnknown COM pointer, which according to MSDN, we can now use QueryInterface on to get an ITextServices COM pointer. However, my initial attempts at this all failed: I always got E_NOINTERFACE back from the QueryInterface call.

The problem turns out to be that the IID_ITextServices linked in from riched20.lib is wrong. Thanks, Microsoft... The code linked from Knowledge Base article Q270161 contains the correct IID:

const IID IID_ITextServices = {
  // 8d33f740-cf58-11ce-a89d-00aa006cadc5
  0x8d33f740, 0xcf58, 0x11ce, {0xa8, 0x9d, 0x00, 0xaa, 0x00, 0x6c, 0xad, 0xc5}
};
When we include this in the CRichDrawText source file (where it will be linked in preference to the one in riched20.lib), we are able to get back an ITextServices COM pointer.

Calling ITextServices methods

Having implemented ITextHost and obtained an ITextServices interface, we are now ready to actually call the methods to size and draw text.

The CRichDrawText::SizeText method calls ITextServices::TxGetNaturalSize to calculate the required height. Trial and error has had to be used here to determine what all the arguments should be:

  • hicTargetDev and ptd are both NULL, even though the documentation does not say that null values are allowed. For drawing onto a display device context, it is not easy to see what else could be passed.
  • psizelExtent is a pointer to a SIZEL structure with both member variables set to -1. MSDN claims that this argument is "currently unused" but this seems not to be the case: passing in NULL leads to an access violation in riched20.dll. Passing in zeros (or small values) seems to affect the returned sizing rectangle. Given the lack of documentation, using {-1,-1} seems a reasonable approach.

The CRichDrawText::DrawText method calls ITextServices::TxDraw to draw the rich text. The arguments to this method have proved slightly less problematic. However:

  • pvAspect is NULL, though the documentation does not say if this is allowed. Given that the argument's type is void* and the documentation for it says "pointer for information for drawing optimizations", this might be worthy of some sort of award for unhelpful documentation.
  • hicTargetDev and ptd are again both NULL.
  • lViewId is zero. MSDN claims that this argument is not used, but in the Platform SDK TextServ.h defines enum TXTVIEW as "useful values for TxDraw lViewId parameter".

Conclusion

With poorly documented interfaces, the hardest problem is usually getting any of it to work in the first place. I hope that this article will give anyone playing with the windowless RichEdit control enough of a start that they can make it do what they need. Anyway, if it was easy, what would be the fun in that?

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 3 Pin
buyong26-Sep-11 15:20
buyong26-Sep-11 15:20 
Questionx64 problems... Pin
ronhash3-Aug-11 18:47
ronhash3-Aug-11 18:47 
AnswerRe: x64 problems... Pin
David Kinder6-Sep-11 2:42
David Kinder6-Sep-11 2:42 
GeneralDoesn't work if compiled with VST2005 SP1 on Vista Pin
mhorowit17-Jan-10 16:09
mhorowit17-Jan-10 16:09 
GeneralRe: Doesn't work if compiled with VST2005 SP1 on Vista Pin
David Kinder29-Jan-10 1:54
David Kinder29-Jan-10 1:54 
Question.net code? Pin
Roey C19-Sep-09 11:38
Roey C19-Sep-09 11:38 
AnswerRe: .net code? Pin
cpw999cn12-Mar-13 23:52
cpw999cn12-Mar-13 23:52 
Questionhow about 64bit... Pin
Member 84311611-Mar-09 21:42
Member 84311611-Mar-09 21:42 
AnswerRe: how about 64bit... Pin
David Kinder20-Mar-09 3:32
David Kinder20-Mar-09 3:32 
QuestionCan you help me? Pin
kjsfuture5-Aug-08 17:42
kjsfuture5-Aug-08 17:42 
QuestionHow to use "TxGetNaturalSize" method? Pin
george112816-Jun-08 16:01
george112816-Jun-08 16:01 
GeneralAdding RTF text Pin
abrken1-Mar-07 22:17
abrken1-Mar-07 22:17 
GeneralRe: Adding RTF text Pin
David Kinder4-Mar-07 5:05
David Kinder4-Mar-07 5:05 
GeneralRe: Adding RTF text Pin
abrken4-Mar-07 23:13
abrken4-Mar-07 23:13 
QuestionHow to add scrolling support Pin
Duc Truong14-Oct-06 8:21
Duc Truong14-Oct-06 8:21 
AnswerRe: How to add scrolling support Pin
David Kinder15-Oct-06 22:24
David Kinder15-Oct-06 22:24 
GeneralRe: How to add scrolling support Pin
Duc Truong18-Oct-06 8:25
Duc Truong18-Oct-06 8:25 
AnswerRe: How to add scrolling support Pin
Amro Ibrahim26-Aug-07 0:00
Amro Ibrahim26-Aug-07 0:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.