Visual Basic Text API Routines
SendMessage: Text Range Selection via API
Posted:   Sunday September 13, 1998
Updated:   Monday December 26, 2011
Applies to:   VB4-32, VB5, VB6
Developed with:   VB5, Windows 98
OS restrictions:   None
Author:   VBnet - Randy Birch


SendMessage: Determine the Current Line in a Text Box
SendMessage: Determine the Number of Lines in a Text Box
SendMessage: Find Text Box Document Size via API
SendMessage: Text Selection Methods via API

txselectrange.gif (10152 bytes)Using the API, it is easy to specify a line range in a textbox for copying to another control or a string.
 BAS Module Code

 Form Code
Create a simple project like the illustration, with a two multiline textboxes (text1, Text2), two combo's (Combo1, Combo2), a check box (Check1) and a command button (Command1). Add two labels (label1, Label2) to show the selected character range. The frame and other labels are optional. Add the following to the form:

Option Explicit
' Copyright 1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
Private Declare Function SendMessage Lib "user32" _
    Alias "SendMessageA" _
   (ByVal hwnd As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    lParam As Any) As Long

Private Const EM_GETSEL  As Long = &HB0
Private Const EM_SETSEL  As Long = &HB1
Private Const EM_GETLINECOUNT  As Long = &HBA
Private Const EM_LINEINDEX  As Long = &HBB
Private Const EM_LINELENGTH  As Long = &HC1
Private Const EM_LINEFROMCHAR  As Long = &HC9
Private Const EM_SCROLLCARET As Long = &HB7
Private Const WM_SETREDRAW  As Long = &HB

Private Sub Form_Load()

   Dim fno As Integer
   Dim fname As String
   Dim cnt As Integer
   Dim lineCount As Long
  'obtain the next free file handle
  'from the system
   fno = FreeFile
   fname = "test.txt"

  'load the file into the textbox
   Open fname For Input As #fno
       Text1.Text = Input$(LOF(fno), fno)
   Close #fno
  'get the number of lines in the textbox
  'and add the lines to the combos
   lineCount = SendMessage(Text1.hwnd, _
                           EM_GETLINECOUNT, 0, ByVal 0&)
   For cnt = 1 To lineCount
      Combo1.AddItem cnt
      Combo2.AddItem cnt
   Combo1.ListIndex = 0
   Combo2.ListIndex = 1

   Me.Move (Screen.Width - Me.Width) \ 2, (Screen.Height - Me.Height) \ 2
End Sub

Private Sub Combo1_Click()

   Dim x As Integer
   Dim y As Integer
   x = Val(Combo1.ListIndex)
   y = Val(Combo2.ListIndex)
  'should the start be greater than the end, 
  'set the end combo to the same value. 
   If x > y Then
      Combo2.ListIndex = x
   End If
End Sub

Private Sub Command1_Click()

   Dim startLine As Long
   Dim endLine As Long
  'set the start and end lines to
  'the combo selections
   startLine = Val(Combo1.List(Combo1.ListIndex))
   endLine = Val(Combo2.List(Combo2.ListIndex))
  'assign the result of the function to Text2
   Text2.Text = GetBlockText(Text1, startLine, endLine)

End Sub

Private Function GetBlockText(ctl As TextBox, _
                              passedLineStart As Long, _
                              passedLineEnd As Long) As String

  ' ctl: control to act on (ie Text1 or Form3.Text1).  
  ' This allows the routine to deal with any control 
  ' passed, or (with the API declarations) to be moved 
  ' into a BAS module for general use.
  ' passedLineStart: first line (1-based) to select.
  '                  Passing <=0 defaults to start.
  ' passedLineEnd: last line (1-based) to select.
  '                  Passing > linecount defaults to all text.
  ' string of selected text
  ' - "transparent" mode (Check1) - no visible action to user
  ' - by returning an assignment of passedLineStart = copyStart
  '   and passedLineEnd = copyEnd, you can return the character
  '   positions for use in labels etc. (see "Debug" below)
   Dim copyStart As Long
   Dim copyEnd As Long
   Dim currLine As Long
   Dim lineCount As Long
   Dim success As Long
   Dim currCursorPos As Long

  'optional: used to start transparent action
   If Check1.Value = 1 Then
      currCursorPos = ctl.SelStart
      Call SendMessage(ctl.hwnd, WM_SETREDRAW, False, ByVal 0&)
   End If

  'get the number of lines in the textbox
   lineCount = SendMessage(ctl.hwnd, EM_GETLINECOUNT, 0, ByVal 0&)
  'the control lines are 0-based, but we're making it
  'more friendly by allowing 1-based numbers to be passed,
  'so subtract 1 from the start number.
  'Nothing is subtracted from the end number
  'because we want the end line + its contents
  '(IOW, the specified line -1 + Len(specified line) )
  'to be selected.
  'The If statement below takes care of specifying
  'a line index larger than the actual number of
  'lines available. It is required.
   passedLineStart = passedLineStart - 1
  'proceeding only if there are lines to work with
   If lineCount > 0 Then
     'if the startline greater than 0
      If passedLineStart > 0 Then
        'get the number of chrs up to the 
        'end of the desired start line
         copyStart = SendMessage(ctl.hwnd, _
                                 EM_LINEINDEX, _
                                 passedLineStart, ByVal 0&)
      Else 'start at the beginning
            'of the textbox
             copyStart = 0
      End If
     'if the lastline greater than 0 and
     'less then the number of lines in the
      If passedLineEnd > 0 And _
         passedLineEnd <= lineCount Then
         '..get the number of chrs up to the 
         'end of the desired last line
          copyEnd = SendMessage(ctl.hwnd, _
                                EM_LINEINDEX, _
                                passedLineEnd, ByVal 0&)
      Else 'copy the whole thing
             copyEnd = Len(ctl)
      End If
     'Set the selection for the returned range.
     'This will return -1 if unsuccessful
      success = SendMessage(ctl.hwnd, _
                            EM_SETSEL, _
                            copyStart, _
                            ByVal copyEnd)
      If success <> -1 Then
        'return the selected text
         GetBlockText = ctl.SelText
      End If
   End If

  'optional: used to end transparent action
   If Check1.Value = 1 Then
      ctl.SelStart = currCursorPos
      Call SendMessage(ctl.hwnd, WM_SETREDRAW, True, ByVal 0&)
     'scroll the selected item into view
      Call SendMessage(ctl.hwnd, EM_SCROLLCARET, 0, ByVal 0)
   End If

  'debug only
   Label1.Caption = "start: " & copyStart
   Label2.Caption = "end: " & copyEnd

End Function

Private Sub Text1_GotFocus()

   Command2.Enabled = False

End Sub

Private Sub Text1_LostFocus()

   Command2.Enabled = True

End Sub
The routine loads a text file from disk .. in my example I just copied a few paragraphs from a KB article and saved to the project folder.

Once the file is in place, run the app. The file should load into Text1. Select a line range from the combo boxes and press Select; the selected range is displayed in Text2. Activating the Hide Action check will perform the same function, but the action (selection and scrolling of the textbox) will be transparent to the user.


PayPal Link
Make payments with PayPal - it's fast, free and secure!


Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy


Hit Counter