Formatted Text via RichEdit and TOM - by just me

Helpful script writing tricks and HowTo's
burque505
Posts: 689
Joined: 22 Jan 2017, 19:37

Formatted Text via RichEdit and TOM - by just me

12 Mar 2018, 10:28

Foreword
I found this tutorial by just me in the German forum, and thought it would be useful for those who come here.
With just me's kind permission, I offer this translation.
Regards,
burque505
MyRTF.PNG
MyRTF.PNG (29.36 KiB) Viewed 1067 times
As a developer, every now and then you might need to display formatted text in a GUI. AHK does not provide suitable control for this. AHK 1. 1 offers two possibilities for embedding further controls registered in the system:
• ActiveX
• Custom
As a rule, ActiveX controls are COM objects that can only be integrated with a GUI in a way that permits use similar to that of built-in controls.

Custom controls usually behave similar to built-in controls. You can assign variables and subroutines, for example. In principle, all built-in controls can also be used as custom controls. That offers few practical benefits.

For 'simple' output of formatted text, there are two alternatives:
1. HTML -> MSIE-Browser Control (ActiveX)
2. RTF -> RichEdit Control (Custom)
We'll limit ourselves here to the second variant (RTF), and the implementation of custom controls.

RichEdit Control

Like the Edit Control, the RichEdit Control is one of the controls provided by Microsoft via the system, but unlike the 'normal' Edit Control, it has not yet been integrated into AHK..

Some time ago I wrote a RichEdit Class, which allows integrating RichEdit Controls into your own GUIs. The actual reason for this was that I needed a way to print formatted text out of AHK without being dependent on any other application. Nonetheless, I equipped the class with a lot of features and methods only used for editing. This makes the whole package a bit on the bulky side, and it requires a bit of training and practice to use.

While I was developing the class, I kept running across documentation for the Text Object Model (TOM). At first I couldn't get very far with it, and even later I remained a bit leery of getting used to this … 'stuff'. Recently I found this post by teadrinker, motivating me to take a closer look at it. I realized that TOM can make the handling of RichEdit Controls for simple tasks, such as the display of RTF files, much easier. Thus, the following tutorial!

Let's get started!

Step 1:

The RichEdit control is provided and registered by the system library msftedit. dll. From WinXP on, the control class registered is RICHEDIT50W. To be able to use the RichEdit control, the script has to explicitly load this dll, i.e.:

Code: Select all

RE_Dll := DllCall("LoadLibrary", "Str", "Msftedit.dll", "Ptr")
Step 2:

Once you've done that, you can add your RichEdit control to the GUI as a custom control:

Code: Select all

Gui, Add, Custom, ClassRICHEDIT50W vRE hwndHRE
Because AHK doesn't recognize the controls added as being Custom, only the essential styles are set automatically, such as: Eg WS_CHILD, WS_TABSTOP, WS_VISIBLE. Scrollbars can be set with the usual options HScroll / VScroll, because they are not control specific (WS_HSCROLL, WS_VSCROLL). However, even with a height specification such as h400 or r20, AHK can't tell it's a multi-line RichEdit Control. You have to set the appropriate style ES_MULTILINE (0x04) yourself. This applies to all other possible RichEdit styles too, for example, ES_READONLY (0x0800). For a multi-line, read-only RichEdit Control with a width and height of 400 pixels each and a vertical scrollbar, you need:

Code: Select all

Gui, Add, Custom, ClassRICHEDIT50W w400 h400 vRE hwndHRE +VScroll +0x0804 ; ES_MULTILINE | ES_READONLY
Step 3:

Now we have an empty RichEdit Control. To get this to display an existing RTF file, we need the associated TOM object, more specifically the TextDocument object. This can be elicited by the control via the message EM_GETOLEINTERFACE. How to do that is roughly described here. For AHK, it looks like this (without going into the ComObj instructions):
• Here, we send an EM_GETOLEINTERFACE message to the RichEdit control. This returns a pointer to the IRichEditOle interface.

Code: Select all

DllCall("SendMessage", "Ptr", HRE, "UInt", 0x043C, "Ptr", 0, "PtrP", IRichEditOle, "UInt") ; EM_GETOLEINTERFACE
• Now, using ComObjQuery (), we get a pointer to the ITextDocument interface,

Code: Select all

ITextDocument := ComObjQuery(IRichEditOle, IID_ITextDocument)
• which we in turn transform, via ComObject() into a TextDocument object.

