Environment:VS .NET (works with RC1, should work with BETA2 as well)
With VC++ 6.0 everything was simple. You had a wizard create a project using a document/view architecture and chose CRichEditView as view class and MFC framework gave you print preview and printing out of the box without need to put additional work in it.
Then came VS.NET. Admittedly, the new features of the dotnet framework are great,
but up until now it lacked an easy way of bringing the contents of a richedit control to your printer.
After many hours of searching for a suitable way to incorporate printing services into my project I finally started resorting to Win32 API calls again, since none of the suggestions you find on the web or on MSDN delivered anything practical.
After many more hours of fiddling with device contexts, page margins etc. I finally succeeded in creating an extension for .NET’s RichTextBox control with additional methods for doing print output in a way it should have been included with .NET from the beginning (IMHO).
In fact the only API function I had to encapsulate was to send EM_FORMATRANGE to the control. Since this particular message receives a pointer to a struct as one parameter I had to dwell into the depths of .NET’s InteropServices, but in the end it worked out quite nicely.
First the required structs had to be introduced to .NET:
typedef struct tagRECT
} RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT;
[ StructLayout( LayoutKind.Sequential )]
private struct RECT
public int left;
public int top;
public int right;
public int bottom;
Note that API’s
LONG type maps to an
int in .NET, not to
long or you’ll get some weird results.
FORMATRANGE struct handled much
the same way, marshalling the device context handles to
Next came the declaration of the SendMessage API function:
private static extern IntPtr SendMessage(IntPtr hWnd,
Although you’ll find an example in MSDN where SendMessage receives
int as type for wParam and lParam, you need
IntPtr here because a pointer to a FORMATRANGE struct has to be marshalled.
The rest went quite straightforward. To put the contents of the FORMATRANGE struct into an IntPtr parameter you have to use a static method
after allocating enough space with
Don’t forget to release the memory afterwards by calling
Marshal.FreeCoTaskMem()(the Garbage Collector won’t help you here).
Use RichTextBoxEx the same way you would use a regular RichTextBox.
When it comes to printing, you can use the method
FormatRange() to render the contents of your RichTextBoxEx control according to the PrintPageEventArgs parameter you receive in the PrintPageEvent event handler function.
When you’re done printing call the method
FormatRangeDone() to release any cached information the WIN32 RichEdit control still is holding.
Have a look at the sample project if you’re unsure on how to use the control.