How do I figure out the anchor and active ends of the current selection of a TextBox or RichTextBox?

RobertAlanGustafsonII

Active member
Joined
Sep 16, 2023
Messages
31
Programming Experience
10+
WHAT I HAVE:
Visual Basic 2019, .NET Framework, WinForms

MY ISSUE:
I'd like to be able to programmatically figure out which end of a selection is the anchor and which is the active end when the user changes the selection of a TextBox or RichTextBox. The SelectionStart property is always the left end of a selection, and apparently EM_GETSEL always returns left/right, whereas EM_SETSEL sets anchor/active end. Left always comes before right, but the anchor can be after the active end. This matters if one has to temporarily change, then restore the selection programatically--as the user can thus find oneself extending the selection on the left, then suddenly contracting it on the right for no apparent reason!

The following StackOverflow page provided a supposed "kludge" fix in C++ and Delphi: "EM_GETSEL swaps parameters", but I haven't been able to successfully adapt the code there to VB.NET. The following code below always sets the Active end--and the caret (with no subsequent selection)--to the end of the full text:

Anchor and active ends of selection:
<DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
Public Shared Function SendMessage(hWnd As IntPtr, msg As Integer, ByRef wParam As Integer, _
        ByRef lParam As Integer) As IntPtr
End Function

Public Sub GetEnds(ByRef Anchor As Integer, ByRef Active As Integer)
        '   get anchor and active end of selection
        Const EM_GETSEL = &HB0, EM_SETSEL = &HB1
        Anchor = 0 : Active = 0
        Dim Start As Integer = 0, Finish As Integer = 0
        With TextBoxOrRichTextBox
            '    get ends of selection
            SendMessage(.Handle, EM_GETSEL, Start, Finish)
            '   temporarily kill selection to get active end
            SendMessage(.Handle, EM_SETSEL, -1, 0)
            SendMessage(.Handle, EM_GETSEL, Active, 0)
            '   restore selection and return values
            If Active = Start Then
                Anchor = Finish : SendMessage(.Handle, EM_SETSEL, Finish, Start)
             Else
                Anchor = Start : SendMessage(.Handle, EM_SETSEL, Start, Finish)
            End If
        End With
End Sub

I need a solution quickly. Please respond ASAP--and keep it in VB.NET (that goes without saying here), and as simple as possible.
 
Last edited:
THIS IS THE BEST I CAN DO FOR YOU, IT GIVES YOU AN EXAMPLE TO WORK WITH:
VB.NET:
# Determine Anchor and Active End of Selection

Dim textBox As New RichTextBox()
Dim anchor As Integer
Dim active As Integer

' Assuming the user has made a selection in the RichTextBox
anchor = textBox.SelectionStart
active = textBox.SelectionStart + textBox.SelectionLength

If anchor > active Then
    ' Swap values if anchor is greater than active
    Dim temp As Integer = anchor
    anchor = active
    active = temp
End If

' Now anchor and active represent the correct ends of the selection
 
THIS IS THE BEST I CAN DO FOR YOU, IT GIVES YOU AN EXAMPLE TO WORK WITH:
VB.NET:
# Determine Anchor and Active End of Selection

Dim textBox As New RichTextBox()
Dim anchor As Integer
Dim active As Integer

' Assuming the user has made a selection in the RichTextBox
anchor = textBox.SelectionStart
active = textBox.SelectionStart + textBox.SelectionLength

If anchor > active Then
    ' Swap values if anchor is greater than active
    Dim temp As Integer = anchor
    anchor = active
    active = temp
End If

' Now anchor and active represent the correct ends of the selection

Anchor will never be greater than Active in the above example, because SelectionStart is always the left end of the selection, and SelectionLength is never negative; therefore, the swap will never take place! I provided the link to the StackOverflow article because apparently one has to use a WinAPI hack to figure out whether Anchor is < or > Active, and one needs to use the EM_SETSEL message if one wants to set the Anchor to be > Active. Check out the article and see if there's a flaw in my VB routine which tries to emulate the "kludge".
 
To determine the anchor and active ends of a selection in a TextBox or RichTextBox, access the SelectionStart and SelectionLength properties in control.

Key Changes:​

  1. Initialization: The anchor and active variables are initialized directly upon declaration, which enhances readability and reduces the number of lines of code.
  2. Swap Function: I introduced a Swap function to encapsulate the swapping logic. This not only makes the code cleaner but also adheres to the DRY (Don't Repeat Yourself) principle. By using a separate function, we can easily reuse the swapping logic if needed in the future.
  3. Clarity: The code now clearly indicates its purpose and functionality, making it easier for other developers (or future you) to understand the logic at a glance.
Determine Anchor and Active End of Selection:
' Determine Anchor and Active End of Selection

Dim textBox As New RichTextBox()
Dim anchor As Integer = textBox.SelectionStart
Dim active As Integer = textBox.SelectionStart + textBox.SelectionLength

' Ensure anchor is always less than or equal to active
If anchor > active Then
    Swap(anchor, active)
End If

' Now anchor and active represent the correct ends of the selection

' Function to swap two integers
Private Sub Swap(ByRef first As Integer, ByRef second As Integer)
    Dim temp As Integer = first
    first = second
    second = temp
End Sub
 
Back
Top