MSDN Home > MSDN Library > User Interface Design and Development > Windows Controls > Individual Control Information > Rich Edit Controls > Text Object Model > |
The top-level Text Object Model (TOM) object is defined by the ITextDocument interface, which has methods for creating and retrieving objects lower in the object hierarchy. For simple, plain text processing, you can obtain an ITextRange object from an ITextDocument object. If you need to add rich-text formatting, you can obtain ITextFont and ITextPara objects from an ITextRange object:
In addition to these three lower-level objects, TOM has a selection object ITextSelection, which is just an ITextRange object with selection highlighting and additional UI-oriented methods. The range and selection objects include screen-oriented methods that enable programs to examine text on the screen or text that could be scrolled onto the screen. These capabilities aid in making text accessible to the visually impaired, for example. These objects can be illustrated by the following directory tree: ITextDocument Top-level editing object ITextStoryRanges Enumerator for stories in document ITextRange Primary text interface: range of text ITextFont Character-attribute interface ITextPara Paragraph-attribute interface ITextSelection Screen highlighted text range that inherits all ITextRange methods A story is a contiguous range of text. An ITextDocument object describes one or more stories. In Microsoft Word, a story contains one of the various parts of a document, such as the main text of a document, headers and footers, footnotes, or annotations. In rich edit controls, there is only one story per document, although a client can use multiple documents to represent multiple stories. An ITextRange object is defined by its start and end character position (cp) offsets and a story object. As such, it does not exist independently of its parent story object, although its text can be copied to the Clipboard or to other targets. A text range object is different from spreadsheet and other range objects, which are defined by other kinds of offsets, like row/column or graphics position (x,y). A text range object can:
Note that an explicit story object is not needed, since an ITextRange object can always be created to represent any given story. In particular, the ITextDocument object can create an ITextStoryRanges object to enumerate the stories in the document in terms of ranges with start and end cp values that describe complete stories (such as, 0 and tomForward). The following topics are discussed in this section. TOM RTFIn Text Object Model (TOM) 1.0, rich-text exchange can be accomplished by sets of explicit method calls or by transfers of rich text in the Rich Text Format (RTF) format. This section gives tables of RTF control words for paragraph properties and for character properties. TOM RTF Paragraph Control Words
TOM RTF Character Format Control Words
Finding Rich TextTOM methods can be used fairly easily to find rich text as defined by a range of text. The Microsoft Word Find command can find plain text with uniform formatting, such as Arial 11-point, but it cannot find text with a combination of formatting, such as a2. Finding such rich text exactly is often needed in word processing, although it has never been fulfilled in a "what you see is what you get" (WYSIWYG) word processor. There is clearly a larger domain of rich-text matching that allows for some character formatting properties to be ignored (or to include paragraph formatting and/or object content), but such generalizations are beyond the scope of this section. One purpose for this functionality is to use a rich-text Find dialog box to define the rich text you want to locate in a Word document. The dialog box would be implemented using a rich edit control and TOM methods would be used to carry out the search through the Word document. You could either copy the desired rich text from a Word document into the Find dialog box or enter and format it directly in the Find dialog box. The following program uses TOM methods to find text containing combinations of exact character formatting. The algorithm searches for the plain text in the match range, which is named pr1. If the plain text is found, it is pointed to by a trial range, which is named pr2. Then, two insertion-point ranges (prip1 and prip2) are used to walk through the trial range comparing its character formatting to that of pr1. If they match exactly, the input range (given by ppr) is updated to point at the trial range's text and the function returns the count of characters in the matched range. Two ITextFont objects, pf1 and pf2, are used in the character-formatting comparison. They are attached to the insertion-point ranges prip1 and prip2, respectively. LONG FindRichText ( ITextRange **ppr, // Ptr to range to search ITextRange *pr1) // Range with rich text to find { BSTR bstr; // pr1 plain-text to search for LONG cch; // Text string count LONG cch1, cch2; // tomCharFormat run char counts LONG cchMatch = 0; // Nothing matched yet LONG cp; // Handy char position LONG cpFirst1; // pr1 cpFirst LONG cpFirst2; // pr2 cpFirst ITextFont * pf1, *pf // Fonts corresponding to IPs prip1 and prip2 ITextRange *pr2; // Range duplicate to search with ITextRange *prip1, *prip // Insertion points to walk pr1, pr2 if (!ppr || !*ppr || !pr1) return E_INVALIDARG; // Initialize range and font objects used in search if ((*ppr)->GetDuplicate(&pr2) != NOERROR || pr1->GetDuplicate(&prip1) != NOERROR || pr2->GetDuplicate(&prip2) != NOERROR || prip1->GetFont(&pf1) != NOERROR || prip2->GetFont(&pf2) != NOERROR || pr1->GetText(&bstr) != NOERROR ) { return E_OUTOFMEMORY; } pr1->GetStart(&cpFirst1); // Keep searching till rich text is matched or no more plain-text hits while(!cchMatch && pr2->FindText(bstr, tomForward, 0, &cch) == NOERROR) { pr2->GetStart(&cpFirst2); // pr2 is a new trial range prip1->SetRange(cpFirst1, cpFirst1); // Set up IPs to scan match prip2->SetRange(cpFirst2, cpFirst2); // and trial ranges while(cch > 0 && pf1->IsEqual(pf2, NULL) == NOERROR) // Walk match & trial ranges { // together comparing font prip1->GetStart(&cch1); // properties prip1->Move(tomCharFormat, 1, NULL); prip1->GetStart(&cp); cch1 = cp - cch1; // cch of next match font run prip2->GetStart(&cch2); prip2->Move(tomCharFormat, 1, NULL); prip2->GetStart(&cp); cch2 = cp - cch2; // cch of next trial font run if(cch1 < cch) // There is more to compare { if(cch1 != cch2) // Different run lengths: break; // no formatting match cch = cch - cch1; // Matched format run } else if(cch2 < cch) // Trial range format run too break; // short else // Both match and trial runs { // reach at least to match pr2->GetEnd(&cp); // text end: rich-text match (*ppr)->SetRange(cpFirst2, cp) // Set input range to hit cchMatch = cp - cpFirst2; // coordinates and return break; // length of matched string } } } pr2->Release(); prip1->Release(); prip2->Release(); pf1->Release(); pf2->Release(); SysFreeString(bstr); return cchMatch; } TOM AccessibilityTOM provides accessibility support through the ITextSelection and ITextRange interfaces. This section describes methods that are useful for accessibility as well as how a program can determine the x, y screen position of an object. Since UI-based accessibility programs typically work with the screen and the mouse, a common concern is to find the corresponding ITextDocument interface for the current mouse location (in screen coordinates). The following sections present two ways to determine the proper interface:
For more information, see the Microsoft Active Accessibilityฎ specification. After you obtain an object from a screen position, you can use for an ITextDocument interface and call the ITextDocument::RangeFromPoint method to get an empty range object at the cp corresponding to the screen position. Interface from Running Object TableA running object table (ROT) tells what object instances are active. By querying this table, you can accelerate the process of connecting a client to an object when the object is already running. Before programs can access TOM interfaces through the running object table, a TOM instance with a window needs to register in the ROT using a moniker. You construct the moniker from a string containing the hexadecimal value of its HWND. The following code sample shows how to do this. // This TOM implementation code is executed when a new windowed // instance starts up. // Variables with leading underscores are members of this class. HRESULT hr; OLECHAR szBuf[10]; // Place to put moniker MONIKER *pmk; hr = StringCchPrintf(szBuff, 10, "%x", _hwnd); if (FAILED(hr)) { // // TODO: write error handler // } CreateFileMoniker(szBuf, &pmk); OleStdRegisterAsRunning(this, pmk, &_dwROTcookie); .................... // Accessibility Client: // Find hwnd for window pointed to by mouse cursor. GetCursorPos(&pt); hwnd = WindowFromPoint(pt); // Look in ROT (running object table) for an object attached to hwnd hr = StringCchPrintf(szBuff, 10, "%x", hwnd); if (FAILED(hr)) { // // TODO: write error handler // } CreateFileMoniker(szBuf, &pmk); CreateBindContext(0, &pbc); pmk->BindToObject(pbc, NULL, IID_ITextDocument, &pDoc); pbc->Release(); if( pDoc ) { pDoc->RangeFromPoint(pt.x, pt.y, &pRange); // ...now do whatever with the range pRange } Interface from Window MessagesThe EM_GETOLEINTERFACE message provides another way to obtain an IUnknown interface for an object at a given screen position. As described in the Interface from Running Object Table topic, you get an HWND for the screen position and then send this message to that HWND. The EM_GETOLEINTERFACE message is rich edit-specific and returns a pointer to an IRichEditOle interface in the variable addressed by lParam. Tip If a pointer is returned (be sure to set the object to which lParam points to null before sending the message), you can call its IUnknown::QueryInterface method to obtain an ITextDocument interface. The following code sample illustrates this approach. HWND hwnd; ITextDocument *pDoc; ITextRange *pRange; POINT pt; IUnknown *pUnk = NULL; GetCursorPos(&pt); hwnd = WindowFromPoint(pt); SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&pUnk); if(pUnk && pUnk->QueryInterface(IID_ITextDocument, &pDoc) == NOERROR) { pDoc->RangeFromPoint(pt.x, pt.y, &pRange); // ... continue with rest of program } Accessibility Oriented MethodsSome TOM methods are particularly useful for navigating around the screen, while other TOM methods enhance what you can do when you arrive at places of interest. The following table describes the most useful methods.
Character Match SetsThe variant parameter of the various Move* methods in ITextRange, for example, ITextRange::MoveWhile and ITextRange::MoveUntil, can take an explicit string or a character-match set 32-bit index. The indexes are defined by either Unicode ranges or GetStringTypeEx character sets. The Unicode range starting at n and of length l (< 32768) is given by the index n + (l << 16) + 0x80000000. For example, basic Greek letters are defined by CR_Greek = 0x805f0370 and printable ASCII characters are defined by CR_ASCIIPrint = 0x805e0020. In addition, the ITextRange::MoveWhile and ITextRange::MoveUntil methods let you rapidly bypass a span of characters in any GetStringTypeEx character set or a span of characters not in any one of these character sets, respectively. In spite of their power, these methods are very efficient, requiring only 150 lines of C++ to implement. The GetStringTypeEx sets are specified by the values for Ctype1, Ctype2, and Ctype3 and are defined as follows.
Specifically, Ctype1 can be any combination of the following.
The Ctype2 types support proper layout of Unicode text. The direction attributes are assigned so that the bidirectional layout algorithm standardized by Unicode produces accurate results. These types are mutually exclusive. For more information about the use of these attributes, see The Unicode Standard: Worldwide Character Encoding, Volumes 1 and 2, Addison-Wesley Publishing Company: 1991, 1992.
The Ctype3 types are intended to be placeholders for extensions to the POSIX types required for general text processing or for the standard C library functions. These types are supported in Microsoft Windows NTฎ, Microsoft Windowsฎ 2000, and Windows XP.
An Edit Development Kit (EDK) could include pVar index #defines for the following ranges described in the Unicode Standard.
TOM Interface ConventionsIn using Microsoft Visual Basicฎ for Applications (VBA)-compatible dual interfaces, all TOM methods return HRESULT values. In general, TOM uses standard values, namely:
While it is possible to use more specific, custom values, they would complicate documentation and usage. Note that if the editing instance associated with a TOM object such as ITextRange is deleted, then the TOM object becomes useless, and all its methods return CO_E_RELEASED. In addition to the HRESULT return values, many methods include out parameters, which are pointers used to return values. In particular, all VBA property-get methods have such an out parameter. As for all interfaces, all pointer (ptr) parameters must be checked to be nonzero before use. Required pointers passed with null values cause the method to return E_INVALIDARG. Optional out pointers with null values are ignored. Such optional out pointers include the pDelta and pB parameters of ITextRange. Use methods with Get- and Set- prefixes respectively, to get and set properties. Get and Set are preferred from a C/C++ perspective. Boolean variables use the explicit values tomFalse = zero for FALSE and tomTrue = 1 for TRUE (to agree with VBA). Reference pages for some TOM interface methods use the phrases "property-put method" and "property-get method" to identify methods that set and retrieve a VBA property. VBA code can use these methods or access the property directly. For example, if tf is an ITextFont object, the following VBA code is equivalent to calling the ITextFont::SetBold method: tf.Bold = tomTrue TOM constants all begin with the prefix tom, for example tomWord, and where possible, agree with the corresponding Word constants, which begin with the prefix WD. Please see the Tom.odh file for Object Description Language (ODL) prototypes of the TOM methods as well as a complete listing of the TOM constants. Also, the files Tomstub.cpp and Tomstub.h give the headers and dummy bodies for all TOM methods needed to facilitate a TOM implementation. To obtain clean C/C++ interfaces and to simplify TOM implementations, take advantage of the VBA strongly typed optional (missing) arguments. For example, an optional Count argument can be declared to be a long value and assigned the default value of 1 in the event that the VBA code omits the Count argument. Since previous versions of VBA need to use VARIANT * for optional arguments, this means that all TOM arguments must be given for use with these older versions. Linear dimensions are given in floating-point points, which is the VBA standard for Word and Microsoft Excel. Use the C languagefloat data type. |
Contact Us | E-Mail this Page | MSDN Flash Newsletter | Legal |
© 2003 Microsoft Corporation. All rights reserved. Terms of Use Privacy Statement Accessibility |