Code: Select all

DocObject := ComObject(9, ITextDocument, 1)
Here's an example of a complete function:

Code: Select all

GetTomDoc(HRE) {
   ; TextDocument Objekt für ein RichEdit Control abrufen
   Static IID_ITextDocument := "{8CC497C0-A1DF-11CE-8098-00AA0047BE5D}"
   DocObj := 0
   If DllCall("SendMessage", "Ptr", HRE, "UInt", 0x043C, "Ptr", 0, "PtrP", IRichEditOle, "UInt") { ; EM_GETOLEINTERFACE
      DocObj := ComObject(9, ComObjQuery(IRichEditOle, IID_ITextDocument), 1) ; ITextDocument
      ObjRelease(IRichEditOle)
   }
   Return DocObj
}
Step 4:

Now we've got a RichEdit control and its TextDocument object. This object has the Open method, used to read files into the RichEdit control. The parameter Flags determines what content the file has. For files with RTF text, the flag tomRTF (0x01) is displayed. You can also specify that the file content being read in should a) completely replace the content of the RichEdit control or b) be inserted (tomPasteFile (0x1000).) That's all that's needed to display the file:

Code: Select all

DocObj.Open("MeineDatei.rtf", 0x01, 0)
Putting it all together

Back to work. Start Microsoft WordPad and create a RichText file. Save it with the name MyRTF.rtf in the same folder as the following script:

Code: Select all

#NoEnv
SetWorkingDir, %A_ScriptDir%
RE_Dll := DllCall("LoadLibrary", "Str", "Msftedit.dll", "Ptr")

Gui, +hwndhGui
Gui, Margin, 10, 10
Gui, Font, s10, Arial
Gui, Add, Custom, ClassRICHEDIT50W w400 h400 vRE hwndHRE +VScroll +0x0804 ; ES_MULTILINE | ES_READONLY
Gui, Show, , RichEdit

TomDoc := GetTomDoc(hRE)
TomFile := "MyRTF.rtf"
TomDoc.Open(TomFile, 0x01, 0)
Return

GuiClose:
ExitApp

GetTomDoc(HRE) {
   ; Get the document object of the specified RichEdit control
   Static IID_ITextDocument := "{8CC497C0-A1DF-11CE-8098-00AA0047BE5D}"
   DocObj := 0
   If DllCall("SendMessage", "Ptr", HRE, "UInt", 0x043C, "Ptr", 0, "PtrP", IRichEditOle, "UInt") { ; EM_GETOLEINTERFACE
      DocObj := ComObject(9, ComObjQuery(IRichEditOle, IID_ITextDocument), 1) ; ITextDocument
      ObjRelease(IRichEditOle)
   }
   Return DocObj
}
Additional considerations for Win 8+

With Win 8, Microsoft distributed a significantly updated RichEdit control. For one thing, the display of 'embedded objects' like images is greatly simplified. For RTF files created and displayed under Win 8, no further action is required. However, per my tests, the RichEdit control must not be ReadOnly when the file is read. Why? Because you can't just isolate and remove this style, you have to use the EM_SETOPTIONS message after the control has been created and populated:

Code: Select all

DllCall("SendMessage", "Ptr", HRE, "UInt", 0x044D, "Ptr", 0x02, "Ptr", 0x0800) ; EM_SETOPTIONS: ECOOP_OR, ECO_READONLY
iPhilip
Posts: 317
Joined: 02 Oct 2013, 12:21

Re: Formatted Text via RichEdit and TOM - by just me

29 Nov 2018, 17:32

Hi burque505,

Thank you for posting this tutorial. I found it easy to follow and the example was easy to test. :)
My question is: where did you get the value for the IID_ITextDocument variable?

Thank you again,

- iPhilip
Windows 7 Pro (64 bit) - AutoHotkey v1.1+ (Unicode 32-bit)
burque505
Posts: 689
Joined: 22 Jan 2017, 19:37

Re: Formatted Text via RichEdit and TOM - by just me

29 Nov 2018, 18:53

