Visual Basic Text API Routines
SendMessage: Text Selection Methods via API
     
Posted:   Saturday July 18, 1998
Updated:   Monday December 26, 2011
     
Applies to:   VB4-32, VB5, VB6
Developed with:   VB5, Windows 95
OS restrictions:   None
Author:   VBnet - Randy Birch
     

Related:  

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 Range Selection via API
     
 Prerequisites
None.

txselect.gif (9600 bytes)This is a small collection of API methods to both simulate VB's 'SelStart/SelLength' methods and provide new word-processing style functionality.

All use SendMessage to affect the selections within a textbox, but some methods may also apply to the RichTextBox control as the Windows RichEdit and Edit classes share many messages.

 BAS Module Code
None.

 Form Code
Create a simple project like the illustration, with a Multiline textbox and six command buttons (Command1-Command6).  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 = &HB0
Private Const EM_SETSEL = &HB1
Private Const EM_GETLINECOUNT = &HBA
Private Const EM_LINEINDEX = &HBB
Private Const EM_LINELENGTH = &HC1
Private Const EM_LINEFROMCHAR = &HC9


Private Sub Command1_Click()

   'Typically this would be called from
   'a menu item, for example 'Select To Top'
    Dim cursorPos As Long
    On Local Error Resume Next

   'get the character position of the cursor
    Call SendMessage(Text1.hwnd, EM_GETSEL, 0&, cursorPos)

   'select the text from position 0 to the cursor
    Text1.SetFocus
    Call SendMessage(Text1.hwnd, EM_SETSEL, 0, ByVal cursorPos)

End Sub


Private Sub Command2_Click()

   'Typically this would be called from
   'a menu item, for example 'Select To End'
    Dim cursorPos As Long
    Dim lineCount As Long
    Dim ChrsUpToLast As Long
    Dim lastLineLen As Long

    On Local Error Resume Next
   
   'get the cursor position in the textbox
    Call SendMessage(Text1.hwnd, _
                     EM_GETSEL, 0, cursorPos)

   'get the number of lines in the textbox
    lineCount = SendMessage(Text1.hwnd, _
                            EM_GETLINECOUNT, 0, ByVal 0&)
   
   'the number of characters in the textbox,
   'up to but not including the the last line
   '(0-based)
    ChrsUpToLast = SendMessage(Text1.hwnd, _
                               EM_LINEINDEX, _
                               lineCount - 1, ByVal 0&)

   'the number of characters in the last line
    lastLineLen = SendMessage(Text1.hwnd, _
                              EM_LINELENGTH, _
                              lineCount, ByVal 0&)

   'select the text from the cursor
   'position to the last line
    Text1.SetFocus
    Call SendMessage(Text1.hwnd, _
                     EM_SETSEL, _
                     cursorPos, _
                     ByVal ChrsUpToLast + lastLineLen)

End Sub


Private Sub Command3_Click()

   'Typically this would be called from
   'a menu item, for example 'Select To Beginning of Line'
    Dim cursorPos As Long
    Dim currLine As Long
    Dim chrsToCurrent As Long
    On Local Error Resume Next
   
   'get the cursor position in the textbox
    Call SendMessage(Text1.hwnd, _
                     EM_GETSEL, 0, cursorPos)
   
   'get the current line index
    currLine = SendMessage(Text1.hwnd, _
                           EM_LINEFROMCHAR, _
                           cursorPos, _
                           ByVal 0&) ' + 1
   
   'number of chrs up to the current line
    chrsToCurrent = SendMessage(Text1.hwnd, _
                                EM_LINEINDEX, _
                                currLine, ByVal 0&)

   'select from the first chr on the
   'cursor line up to the cursor
    Text1.SetFocus
    Call SendMessage(Text1.hwnd, _
                     EM_SETSEL, _
                     chrsToCurrent, _
                     ByVal cursorPos)

End Sub


Private Sub Command4_Click()

   'Typically this would be called from
   'a menu item, for example 'Select To End of Line'
    Dim cursorPos As Long
    Dim currLine As Long
    Dim chrsToCurrent As Long

    On Local Error Resume Next
   
   'get the cursor position in the textbox
    Call SendMessage(Text1.hwnd, _
                     EM_GETSEL, 0, cursorPos)

   
   'get the current line index
    currLine = SendMessage(Text1.hwnd, EM_LINEFROMCHAR, cursorPos, ByVal 0&)
   
   'number of chrs up to the *next* line
    chrsToCurrent = SendMessage(Text1.hwnd, _
                                EM_LINEINDEX, _
                                currLine + 1, _
                                ByVal 0&)

   'select from the cursor position
   'to the the end of the line, subtracting
   '1 to keep the cursor on the selected line.
    Text1.SetFocus
    Call SendMessage(Text1.hwnd, _
                     EM_SETSEL, _
                     cursorPos, _
                     ByVal chrsToCurrent - 1)

End Sub


Private Sub Command5_Click()

   'Typically this would be called from
   'a menu item, for example 'Select Line'  
    Dim cursorPos As Long
    Dim currLine As Long
    Dim chrsToStart As Long
    Dim chrsToEnd As Long

    On Local Error Resume Next
   
   'get the cursor position in the textbox
    Call SendMessage(Text1.hwnd, _
                     EM_GETSEL, 0, cursorPos)

   'get the current line index
    currLine = SendMessage(Text1.hwnd, _
                           EM_LINEFROMCHAR, _
                           cursorPos, ByVal 0&)
   
   'number of chrs up to the current line
    chrsToStart = SendMessage(Text1.hwnd, _
                              EM_LINEINDEX, _
                              currLine, ByVal 0&)

   'number of chrs up to the next line
    chrsToEnd = SendMessage(Text1.hwnd, _
                            EM_LINEINDEX, _
                            currLine + 1, ByVal 0&)

   'select from the cursor position
   'to the the end of the line. Subtracting
   '1 keeps the cursor on the selected line.
    Text1.SetFocus
    Call SendMessage(Text1.hwnd, _
                     EM_SETSEL, _
                     chrsToStart, _
                     ByVal chrsToEnd - 1)

End Sub


Private Sub Command6_Click()

   Unload Me
   
End Sub
 Comments
The textbox passed to the SendMessage API must have its multiline property set to true at design time.

The EM_GETLINECOUNT message does not pass additional parameters to the API in the wParam or lParam variables. These must be 0.

With EM_LINEINDEX, the value of the wParam parameter specifies the zero-based line number. A value of -1 specifies the current line number (the line that contains the caret). lParam is not used an must be 0.

With EM_LINELENGTH, the value of the wParam parameter specifies the character index of a character in the line whose length is to be retrieved. If this parameter is -1, the message returns the number of unselected characters on lines containing selected characters. lParam is not used and must be 0.

This code is new and reflects the methods used with 32-bit applications. The messages for 16-bit apps was different, requiring data to be packed into a long for passing as a single parameter. The 32-bit code is far less involved.

 
 

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