How To Use FindText to Enable Searching in a Text Box (267939)
The information in this article applies to:
- Microsoft Visual Basic Professional Edition for Windows 5.0
- Microsoft Visual Basic Professional Edition for Windows 6.0
- Microsoft Visual Basic Enterprise Edition for Windows 5.0
- Microsoft Visual Basic Enterprise Edition for Windows 6.0
This article was previously published under Q267939 SUMMARY
This article shows you how to use the FindText API function to programmatically enable searching in a Text box for the first match.
MORE INFORMATION
The FindText function creates a system-defined, modeless Find dialog box that lets the user specify a string to search for and options to use when searching for text in a document. It has one parameter and returns the handle to the Find dialog box. This parameter is:
- lpfr - pointer to a FINDREPLACE structure that contains information used to initialize the dialog box. For example, if the FR_MATCHCASE value is used for the FLAGS field of the structure, the Find dialog box pops up with an enabled Match Case check box. Such constants can be found in the Text Viewer API function or in COMMDLG.H.
After you get the handle, you can use the GetWindowLong and SetWindowLong functions to change the window procedure of the Find Next button. These functions have two parameters in common:
- hWnd - Handle to the Find dialog box.
- nIndex - Use GWL_WNDPROC here.
SetWindowLong has one additional parameter:
- dwNewLong - The address of the new window procedure.
You write code for the WM_LBUTTONDOWN event in the new window procedure. This event is fired when the user clicks the Find Next button in the Find dialog box. Use the IsDlgButtonChecked function to determine whether the Match Case option is checked. It has two parameters:
- hDlg -- Handle to the Find dialog box.
- nIDButton -- Specifies the identifier of the button control. For Match Case button, the value is 0x411.
To get the pattern string that is to be matched, you can use the GetDlgItemText function API. It has four parameters:
- hWnd -- Handle to the text box in the Find dialog box. You can use the GetDlgItem function to get the value for this parameter.
- nIDDlgItem - Control identifier. This is 0x480.
- lpString - Pointer to the buffer that receives the text.
- nMaxCount - Specifies the maximum number of characters to copy to the buffer, including the NULL character. If the text exceeds this limit, it is truncated.
A global string variable is used here to store the current content of the Text box within which you want to find the matching string. After you find the start position of the first match, you can use the SendMessage API function to highlight the matching string in the Text box. SendMessage has four parameters:
- hWnd - Handle to the Text box.
- Msg - Message to be sent. Use EM_SETSEL here.
- wParam - Start position of the matching string.
- lParam - End position of the matching string.
As to the other messages from WM_LBUTTONDOWN, you can use the previous window procedure to proceed them. You can use the CallWindowProc function here. CallWindowProc has five parameters:
- lpPrevWndFunc - Pointer to the previous window procedure.
- hWnd - Handle to the Find dialog box.
- Msg - Use the same value as what is passed to the new window procedure.
- wParam - Use the same value as what is passed to the new window procedure.
- lParam - Use the same value as what is passed to the new window procedure.
Step-by-Step Example- Start a new Standard EXE project in Visual Basic. Form1 is created by default.
- Add a CommandButton and a TextBox control to Form1.
- Copy the following code to the Code window of Form1:
Private Sub Command1_Click()
Dim szFindString As String ' initial string to find
Dim hCmdBtn As Long ' handle of 'Find Next' command button
Dim strArr() As Byte ' for API use
Dim i As Integer ' position indicator in the loop
' Fill in the structure.
szFindString = "Find Me"
ReDim strArr(0 To Len(szFindString) - 1)
For i = 1 To Len(szFindString)
strArr(i - 1) = Asc(Mid(szFindString, i, 1))
Next i
frText.flags = FR_MATCHCASE Or FR_NOUPDOWN Or FR_NOWHOLEWORD
frText.lpfnHook = 0&
frText.lpTemplateName = 0&
frText.lStructSize = Len(frText)
frText.hwndOwner = Me.hwnd
frText.hInstance = App.hInstance
frText.lpstrFindWhat = VarPtr(strArr(0))
frText.lpstrReplaceWith = 0&
frText.wFindWhatLen = Len(szFindString)
frText.wReplaceWithLen = 0
frText.lCustData = 0
' Show the dialog box.
gHDlg = FindText(frText)
' Get the handle of the dialog box
hCmdBtn = GetDlgItem(gHDlg, 1)
' Get necessary value for calling default window procedure.
gOldDlgWndHandle = GetWindowLong(hCmdBtn, GWL_WNDPROC)
If SetWindowLong(hCmdBtn, GWL_WNDPROC, AddressOf FindTextHookProc) = 0 Then
gOldDlgWndHandle = 0
End If
End Sub
Private Sub Form_Load()
gHTxtWnd = Text1.hwnd
End Sub
Private Sub Text1_Change()
gTxtSrc = Text1.Text
End Sub
- From the Project menu, add a new module to the project and insert the following code:
Public Type FINDREPLACE
lStructSize As Long ' size of this struct 0x20
hwndOwner As Long ' handle to owner's window
hInstance As Long ' instance handle of.EXE that
' contains cust. dlg. template
flags As Long ' one or more of the FR_??
lpstrFindWhat As Long ' ptr. to search string
lpstrReplaceWith As Long ' ptr. to replace string
wFindWhatLen As Integer ' size of find buffer
wReplaceWithLen As Integer ' size of replace buffer
lCustData As Long ' data passed to hook fn.
lpfnHook As Long ' ptr. to hook fn. or NULL
lpTemplateName As Long ' custom template name
End Type
Public Declare Function FindText Lib "comdlg32.dll" Alias "FindTextA" (pFindreplace As FINDREPLACE) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function GetDlgItem Lib "user32" (ByVal hDlg As Long, ByVal nIDDlgItem As Long) As Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function SetFocus Lib "user32" (ByVal hwnd As Long) As Long
Public Declare Function IsDlgButtonChecked Lib "user32" (ByVal hDlg As Long, ByVal nIDButton As Long) As Long
Public Declare Function GetDlgItemText Lib "user32" Alias "GetDlgItemTextA" (ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal lpString As String, ByVal nMaxCount As Long) As Long
Public Const GWL_WNDPROC = (-4)
Public Const WM_LBUTTONDOWN = &H201
Public Const FR_NOMATCHCASE = &H800
Public Const FR_MATCHCASE = &H4
Public Const FR_NOUPDOWN = &H400
Public Const FR_UPDOWN = &H1
Public Const FR_NOWHOLEWORD = &H1000
Public Const FR_WHOLEWORD = &H2
Public Const EM_SETSEL = &HB1
Public Const MaxPatternLen = 50 ' Maximum Pattern Length
Global gOldDlgWndHandle As Long
Global frText As FINDREPLACE
Global gTxtSrc As String
Global gHDlg As Long
Global gHTxtWnd As Long
Function FindTextHookProc(ByVal hDlg As Long, ByVal uMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Dim strPtn As String ' pattern string
Dim hTxtBox As Long ' handle of the text box in dialog box
Dim ptnLen As Integer ' actual length read by GetWindowString
Dim sp As Integer ' start point of matching string
Dim ep As Integer ' end point of matchiing string
Dim ret As Long ' return value for SendMessage
strPtn = Space(MaxPatternLen)
Select Case uMsg
Case WM_LBUTTONDOWN
' Get the pattern string
ptnLen = GetDlgItemText(gHDlg, &H480, strPtn, MaxPatternLen)
' Call default window procedure
If gOldDlgWndHandle <> 0 Then
FindTextHookProc = CallWindowProc(gOldDlgWndHandle, _
hDlg, uMsg, wParam, lParam)
End If
' Customize the winodw procedure
If ptnLen <> 0 Then
strPtn = Left(strPtn, ptnLen)
SetFocus gHTxtWnd
' Get the MatchCase option
If IsDlgButtonChecked(gHDlg, &H411) = 0 Then
sp = InStr(LCase(gTxtSrc), LCase(strPtn))
Else
sp = InStr(gTxtSrc, strPtn)
End If
sp = IIf(sp = 0, -1, sp - 1)
If sp = -1 Then
Call MessageNoFound
End If
ep = Len(strPtn)
ret = SendMessage(gHTxtWnd, EM_SETSEL, sp, sp + ep)
End If
Case Else
' Call the default window procedure
If gOldDlgWndHandle <> 0 Then
FindTextHookProc = CallWindowProc(gOldDlgWndHandle, _
hDlg, uMsg, wParam, lParam)
End If
End Select
End Function
Sub MessageNoFound()
MsgBox "No matches found"
End Sub
- Press the F5 key to run the program. Input any words you like into the Text box and click the CommandButton to show the Find dialog box. Then change the pattern string and click Find Next to highlight the first match in the Text box. If no match is found, a message box appears indicating that the document was searched but no match was found.
Modification Type: | Minor | Last Reviewed: | 7/13/2004 |
---|
Keywords: | kbAPI kbCmnDlgFind kbhowto KB267939 |
---|
|