'
' Version 3.
'
' This version uses DDT coding. A special version of the message loop is
' necessary for the code to work satisfactorily. This also eliminates the
' need for subclassing. A keyboard accelerator array is also implemented.
' Thanks to Borje Hagsten, Semen Matusovski, Dominic Mitchell and Jim Fritts.

'
' Best regards,
'
' Erik Christensen ------- March 27, 2005
'
' P.S. I like this version best.

'
' March 29 and April 9, 2005: Improvements made.
'
' August 29, 2005: Unimportant change made.
Code:
#COMPILE EXE #REGISTER NONE #DIM ALL ' #INCLUDE "WIN32API.INC" #INCLUDE "COMDLG32.INC" ' %TEXTBOX1 = 100 %BUTTONFIND = 105 %BUTTONREPLACE = 110 %BUTTONEXIT = 115 ' GLOBAL hForm1& GLOBAL MsgFindReplace AS LONG GLOBAL hDlgModeless AS LONG ' ' FUNCTION OpenFindOrReplaceTextDialog (BYVAL hWnd AS LONG, BYVAL ind AS LONG, BYVAL Flgs AS LONG) AS LONG STATIC fr AS FINDREPLACE, zTxt AS ASCIIZ * 256, zTxt2 AS ASCIIZ * 256 ' ' The dialog remembers the find-string and replace-string between calls. ' There is no need to set them here. ' fr.lStructSize = SIZEOF(fr) fr.hWndOwner = hWnd fr.hInstance = %NULL ' First time set flags to downward search direction - else to previous values. IF ISTRUE Flgs THEN fr.Flags = Flgs ELSE fr.Flags = %FR_DOWN fr.lpstrFindWhat = VARPTR(zTxt) fr.wFindWhatLen = SIZEOF(zTxt) fr.lpstrReplaceWith = VARPTR(zTxt2) fr.wReplaceWithLen = SIZEOF(zTxt2) fr.lCustData = 0 fr.lpfnHook = %NULL fr.lpTemplateName = %NULL ' IF ind = 1 THEN FUNCTION = FindText(fr) IF ind = 2 THEN FUNCTION = ReplaceText(fr) ' END FUNCTION ' ' FUNCTION DoFindReplaceAction(BYVAL LLPARAM AS LONG,BYVAL hWnd AS LONG, BYVAL id AS LONG, BYREF Flgs AS LONG) AS LONG STATIC txt AS STRING STATIC iPos AS LONG, PrPos AS LONG STATIC Match AS LONG STATIC Sel1 AS LONG, Sel2 AS LONG STATIC PrZt AS STRING STATIC Sta AS LONG STATIC Delim AS STRING STATIC lpPfr AS FINDREPLACE PTR STATIC zt AS ASCIIZ PTR, zt2 AS ASCIIZ PTR Delim = "!""#¤%&/()=?`´|@£${[]}+^¨~*',;.:-_ " ' word delimiting characters. This may be modified if you so wish. lpPfr = LLPARAM IF (@lpPfr.Flags AND %FR_DIALOGTERM) THEN ' Find or replace dialog is closed hDlgModeless = %NULL : FUNCTION = 0 : EXIT FUNCTION END IF Flgs = @lpPfr.Flags ' save flags for next call zt = @lpPfr.lpstrFindWhat ' text to search for zt2 = @lpPfr.lpstrReplaceWith ' replacing text if any CONTROL GET TEXT hWnd, id TO txt ' text to search in CONTROL SEND hWnd, id, %EM_GETSEL, VARPTR(Sel1), VARPTR(Sel2) iPos = Sel1 ' Set position to caret or start of selection if any IF (@lpPfr.Flags AND %FR_FINDNEXT) THEN ' find next IF (UCASE$(MID$(txt,Sel1+1,Sel2-Sel1))=PrZt AND Sel2>Sel1) OR Sel2=LEN(txt) THEN INCR iPos ' Necessary adjustment to prevent from being stuck in the same position. GOSUB Find IF ISTRUE Match THEN CONTROL SEND hWnd, id, %EM_SETSEL, PrPos-1, PrPos + LEN(@zt)-1 CONTROL SEND hWnd, id, %EM_SCROLLCARET,0,0 PrZt = UCASE$(TRIM$(@zt)) ELSE MSGBOX "No match found",%MB_ICONINFORMATION, "Find" END IF ELSEIF (@lpPfr.Flags AND %FR_REPLACE) THEN ' replace GOSUB Find IF ISTRUE Match THEN txt = LEFT$(txt,PrPos-1)+@zt2+MID$(txt,PrPos+LEN(@zt)) ' replace @zt with @zt2 CONTROL SET TEXT hWnd, id, txt ' set changed text in textbox GOSUB Find IF ISTRUE Match THEN CONTROL SEND hWnd, id, %EM_SETSEL, PrPos-1, PrPos + LEN(@zt)-1 CONTROL SEND hWnd, id, %EM_SCROLLCARET,0,0 ELSE MSGBOX "No further match found",%MB_ICONINFORMATION, "Find" END IF ELSE MSGBOX "No match found",%MB_ICONINFORMATION, "Find" END IF ELSEIF (@lpPfr.Flags AND %FR_REPLACEALL) THEN ' replace all GOSUB Find IF ISTRUE Match THEN DO txt = LEFT$(txt,PrPos-1)+@zt2+MID$(txt,PrPos+LEN(@zt)) ' replace @zt with @zt2 GOSUB Find LOOP UNTIL ISFALSE Match ' loop until no more matches CONTROL SET TEXT hWnd, id, txt ' set changed text in textbox CONTROL SEND hWnd, id, %EM_SETSEL, PrPos-1, PrPos+LEN(@zt2)-1 ' select last replacement CONTROL SEND hWnd, id, %EM_SCROLLCARET,0,0 ELSE MSGBOX "No match found",%MB_ICONINFORMATION, "Find" END IF END IF FUNCTION = 1 : EXIT FUNCTION ' Find: ' Subroutine Find ' DO Again: ' Establish search direction - up or down - and start position for INSTR-search. IF (@lpPfr.Flags AND %FR_DOWN) THEN Sta=iPos+1 ELSE Sta=iPos-LEN(txt)-2 IF (@lpPfr.Flags AND %FR_MATCHCASE) THEN ' match case iPos = INSTR(Sta, txt, @zt) ELSE ' no matching of case is necessary iPos = INSTR(Sta, UCASE$(txt), UCASE$(@zt)) END IF IF iPos THEN ' if result IF (@lpPfr.Flags AND %FR_WHOLEWORD) THEN ' check for whole word ' This may seem too simple, but it works - also at the start and end of the text. IF ISTRUE VERIFY(MID$(txt,iPos-1,1),Delim) OR _ ISTRUE VERIFY(MID$(txt,iPos+LEN(@zt),1),Delim) THEN GOTO Again END IF ' Match found - Set previous position for next search Match = %TRUE : PrPos = iPos END IF LOOP UNTIL ISTRUE Match OR ISFALSE iPos ' Match not found - Set pos to previous position IF ISFALSE iPos THEN iPos = PrPos : Match = %FALSE ' RETURN ' END FUNCTION ' ' CALLBACK FUNCTION Form1_DLGPROC STATIC Flgs AS LONG ' saving find or replace flags between calls. ' SELECT CASE CBMSG CASE MsgFindReplace ' This is the message registered ' Do actions in response to your input in the dialog box FUNCTION = DoFindReplaceAction(CBLPARAM, CBHNDL, %TEXTBOX1, Flgs) ' CASE %WM_DESTROY PostQuitMessage 0 ' CASE %WM_COMMAND SELECT CASE CBCTLMSG CASE %BN_CLICKED, 1 ' Accelerator notification codes have CBCTLMSG set to 1. SELECT CASE CBCTL CASE %BUTTONFIND hDlgModeless = OpenFindOrReplaceTextDialog(CBHNDL, 1, Flgs) FUNCTION = 1 CASE %BUTTONREPLACE hDlgModeless = OpenFindOrReplaceTextDialog(CBHNDL, 2, Flgs) FUNCTION = 1 CASE %BUTTONEXIT DIALOG END CBHNDL, 0 FUNCTION = 1 CASE ELSE END SELECT CASE ELSE END SELECT CASE ELSE END SELECT END FUNCTION ' ' ' FUNCTION PBMAIN LOCAL msg AS tagMsg LOCAL hAccel AS LONG LOCAL txt AS STRING DIM ac(0 TO 2) AS ACCELAPI ' Register a message for the find or replace dialog. MsgFindReplace = RegisterWindowMessage ("commdlg_FindReplace") DIALOG NEW 0, "Find and Replace Common Dialogs Demonstration", 0, 0, 357, 246, _ %WS_POPUP OR %DS_MODALFRAME OR %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU OR %DS_CENTER, 0 TO hForm1& CONTROL ADD BUTTON, hForm1&, %BUTTONFIND, "Find - Ctrl+F", 32, 219, 80, 15, _ %WS_CHILD OR %WS_VISIBLE OR %BS_PUSHBUTTON OR %WS_TABSTOP CONTROL ADD BUTTON, hForm1&, %BUTTONREPLACE, "Replace - Ctrl+R", 139, 219, 80, 15, _ %WS_CHILD OR %WS_VISIBLE OR %BS_PUSHBUTTON OR %WS_TABSTOP CONTROL ADD BUTTON, hForm1&, %BUTTONEXIT, "Exit - Alt+X", 245, 219, 80, 15, _ %WS_CHILD OR %WS_VISIBLE OR %BS_PUSHBUTTON OR %WS_TABSTOP ' txt ="Common Dialog Box Library provides a creation function and a structure"+ _ " for each type of common dialog box. To use a common dialog box in its"+ _ " simplest form, you call its creation function and specify a pointer to a"+ _ " structure containing initial values and option flags. After initializing"+ _ " the dialog box, the dialog box procedure uses the structure to return"+ _ " information about the user's input."+ $CRLF+$CRLF+_ "Find"+$CRLF+ _ "Displays a dialog box in which the user can type the string to find. The"+ _ " user can also specify search options, such as the search direction,"+ _ " whether to search for a whole word and whether the search is case"+ _ " sensitive. You create and display a Find dialog box by initializing a"+ _ " FINDREPLACE structure and passing the structure to the FindText function."+$CRLF+$CRLF+ _ "Replace"+$CRLF+ _ "Displays a dialog box in which the user can type the string to find and"+ _ " the replacement string. The user can specify search options, such as"+ _ " whether to search for a whole word and whether the search is case"+ _ " sensitive, and replacement options, such as the scope of replacement."+ _ " You CREATE and display a Replace dialog box by initializing a FINDREPLACE"+ _ " structure and passing the structure to the ReplaceText function."+$CRLF+$CRLF+ _ "Unlike other common dialog boxes, the Find and Replace dialog boxes are"+ _ " modeless. A modeless dialog box allows the user to switch between the"+ _ " dialog box and the window that created it. This is useful for letting the"+ _ " user search for a string, switch to the application window to work on the"+ _ " string, and switch back to the dialog box to search for another string"+ _ " without repeating the command needed to open the dialog box."+ _ " If the FindText or ReplaceText function successfully creates the dialog"+ _ " box, it returns the handle of the dialog box. You can use this handle to"+ _ " move and communicate with the dialog box. If the function cannot create"+ _ " the dialog box, it returns NULL. You can determine the cause of an error"+ _ " by calling the CommDlgExtendedError function to retrieve the extended"+ _ " error value."+$CRLF+$CRLF+ _ "Before creating a Find or Replace dialog box, you must call the"+ _ " RegisterWindowMessage function to get a message identifier for the"+ _ " FINDMSGSTRING registered message. You can then use the identifier to"+ _ " detect and process messages sent from the dialog box. When the user"+ _ " clicks the Find Next, Replace, or Replace All button in a dialog box, the"+ _ " dialog box procedure sends a FINDMSGSTRING message to the window"+ _ " procedure of the owner window. When you create the dialog box, the"+ _ " hwndOwner member of the FINDREPLACE structure identifies the owner"+ _ " window."+$CRLF+$CRLF+ _ "The lParam parameter of a FINDMSGSTRING message is a pointer to the"+ _ " FINDREPLACE structure that you specified when you created the dialog box."+ _ " Before sending the message, the dialog box sets the members of this"+ _ " structure with the latest user input, including the string to search for,"+ _ " the replacement string (if any), and options for the find-and-replace"+ _ " operation." 'txt ="ddddffff" CONTROL ADD TEXTBOX, hForm1&, %TEXTBOX1, txt, 32, 27, 293, 180, _ %WS_CHILD OR %WS_VISIBLE OR %ES_MULTILINE OR %ES_NOHIDESEL OR %ES_WANTRETURN OR %ES_LEFT OR %ES_AUTOVSCROLL OR %WS_VSCROLL OR %WS_TABSTOP, _ %WS_EX_CLIENTEDGE CONTROL SEND hForm1&, %TEXTBOX1, %WM_SETFONT, GetStockObject(%SYSTEM_FIXED_FONT), %TRUE ' ' Attach keyboard accelerators. ac(0).fvirt = %FCONTROL OR %FVIRTKEY ac(0).key = ASC("F") ac(0).cmd = %BUTTONFIND ac(1).fvirt = %FCONTROL OR %FVIRTKEY ac(1).key = ASC("R") ac(1).cmd = %BUTTONREPLACE ac(2).fvirt = %FALT OR %FVIRTKEY ac(2).key = ASC("X") ac(2).cmd = %BUTTONEXIT ACCEL ATTACH hForm1&, ac() TO hAccel ' DIALOG SHOW MODELESS hForm1& , CALL Form1_DLGPROC ' ' Expanded SDK-style main message loop ' Acquire and dispatch messages until a WM_QUIT message is received. ' ' This particular version was originally proposed by Dominic Mitchell - thanks! WHILE ISTRUE GetMessage(msg, BYVAL %NULL, 0, 0) ' IF ISFALSE TranslateMDISysAccel(ghWndClient, msg) THEN IF ISFALSE TranslateAccelerator(hForm1, hAccel, msg) THEN IF ISFALSE IsDialogMessage(hDlgModeless, msg) THEN TranslateMessage msg DispatchMessage msg END IF END IF ' END IF WEND END FUNCTION
[This message has been edited by Erik Christensen (edited August 29, 2005).]
Leave a comment: