PowerBuilder Authors: Chris Pollach, Yeshim Deniz, Jayaram Krishnaswamy, Kevin Benedict, Avi Rosenthal

Related Topics: PowerBuilder

PowerBuilder: Article

Implementing the Microsoft Rich Edit Control

Part 1

What we needed to do was implement spell checking in the rich edit fields in our application (see Figures 1 and 2). To do that, we got a license for the Sentry Spelling Checker Engine from Wintertree Software (www.wintertree-software.com). The utility is easily implemented and works quite well on standard Rich Edit controls.

However, the PowerBuilder Rich Edit control is an OEM version of an old third-party control that was popular before Microsoft introduced its Rich Edit control to the common controls. As a result, the messages and functions it supports are completely different from those that the Sentry utility is trying to use to interact with the control.

Our first approach to dealing with this was to extend the PowerBuilder Rich Edit control so that it mimicked the events and functions of the Microsoft Rich Edit control. However, we soon realized that the amount of work required to do this was rapidly approaching the same level of effort needed to replace the PowerBuilder Rich Edit control with the Microsoft version. We also realized that there were other potential advantages to implementing the Microsoft version instead, not the least of which would be support for a recent version of the RTF standard.

Implementation - u_richedit
The first step was to take a page from Regan Sizer (author of the Common Controls chapter of the SAMs PowerBuilder 9: Advanced Client/Server Development book and a couple of related excerpts here in PBDJ) and create a custom visual user object based on the Microsoft Rich Edit control (see Figure 3).

You'll want to refer to the MSDN reference page on its Rich Edit control as we discuss the implementation. See http://msdn.microsoft.com/library/default.asp?url=/

The "About Rich Edit Controls" link on that page takes us to another page that indicates the DLL and class name we need to reference to implement the control. We've referenced the RICHED20.DLL file so we can support up through version 3.0 of the control. The most recent version of the control (as of this writing) is 4.1 and would require a reference to the MSFTEDIT.DLL file instead. However, that version of the control is only supported on Windows XP SP1 and later. Version 3.0 is supported on all operating systems since Window 98. Since we can't guarantee that all of our users will be on XP SP1 or later, we chose to implement a slightly older version of the control to ensure compatibility on all clients. Since version 2.0, the control offers two class names: one for Unicode and another for ANSI. Since our application is still PowerBuilder 9 (ANSI)-based, we're using the ANSI class (RichEdit20A).

Finally, the "Rich Edit Control Styles" link on that page takes us to another page that indicates the various style settings available that we need to implement through the Style property of the visual user object. The styles we are particularly concerned about are:

  • ES_LEFT: left paragraph alignment
  • ES_SUNKEN: gives the control a sunken border
  • ES_MULTILINE: otherwise the control defaults to support for only a single line
  • ES_WANTRETURNS: so the user entering carriage returns will result in a returns character being added to the text in the control
  • ES_NOHIDESEL: so the selected text in the control is still highlighted when focus moves off the control.

The values for those and other constants we'll be using are provided in the include files (*.h) provided in the Windows SDK, particularly WinUser.H and RichEdit.H. The values in those files are provided in a hexadecimal format that we'll need to convert to decimal and combine (see Table 1).

u_richedit Instance Variables
There are a large number of instance variables declared in the user object; all but one of them are constants from the Windows API used to interact with the control. For those of you with some C++ experience, this is essentially the way that we incorporated an include file with defined constants. What this let us do was refer to various messages and settings in our code by the names used in the Windows API (e.g., PFA_LEFT, PFA_RIGHT, PFA_CENTER, and PFA_JUSTIFY for paragraph justification), which will make the PowerScript code more understandable. The one additional instance variable was a string variable (rtftext) used to capture data coming from a callback, which we'll discuss a bit later.

u_richedit Local External Functions
The user object also has a large number of local external functions declared on it. Many of them are aliases for the SendMessage Windows API function. Most of the interaction we'll be having with the control will be by sending a certain Windows message to the control using that function. The SendMessage function takes four arguments, the first one being the handle of the window or control we're sending the message to and the second one being the numeric value of the message we're sending. The third and fourth arguments vary depending on which message we're sending. We could have declared a number of overloaded versions of the SendMessage function without using aliases, but opted to use aliases to make the PowerScript code more understandable.

When working with Windows API function calls, we occasionally have to work with arguments that are pointers or structures used as arguments that contain pointers. That requires some memory manipulation before or after the call, and we've declared a number of Windows API functions as local external functions to assist us with that (LocalAlloc, LocalFree, RtlMoveMemory, GlobalAlloc, GlobalLock, GlobalUnlock, and GlobalFree). To do copy and paste operations with RTF data, we also declared a number of Windows API functions for working with the clipboard (OpenClipboard, RegisterClipboardFormat, GetClipboardData, SetClipboardData, and CloseClipboard). A few Windows API function declarations were added to support the use of the ChooseFont dialog (ChooseFont, GetDC, GetDeviceCaps, and MulDiv).

One of the Windows messages we'll be sending to the control (EM_STREAMOUT - used to get the RTF formatted data out of the control) requires the address of a callback routine to return the data. Since PowerBuilder doesn't support callbacks, we've written a custom DLL (which we'll be discussing in Part 2) to provide that callback. We have to load the DLL and get the address of that callback, so we've declared a couple of Windows API function calls to help with that (LoadLibrary, GetProcAddress, and FreeLibrary). Finally, the callback needs to know how to send the data back to the control, so there's also a local external function declaration for that custom DLL to provide the handle to the control (SetControl).

More Stories By Bruce Armstrong

Bruce Armstrong is a development lead with Integrated Data Services (www.get-integrated.com). A charter member of TeamSybase, he has been using PowerBuilder since version 1.0.B. He was a contributing author to SYS-CON's PowerBuilder 4.0 Secrets of the Masters and the editor of SAMs' PowerBuilder 9: Advanced Client/Server Development.

More Stories By Demetrios Tsakiris

Demetrios Tsakiris is a senior programmer at Integrated Data Services. He has been working with PowerBuilder since version 5.0 and has a total of 5 1/2 years in the programming world. Demetrios is also an Oracle, Sybase, and Unix developer.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.