Determining the Lines as They Are Being Displayed in a TextBox Control

The TextBoxBase class provides a GetLines method which returns the textbox’ lines which are separated by a new line character sequence. However, textbox controls do not have a built-in method to get the lines as they are being displayed in the control including wrapped lines. This can be achieved using P/Invoke together with the SendMessage function as shown in the listing below. The functionality is encapsulated in the GetTextBoxLines function:

Private Declare Auto Function SendMessage Lib "user32.dll" ( _
    ByVal hwnd As IntPtr, _
    ByVal wMsg As Int32, _
    ByVal wParam As IntPtr, _
    ByVal lParam As String _
) As IntPtr

Private Declare Auto Function SendMessage Lib "user32.dll" ( _
    ByVal hwnd As IntPtr, _
    ByVal wMsg As Int32, _
    ByVal wParam As IntPtr, _
    ByVal lParam As IntPtr _
) As IntPtr

Private Const EM_GETLINE As Int32 = &HC4
Private Const EM_GETLINECOUNT As Int32 = &HBA
Private Const EM_LINEINDEX As Int32 = &HBB
Private Const EM_LINELENGTH As Int32 = &HC1

Private Function GetLine( _
    ByVal TextBox As TextBoxBase, _
    ByVal LineNumber As Integer _
) As String
    Dim dwLineStart As Int32 = _
        SendMessage( _
            TextBox.Handle, _
            EM_LINEINDEX, _
            New IntPtr(LineNumber), _
            IntPtr.Zero _
        ).ToInt32()
    Dim dwLineLen As Integer = _
        SendMessage( _
            TextBox.Handle, _
            EM_LINELENGTH, _
            New IntPtr(dwLineStart), _
            IntPtr.Zero _
        ).ToInt32()
    Dim Line As String = _
        ChrW(dwLineLen) & Space(dwLineLen - 1)
    Dim dwLen As Int32 = _
        SendMessage( _
            TextBox.Handle, _
            EM_GETLINE, _
            New IntPtr(LineNumber), _
            Line _
        ).ToInt32()
    Return Strings.Left(Line, dwLen)
End Function

Private Function GetTextBoxLines(ByVal TextBox As TextBoxBase) As String()
    Dim Max As Int32 = _
        SendMessage( _
            TextBox.Handle, _
            EM_GETLINECOUNT, _
            IntPtr.Zero, _
            IntPtr.Zero _
        ).ToInt32() - 1
    Dim Lines(Max) As String
    For i As Integer = 0 To Max
        Lines(i) = GetLine(TextBox, i)
    Next i
    Return Lines
End Function

The listing below demonstrates how to determine the lines of a richtextbox control and add them to a listbox control:

Me.ListBox1.Items.AddRange(GetTextBoxLines(Me.RichTextBox1))