Extending the TextBox Control
Now, let's go to work, first you have to declare the SendMessage API function:
Public Declare Function SendMessage _ Lib "user32" Alias "SendMessageA" ( _ ByVal hwnd As Long, _ ByVal wMsg As Long, _ ByVal wParam As Long, _ lParam As Any) As Long
You also need to declare the messages you want to send to the textbox. Let's say you want to write a wrapper function that can tell you the index of the first visible line in the textbox. Then you have to declare the following message:
Public Const EM_GETFIRSTVISIBLELINE = &HCE
Now you can go ahead and write the function:
Public Function TopLineIndex(txtBox As TextBox) As Long TopLineIndex = SendMessage(txtBox.hWnd, _ EM_GETFIRSTVISIBLELINE, 0&, 0&) End Function
The EM_GETFIRSTVISIBLELINE message doesn't take any arguments so wParam and lParam must be set to 0 (zero). If you want to use this function on a rich text box instead of the standard textbox then just change the argument type to RichTextBox instead of TextBox in the TopLineIndex function. Remember that the line index is zeroing based i.e. the function returns 0 for the first line, 1 for the second and so on.
A rich text box has a method called GetLineFromChar which returns the line index of the given character indexes. The standard textbox lack such a method though. Let's fix that! You need to use the EM_LINEFROMCHAR message witch is declared in the following manner:
Public Const EM_LINEFROMCHAR = &HC9
The EM_LINEFROMCHAR message takes the index of the character position in the wParam argument.
Public Function GetLineFromChar(txtBox As TextBox, CharPos As Long) As Long GetLineFromChar = SendMessage( _ txtBox.hWnd, EM_LINEFROMCHAR, CharPos, 0&) End Function
So if you want to know what line the text caret is on in a multiline textbox you could call the function in this manner:
Dim lngLineIndex As Long lngLineIndex = GetLineFromChar(Text1, Text1.SelStart) MsgBox "You are on line number " & lngLineIndex + 1
Again remember that the line index is zero based.
You can also do the opposite, finding the index of the first character of a line, with the EM_LINEINDEX message.
Public Const EM_LINEINDEX = &HBB Public Function GetCharFromLine(txtBox As TextBox, LineIndex As Long) As Long GetCharFromLine = SendMessage( _ txtBox.hWnd, EM_LINEINDEX, LineIndex, 0&) End Function
Now that we know how to find out what line we currently standing on wouldn't it be nice to find out how many lined of text there is in the textbox? Well that's easily done if you know of the EM_GETLINECOUNT message. This message doesn't take any arguments so we must pass 0 to wParam and lParam.
Public Const EM_GETLINECOUNT = &HBA Public Function LineCount(txtBox As TextBox) As Long LineCount = SendMessage( _ TxtBox.hWnd, EM_GETLINECOUNT, 0&, 0&) End Function
OK that was simple enough. Let us go on to the next message: EM_LINELENGTH. This message takes a character index in the wParam argument and returns the length of the line which contains that character:
Public Const EM_LINELENGTH = &HC1 Public Function LineLen(txtBox As TextBox, CharPos As Long) As Long LineLen = SendMessage( _ TxtBox.hWnd, EM_LINELEENGTH, CharPos, 0&) End Function
Page 2 of 3
This article was originally published on November 20, 2002