# Visual Basic > Visual Basic 6 and Earlier >  ITextDocument::GetText - different versions?

## jj2007

Hello everybody,

I need the ITextDocument.GetRange(Int32, Int32) and ITextDocument.GetText(TextGetOptions, String) to retrieve a string from a RichEdit control *without selecting it*.

Point is my C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include\TOM.h looks different. There is the ITextDocumentVtbl, but no GetText; there is, however, GetText in the ITextRangeVtbl. Only that this GetText wants only one argument, no options, and I can't get it to work.

The purpose of my search is to retrieve a string from a RichEdit control *without selecting it*, and *without hidden text*. The EM_GETTEXTRANGE message would be ok, but you can't set any options, so you get the hidden text, too.

Any ideas?

I am using msftedit.dll on Win7-64. I've used various other versions in the past, each having their own bugs and quirks. RichEdit is a horrible mess, and a shame for Microsoft.

----------


## dilettante

I think you are after something that only exists in the WinRT extended API starting in Windows 10.  I don't think it is available to native desktop applications at all, and never in older versions of Windows.

ITextDocument.GetText(TextGetOptions, String) Method
ITextRange.GetText(TextGetOptions, String) Method

----------


## jj2007

Thanks, dilettante. That's what I feared... there are hundreds of TOM methods for this bloody control, but you can't get plain text without hidden text.

Except with EM_GETTEXTEX, but that means you have to *select* the range you want, and even if you use WM_SETREDRAW, your text will jump all over the place when the text is outside the visible screen. RichEdit is driving me mad, with its quirks and serious bugs.

----------


## dilettante

Well here is a brute-force approach:



```
Option Explicit

'Requires a reference to:
'
'   tom (Text Object Model) in RICHED20.dll

Private Const WM_USER As Long = &H400&
Private Const EM_GETOLEINTERFACE As Long = WM_USER + 60

Private Declare Function SendMessage Lib "user32" Alias "SendMessageW" ( _
    ByVal hWnd As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long) As Long

Private TextDocument1 As tom.ITextDocument

Private Sub Form_Load()
    Dim IUnknown As stdole.IUnknown

    With RichTextBox1
        SendMessage .hWnd, EM_GETOLEINTERFACE, 0, VarPtr(IUnknown)
        Set TextDocument1 = IUnknown
        .LoadFile "Sample.rtf", rtfRTF
    End With
End Sub

Private Sub mnuGetit_Click()
    Dim FirstCharPos As Long
    Dim CharPos As Long
    Dim PastLastCharPos As Long
    Dim Hidden As Boolean

    Text2.Text = vbNullString
    With TextDocument1
        .Freeze
        With .Selection.Duplicate
            .Expand tomStory
            Text1.Text = .Text
            PastLastCharPos = .End
            CharPos = FirstCharPos
            Do
                Do
                    .SetRange CharPos, CharPos + 1
                    CharPos = CharPos + 1
                    Hidden = .Font.Hidden = tomTrue
                Loop Until Hidden Or CharPos = PastLastCharPos
                .SetRange FirstCharPos, CharPos - 1
                Text2.SelText = .Text
                If Hidden Then
                    Do
                        .SetRange CharPos, CharPos + 1
                        CharPos = CharPos + 1
                        Hidden = .Font.Hidden = tomTrue
                    Loop Until Not Hidden Or CharPos = PastLastCharPos
                    If Not Hidden Then
                        FirstCharPos = CharPos - 1
                    Else
                        Exit Do
                    End If
                Else
                    Exit Do
                End If
            Loop
        End With
        .Unfreeze
    End With
    mnuGetit.Enabled = False
End Sub
```

I haven't exhaustively tested it though for all combinations (single bit of hidden text, multiples, one at start, one at end, etc.).  It's just an idea: to loop through char by char.

----------


## fafalone

ITextRange::Text should have *no* options. It's a property get. Have you tried using the version in oleexp? You'd declare a String, = ITextRange.Text

But the FormattedText method looks a lot more promising; that's probably what you want.

----------


## dilettante

ITextRange.FormattedText is a Property that returns an ITextRange copy of the text and all markup.  The default property of ITextRange is Text, so that might explain your confusion.

It doesn't do what is being asked for here.  ITextRange.FormattedText.Text will contain any hidden text.

----------


## fafalone

I see.

Shouldn't EM_GETTEXTEXT only require the text to be selected if you use the GT_SELECTION flag? Or has MS helpfully included a deliberately misleading flag.

Also if you're using a newer RichEdit version, ITextRange2::GetText2 has a tomNoHidden flag... but olelib/oleexp don't include the newer interfaces like that yet so you'd have to write your own tlb or direct vtable call equivalent. I started them in the twinBASIC version of oleexp but that one isn't implemented yet there either.

----------