Hi iPhilip,
All I did was translate this from German to English - I'm not sure where @just me got that value. I'll dig around, though.
EDIT: There is some good info here.
And https://stackoverflow.com/questions/179 ... interfaces] here.
Even cooler: If you have an old version of Delphi, you can get these IDs easily. See [url=https://stackoverflow.com/questions/179 ... interfaces] here. [url]
The tool is tlibimp.exe, and is generally in a Delphi bin directory.
I generated files by running

Code: Select all

tlibimp -D. C:\Windows\System32\msftedit.dll
. Looking inside tom_TLB.pas, I got all this near the top:

Code: Select all

  tomMajorVersion = 1;
  tomMinorVersion = 0;

  LIBID_tom: TGUID = '{8CC497C9-A1DF-11CE-8098-00AA0047BE5D}';

  IID_ITextDocument: TGUID = '{8CC497C0-A1DF-11CE-8098-00AA0047BE5D}';
  IID_ITextRange: TGUID = '{8CC497C2-A1DF-11CE-8098-00AA0047BE5D}';
  IID_ITextSelection: TGUID = '{8CC497C1-A1DF-11CE-8098-00AA0047BE5D}';
  IID_ITextFont: TGUID = '{8CC497C3-A1DF-11CE-8098-00AA0047BE5D}';
  IID_ITextPara: TGUID = '{8CC497C4-A1DF-11CE-8098-00AA0047BE5D}';
  IID_ITextStoryRanges: TGUID = '{8CC497C5-A1DF-11CE-8098-00AA0047BE5D}';
  IID_ITextDocument2: TGUID = '{01C25500-4268-11D1-883A-3C8B00C10000}';
  IID_ITextMsgFilter: TGUID = '{A3787420-4267-11D1-883A-3C8B00C10000}';
Now I feel like a kid with a new toy!
Regards,
burque505
Last edited by burque505 on 29 Nov 2018, 19:14, edited 2 times in total.
iPhilip
Posts: 317
Joined: 02 Oct 2013, 12:21

Re: Formatted Text via RichEdit and TOM - by just me

29 Nov 2018, 19:10

burque505 wrote:
29 Nov 2018, 18:53

... All I did was translate this from German to English ...

Thank you for your translation skills. :)

- iPhilip
Windows 7 Pro (64 bit) - AutoHotkey v1.1+ (Unicode 32-bit)
burque505
Posts: 689
Joined: 22 Jan 2017, 19:37

Re: Formatted Text via RichEdit and TOM - by just me

29 Nov 2018, 19:15

Hi iPhilip, check out the edited post above.
Regards,
burque505
User avatar
jeeswg
Posts: 5444
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Formatted Text via RichEdit and TOM - by just me

29 Nov 2018, 19:24

Installing Visual Studio Express 2013 for Windows Desktop, created this folder:
C:\Program Files (x86)\Windows Kits\8.1
I searched the .h files for IID_ITextDocument and found:
C:\Program Files (x86)\Windows Kits\8.1\Include\um\TOM.h
C:\Program Files (x86)\Windows Kits\8.1\Include\winrt\windows.ui.text.h
Only TOM.h contained the value, 8CC497C0-A1DF-11ce-8098-00AA0047BE5D. Cheers.
iPhilip
Posts: 317
Joined: 02 Oct 2013, 12:21

Re: Formatted Text via RichEdit and TOM - by just me

29 Nov 2018, 19:31

Hi burque505,

Great! Thank you. I look forward to playing with that as well. :)

- iPhilip
Windows 7 Pro (64 bit) - AutoHotkey v1.1+ (Unicode 32-bit)
iPhilip
Posts: 317
Joined: 02 Oct 2013, 12:21

Re: Formatted Text via RichEdit and TOM - by just me

03 Dec 2018, 19:07

jeeswg wrote:
29 Nov 2018, 19:24
Installing Visual Studio Express 2013 for Windows Desktop, created this folder:
C:\Program Files (x86)\Windows Kits\8.1
I searched the .h files for IID_ITextDocument and found:
C:\Program Files (x86)\Windows Kits\8.1\Include\um\TOM.h
C:\Program Files (x86)\Windows Kits\8.1\Include\winrt\windows.ui.text.h
Only TOM.h contained the value, 8CC497C0-A1DF-11ce-8098-00AA0047BE5D. Cheers.
Thank you jeeswg,

After installing Visual Studio Community 2017 (Desktop development with C++), I found the above information in C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\TOM.h

Cheers!

- iPhilip
Windows 7 Pro (64 bit) - AutoHotkey v1.1+ (Unicode 32-bit)

Return to “Tutorials”

Who is online

Users browsing this forum: No registered users and 7 guests