Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Find and Replace Common Dialog Boxes Demonstration Program

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Find and Replace Common Dialog Boxes Demonstration Program

    ' find and replace common dialog boxes demonstration program
    '
    ' your comments and suggestions are most welcome in this link:
    http://www.powerbasic.com/support/pb...ad.php?t=11740
    '
    ' version 1.
    '
    ' this small code illustrates the use of the built-in find and replace
    ' dialog boxes.

    ' from the the win32api help file:
    '
    ' 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.

    ' find
    ' 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.
    '
    ' replace
    ' 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.
    '
    ' 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.

    ' 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.
    '
    ' 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.
    '
    ' thanks to borje hagsten for an inspiring skeleton code in the forum.
    '
    ' best regards,
    '
    ' erik christensen ------- march 24, 2005
    '
    ' p.s. improved markedly march 29 and somewhat april 9, 2005
    '
    ' august 29, 2005: unimportant small 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
    global oldtextproc     as long
    global flgs            as long ' for saving of find or replace flags between calls.
    '
    '
    function openfindorreplacetextdialog (byval hwnd as long, byval ind 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) 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
    '
    '
    ' main callback
    callback function dlgproc() as long
        local res as long
        '
        select case cbmsg
            case %wm_command
                select case cbctlmsg
                    case %bn_clicked
                        select case cbctl
                            case %buttonfind
                                res = openfindorreplacetextdialog(getdlgitem(cbhndl, %textbox1), 1) ' find
                            case %buttonreplace
                                res = openfindorreplacetextdialog(getdlgitem(cbhndl, %textbox1), 2) ' replace
                            case %buttonexit
                                dialog end cbhndl, 0
                        end select
                        '
                end select
                function = 1
                '
            case %wm_destroy
                setwindowlong getdlgitem(cbhndl, %textbox1), %gwl_wndproc, oldtextproc
        end select
    end function
    '
    '
    ' create dialog and controls, etc
    function pbmain () as long
        local txt as string
        '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", 32, 219, 80, 15, _
            %ws_child or %ws_visible or %bs_pushbutton or %ws_tabstop
        control send hform1&,  %buttonfind, %wm_setfont, getstockobject(%system_fixed_font), %true
        control add button, hform1&,  %buttonreplace,  "&replace", 139, 219, 80, 15, _
            %ws_child or %ws_visible or %bs_pushbutton or %ws_tabstop
        control send hform1&,  %buttonreplace, %wm_setfont, getstockobject(%system_fixed_font), %true
        control add button, hform1&,  %buttonexit,  "e&xit", 245, 219, 80, 15, _
            %ws_child or %ws_visible or %bs_pushbutton or %ws_tabstop
        control send hform1&,  %buttonexit, %wm_setfont, getstockobject(%system_fixed_font), %true
        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."
        control add textbox, hform1&,  %textbox1, txt, 32, 27, 293, 180, _
            %ws_child or %ws_visible or %es_multiline or %es_nohidesel  or %ws_vscroll or %ws_tabstop or %es_wantreturn or %es_left or %es_autovscroll, _
            %ws_ex_clientedge
        control send hform1&,  %textbox1, %wm_setfont, getstockobject(%system_fixed_font), %true
        control set focus hform1&, %textbox1
        oldtextproc = setwindowlong(getdlgitem(hform1&, %textbox1), %gwl_wndproc, codeptr(textproc))
        dialog show modal hform1& call dlgproc
    end function
    '
    '
    ' text control subclass
    callback function textproc
        static res as long
        '
        select case cbmsg
            case msgfindreplace  ' this is the message we registered
                ' do actions in response to your input in the dialog box
                function = dofindreplaceaction(cblparam, getparent(cbhndl), %textbox1)
                '
            case %wm_keydown
                if hiwrd(getkeystate(%vk_control)) and cbwparam = 70 then       ' ctrl+f pressed in textbox,
                    res = openfindorreplacetextdialog(cbhndl, 1)                ' so popup find dialog.
                elseif hiwrd(getkeystate(%vk_control)) and cbwparam = 82 then   ' ctrl+r pressed in textbox,
                    res = openfindorreplacetextdialog(cbhndl, 2)                ' so popup replace dialog. textbox needs to have the focus for this to work.
                end if
        end select
        function = callwindowproc(oldtextproc, cbhndl, cbmsg, cbwparam, cblparam)
    end function

    [this message has been edited by erik christensen (edited august 29, 2005).]

  • #2
    ' Find and Replace Common Dialog Boxes Demonstration Program
    '
    ' Version 2.
    '
    ' This version uses SDK coding. No subclassing is needed. A special version
    ' of the message loop is necessary for the code to work satisfactorily.
    ' For this I am grateful for contributions in the Forum by Dominic Mitchell
    ' and Jim Fritts. Thanks very much!
    '
    ' Best regards,
    '
    ' Erik Christensen ------- March 26, 2005
    '
    ' P.S. Improved markedly March 29 and somewhat April 9, 2005
    '
    ' August 29, 2005: Small 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
    GLOBAL H&,W&
    '
    FUNCTION A(BYVAL X1 AS LONG) AS LONG
        FUNCTION = X1 * W / 357
    END FUNCTION
    '
    FUNCTION B(BYVAL Y1 AS LONG) AS LONG
        FUNCTION = Y1 * H / 246
    END FUNCTION
    ' --------------------------------------------------------------------------------
    ' Main entry point for the application
    '
    FUNCTION WINMAIN (BYVAL hInstance     AS LONG, _
                      BYVAL hPrevInstance AS LONG, _
                      BYVAL lpCmdLine     AS ASCIIZ PTR, _
                      BYVAL iCmdShow      AS LONG) AS LONG
    
        LOCAL Msg         AS tagMsg
        LOCAL wclass      AS WndClassEx
        LOCAL szClassName AS ASCIIZ * %MAX_PATH
        LOCAL Caption     AS ASCIIZ * 100
        LOCAL hAccel      AS LONG
        LOCAL rc AS RECT
        ' Register the main application window
        szClassName          = "WINDOWMAIN"
        wclass.cbSize        = SIZEOF(wclass)
        wclass.style         = %CS_HREDRAW OR %CS_VREDRAW
        wclass.lpfnWndProc   = CODEPTR(WndProc)
        wclass.cbClsExtra    = 0
        wclass.cbWndExtra    = 0
        wclass.hInstance     = hInstance
        wclass.hIcon         = LoadIcon(GetModuleHandle(BYVAL 0&), "PROGRAM")
        wclass.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
        wclass.hbrBackground = GetStockObject(%LTGRAY_BRUSH)
        wclass.lpszMenuName  = %NULL
        wclass.lpszClassName = VARPTR(szClassName)
        wclass.hIconSm       = LoadIcon(GetModuleHandle(BYVAL 0&), "PROGRAM")
        RegisterClassEx wclass
    
        ' Adapt window to Work Area on screen (desktop).
        SystemParametersInfo %SPI_GETWORKAREA,BYVAL %NULL, BYVAL VARPTR(rc),BYVAL %NULL
        Caption = "Find and Replace Common Dialogs Demonstration"
        ' Create a window using the registered class
        hForm1& = CreateWindow(szClassName, _     ' Window class name
            Caption, _                            ' Window caption
            %WS_POPUP OR %DS_MODALFRAME OR %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU OR %DS_CENTER, _ ' Window style
            %CW_USEDEFAULT, _                     ' Initial x position
            %CW_USEDEFAULT, _                     ' Initial y position
            (rc.nRight-rc.nLeft)*.7, _            ' Initial x size
            (rc.nBottom-rc.nTop)*.7, _            ' Initial y size
            %HWND_DESKTOP, _                      ' Parent window handle
            BYVAL %NULL, _                        ' Window menu handle
            hInstance, _                          ' Program instance handle
            BYVAL %NULL)                          ' Creation parameters
        '
        'register a message for the find or replace dialog.
        MsgFindReplace = RegisterWindowMessage ("commdlg_FindReplace")
        '
        ' Display the main window
        ShowWindow hForm1, iCmdShow
        UpdateWindow hForm1
        '
        ' 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 very much!
        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
        '
        ' Return the Process Exit code
        FUNCTION = msg.wParam
        '
    END FUNCTION
    '
    '------------------------------------------------------------------------------
    '
    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
    '
    '
    SUB textblock(BYREF txt AS STRING)
        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."
    END SUB
    '
    ' Main callback
    '
    CALLBACK FUNCTION WndProc
        STATIC hButton1  AS DWORD
        STATIC hButton2  AS DWORD
        STATIC hButton3  AS DWORD
        STATIC hEdit1    AS DWORD
        STATIC txt AS STRING
        STATIC Res AS LONG
        STATIC rc AS RECT
        STATIC Flgs AS LONG ' saving find or replace flags between calls.
        '
        SELECT CASE CBMSG
            CASE %WM_CREATE
                GetClientRect CBHNDL, rc : H = rc.nBottom : W = rc.nRight
                hButton1 = CreateWindow("BUTTON","Find  -  Ctrl+F",%WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP _
                    ,A(32),B(219),A(94),B(15),CBHNDL,%BUTTONFIND,GetModuleHandle(""),BYVAL 0)
                hButton2 = CreateWindow("BUTTON","Replace  -  Ctrl+R",%WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP _
                    ,A(132),B(219),A(94),B(15),CBHNDL,%BUTTONREPLACE,GetModuleHandle(""),BYVAL 0)
                hButton3 = CreateWindow("BUTTON","Exit",%WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP _
                    ,A(231),B(219),A(94),B(15),CBHNDL,%BUTTONEXIT,GetModuleHandle(""),BYVAL 0)
                CALL textblock(txt)
                hEdit1 = CreateWindowEx(%WS_EX_CLIENTEDGE,"EDIT","",%WS_CHILD OR %WS_VISIBLE OR %ES_MULTILINE OR %ES_NOHIDESEL  _
                    OR %WS_VSCROLL OR %WS_TABSTOP OR %ES_WANTRETURN OR %ES_LEFT OR %ES_AUTOVSCROLL, _
                    A(32),B(27),A(293),B(180),CBHNDL,%TEXTBOX1,GetModuleHandle(""),BYVAL 0)
                SendMessage hEdit1,%WM_SETFONT,GetStockObject(%SYSTEM_FIXED_FONT),MAKLNG(%TRUE,0)
                Res = SetWindowText(hEdit1, BYVAL STRPTR(txt))
                FUNCTION = 0
                EXIT FUNCTION
                '
            CASE MsgFindReplace ' This is the message registered
                ' Do actions in response to your input in the dialog box
                FUNCTION = DoFindReplaceAction(CBLPARAM, CBHNDL, %TEXTBOX1, Flgs)
                EXIT FUNCTION
                '
            CASE %WM_KEYDOWN
                IF HIWRD(GetKeyState(%VK_CONTROL)) AND CBWPARAM = 70 THEN       ' CTRL+F pressed,
                    hDlgModeless = OpenFindOrReplaceTextDialog(CBHNDL, 1, Flgs)       ' so popup Find dialog.
                ELSEIF HIWRD(GetKeyState(%VK_CONTROL)) AND CBWPARAM = 82 THEN   ' CTRL+R pressed,
                    hDlgModeless = OpenFindOrReplaceTextDialog(CBHNDL, 2, Flgs)       ' so popup Replace dialog.
                END IF
                FUNCTION = 0 : EXIT FUNCTION
                '
            CASE %WM_COMMAND
                SELECT CASE CBCTLMSG
                    CASE %BN_CLICKED
                        SELECT CASE CBCTL
                            CASE %BUTTONFIND
                                hDlgModeless = OpenFindOrReplaceTextDialog(CBHNDL, 1, Flgs) ' find
                            CASE %BUTTONREPLACE
                                hDlgModeless = OpenFindOrReplaceTextDialog(CBHNDL, 2, Flgs) ' replace
                            CASE %BUTTONEXIT
                                PostQuitMessage 0
                        END SELECT
                END SELECT
                FUNCTION = 0
                EXIT FUNCTION
                '
            CASE %WM_DESTROY
                PostQuitMessage 0
                FUNCTION = 0
                EXIT FUNCTION
    
        END SELECT
    
        ' Pass unprocessed messages on to the default handler
        FUNCTION = DefWindowProc(CBHNDL, CBMSG, CBWPARAM, CBLPARAM)
    
    END FUNCTION

    [This message has been edited by Erik Christensen (edited August 29, 2005).]

    Comment


    • #3
      ' Find and Replace Common Dialog Boxes Demonstration Program
      '
      ' 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).]

      Comment

      Working...
      X