Rozdział XXXIV - RichEdit: Operacje tekstowe


Na tej lekcji dowiesz się więcej o operacjach tekstowych wykonywanych w kontrolce RichEdit. Zajmiemy się szczególnie wyszukiwaniem i zamianą tekstu oraz przechodzeniem do wybranego numeru wiersza.

 

 

Załaduj {ten przykład}

 

Teoria

Wyszukiwanie tekstu

Istnieje kilka operacji tekstowych, które może wykonywać kontrolka RichEdit. Wyszukiwanie tekstu jest jedną z nich. Wykonuje się je wysyłając wiadomości EM_FINDTEXT lub EM_FINDTEXTEX. Te wiadomości nieco się różnią między sobą.

 

Wiadomość EM_FINDTEXT
wParam Opcje poszukiwań. Może to być dowolna kombinacja poniższych znaczników, które są identyczne zarówno dla EM_FINDTEXT jak i dla EM_FINDTEXTEX:
  • FR_DOWN - jeśli zostanie określony, to wyszukiwanie rozpoczyna się od końca bieżącego zaznaczenia do końca tekstu w kontrolce (w dół). Znacznik ten działa jedynie w kontrolce RichEdit od wersji 2.0. Działanie takie jest standardowe dla RichEdit 1.0. Standardowo od wersji 2.0 kontrolki RichEdit przeszukują tekst od końca bieżącego zaznaczenia do początku tekstu (w górę). Podsumowując, jeśli korzystasz z RichEdit 1.0, to nie możesz zmieniać kierunku przeszukiwań, który zawsze będzie w dół. Jeśli korzystasz z RichEdit 2.0 i chcesz wyszukiwać w dół, to musisz określić ten znacznik, inaczej kontrolka będzie wyszukiwała tekst w górę.
  • FR_MATCHCASE - jeśli zostanie określony, to poszukiwanie rozróżnia wielkość liter.
  • FR_WHOLEWORD - jeśli ustawiony, to wyszukiwane są pełne słowa, które pasują do poszukiwanego łańcucha tekstu.

Istnieje jeszcze kilka innych znaczników, lecz mają one znaczenie jedynie dla języków innych niż angielski.

lParam Wskazuje strukturę FINDTEXT

FINDTEXT STRUCT   chrg      CHARRANGE <>   lpstrText DWORD ?FINDTEXT ENDS
  • chrg jest strukturą CHARRANGE zdefiniowaną następująco:
CHARRANGE STRUCT    cpMin DWORD ?    cpMax DWORD ?CHARRANGE ENDS
    • cpMin zawiera indeks pierwszego znaku w zakresie
    • cpMax zawiera indeks znaku bezpośrednio za ostatnim znakiem w zakresie.Aby szukać tekstu, musisz określić zakres poszukiwań. Znaczenie cpMin i cpMax różni się w zależności, czy poszukiwanie odbywa się w dół czy w górę. Jeśli poszukiwanie odbywa się w dół, cpMin określa początkowy indeks znaku do przeszukania, a cpMax indeks końcowy. Jeśli poszukiwanie odbywa się w górę, to obowiązuje zasada odwrotna, tj. cpMin zawiera końcowy indeks, a cpMax początkowy.
  • lpstrText jest wskazaniem poszukiwanego łańcucha znaków.
Wiadomość EM_FINDTEXT zwraca indeks pozycji pierwszego znaku poszukiwanego tekstu w kontrolce RichEdit. Jeśli tekst nie został odnaleziony, zwracana jest wartość -1.

 

Wiadomość EM_FINDTEXTEX
wParam Opcje poszukiwań takie same jak w EM_FINDTEXT.
lParam Wskazuje strukturę FINDTEXTEX

FINDTEXTEX STRUCT
    chrg      CHARRANGE <>
    lpstrText DWORD ?
    chrgText  CHARRANGE <>
FINDTEXTEX ENDS

    

Pierwsze dwa pola struktury FINDTEXTEX są identyczne z FINDTEXT. Pole chrgText jest strukturą CHARRANGE, która zostanie wypełniona początkowym i końcowym indeksem, jeśli zostanie znaleziony w kontrolce poszukiwany łańcuch znaków.

Wartość zwrotna EM_FINDTEXTEX jest identyczna z wartością zwrotną EM_FINDTEXT.

 

Różnica pomiędzy wiadomościami EM_FINDTEXT a EM_FINDTEXTEX jest taka, iż struktura FINDTEXTEX posiada dodatkowe pole. chrgText, które zostanie wypełnione w razie odszukania tekstu jego początkowym i końcowym indeksem w kontrolce RichEdit. Jest to wygodne, gdy chcemy przeprowadzić na tym łańcuchu tekstu więcej operacji tekstowych.

 

Zamiana/wstawianie Tekstu

Kontrolka RichEdit udostępnia wiadomość EM_SETTEXTEX do zamiany lub wstawiania tekstu. Wiadomość ta łączy w sobie operacje wykonywane przez wiadomości WM_SETTEXT i EM_REPLACESEL. Posiada ona następującą składnię:

 

Wiadomość EM_SETTEXTEX
wParam Wskazanie struktury SETTEXTEX

SETTEXTEX STRUCT
    flags    DWORD ?
    codepage DWORD ?
SETTEXTEX ENDS
  • flags może być kombinacją następujących znaczników:
    • ST_DEFAULT - czyści stos cofnięć, usuwa formatowanie, zastępuje cały tekst
    • ST_KEEPUNDO - utrzymuje stos cofnięć
    • ST_SELECTION - zastępuje zaznaczenie i utrzymuje formatowanie
  • codepage jest stałą określającą stronę kodową dla tekstu. Zwykle po prostu stosujemy CP_ACP.
lParam Wskazuje tekst zakończony zerem, który ma zostać wstawiony. Tekst jest łańcuchem ANSI o ile strona kodowa nie ma numeru 1200 (Unicode). W takim przypadku jest to łańcuch Unicode.
Jeśli operacja ustawia cały tekst i się powiodła, zwracana jest wartość 1.Jeśli operacja ustawia zaznaczenie i się powiodła, wartość zwrotna jest liczbą skopiowanych znaków.Jeśli operacja się nie powiedzie, zwracana jest wartość 0

 

Zaznaczanie Tekstu

Można programowo zaznaczać tekst za pomocą wiadomości EM_SETSEL lub EM_EXSETSEL. Każda z nich nadaje się doskonale do tego celu. Wybór zależy od dostępnego formatu indeksów znakowych. Jeśli są one już umieszczone w strukturze CHARRANGE, to łatwiej będzie zastosować wiadomość EM_EXSETSEL.

 

Wiadomość EM_EXSETSEL
wParam Nie używane. Musi mieć wartość 0.
lParam Wskazanie struktury CHARRANGE, która zawiera zakres znaków do zaznaczenia.

 

Powiadamianie o Zdarzeniach

W przypadku wielowierszowej kontrolki edycyjnej należy przejąć jej procedurę okna, aby odbierać wiadomości o zdarzeniach myszki czy klawiatury. Kontrolka RichEdit posiada lepszą konstrukcję, która umożliwia jej powiadamianie okna nadrzędnego o takich zdarzeniach. Aby zarejestrować się do pobierania powiadomień, okno nadrzędne wysyła do kontrolki RichEdit wiadomość EM_SETEVENTMASK, która określa interesujące je zdarzenia. Wiadomość ta ma następującą składnię:

 

Wiadomość EM_SETEVENTMASK
wParam Nie używane. Musi mieć wartość 0.
lParam Wartość maski dla filtrowania zdarzeń. Może być dowolną kombinacją wymienionych poniżej znaczników:
  • ENM_CHANGE- wysyła powiadomienia EN_CHANGE
  • ENM_CORRECTTEXT - wysyła powiadomienia EN_CORRECTTEXT
  • ENM_DRAGDROPDONE - wysyła powiadomienia EN_DRAGDROPDONE
  • ENM_DROPFILES - wysyła powiadomienia EN_DROPFILES
  • ENM_KEYEVENTS- wysyła powiadomienia EN_MSGFILTER dla zdarzeń klawiatury
  • ENM_LINK - od wersji RichEdit 2.0: Wysyła powiadomienia EN_LINK, gdy kursor myszki znajduje się ponad tekstem z ustawionym znacznikiem CFE_LINK i wykonywane są operacje myszką
  • ENM_MOUSEEVENTS - wysyła powiadomienia EN_MSGFILTER dla zdarzeń myszki
  • ENM_OBJECTPOSITIONS - wysyła powiadomienia EN_OBJECTPOSITIONS
  • ENM_PROTECTED - wysyła powiadomienia EN_PROTECTED
  • ENM_REQUESTRESIZE - wysyła powiadomienia EN_REQUESTRESIZE
  • ENM_SCROLL - wysyła powiadomienia EN_HSCROLL i EN_VSCROLL
  • ENM_SCROLLEVENTS - wysyła powiadomienia EN_MSGFILTER dla zdarzeń kółka myszki
  • ENM_SELCHANGE - wysyła powiadomienia EN_SELCHANGE
  • ENM_UPDATE - wysyła powiadomienia EN_UPDATE. Od wersji RichEdit 2.0 znacznik ten jest ignorowany, a powiadomienia EN_UPDATE są wysyłane zawsze. Jednakże, gdy kontrolka RichEdit 3.0 emuluje RichEdit 1.0, musisz użyć tego znacznika w celu ustawienia wysyłania powiadomień EN_UPDATE

 

Wszystkie powyższe powiadomienia zostaną wysłane jako wiadomość WM_NOTIFY: należy sprawdzić pole code struktury NMHDR w celu pobrania wiadomości powiadomienia. Na przykład, jeśli chcesz rejestrować zdarzenia myszki (np. chcesz udostępnić wyskakujące menu kontekstowe), musisz wykonać coś w tym rodzaju:

 

    INVOKE SendMessage, hwndRichEdit, EM_SETEVENTMASK, 0,
                        ENM_MOUSEEVENTS
    ...
WndProc PROC hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
    ...
    ...
    .ELSEIF uMsg==WM_NOTIFY
        push esi
        mov  esi, lParam

ASSUME esi: PTR NMHDR

        .IF [esi].code==EN_MSGFILTER
            ...
            [ tutaj sobie coś robisz ]
            ...
        .ENDIF

ASSUME esi: NOTHING

        pop esi
        ...

Przykład

Poniższy przykład programu jest uaktualnieniem edytora IczEdit z lekcji XXXIII. Dodaje on operacje wyszukiwania i zastępowania tekstu oraz klawisze skrótów. Przetwarza również zdarzenia myszki i udostępnia wyskakujące menu kontekstowe po kliknięciu prawym przyciskiem myszki w obrębie kontrolki RichEdit.

Plik ICZEDIT.ASM

 

.386

.MODEL FLAT, STDCALL

OPTION CASEMAP:NONE

INCLUDE    \masm32\include\windows.inc
INCLUDE    \masm32\include\user32.inc
INCLUDE    \masm32\include\comdlg32.inc
INCLUDE    \masm32\include\gdi32.inc
INCLUDE    \masm32\include\kernel32.inc
INCLUDELIB \masm32\lib\gdi32.lib
INCLUDELIB \masm32\lib\comdlg32.lib
INCLUDELIB \masm32\lib\user32.lib
INCLUDELIB \masm32\lib\kernel32.lib

WinMain PROTO :DWORD, :DWORD, :DWORD, :DWORD

.CONST

IDR_MAINMENU     EQU   101
IDD_OPTIONDLG    EQU   101
IDD_FINDDLG      EQU   102
IDD_GOTODLG      EQU   103
IDD_REPLACEDLG   EQU   104
IDR_MAINACCEL    EQU   105

RichEditID       EQU   300

IDC_BACKCOLORBOX EQU  1000
IDC_TEXTCOLORBOX EQU  1001
IDC_FINDEDIT     EQU  1000
IDC_MATCHCASE    EQU  1001
IDC_REPLACEEDIT  EQU  1001
IDC_WHOLEWORD    EQU  1002
IDC_DOWN         EQU  1003
IDC_UP           EQU  1004
IDC_LINENO       EQU  1005

IDM_OPEN         EQU 40001
IDM_SAVE         EQU 40002
IDM_CLOSE        EQU 40003
IDM_SAVEAS       EQU 40004
IDM_EXIT         EQU 40005
IDM_COPY         EQU 40006
IDM_CUT          EQU 40007
IDM_PASTE        EQU 40008
IDM_DELETE       EQU 40009
IDM_SELECTALL    EQU 40010
IDM_OPTION       EQU 40011
IDM_UNDO         EQU 40012
IDM_REDO         EQU 40013
IDM_FIND         EQU 40014
IDM_FINDNEXT     EQU 40015
IDM_REPLACE      EQU 40016
IDM_GOTOLINE     EQU 40017
IDM_FINDPREV     EQU 40018

.DATA

ClassName       DB "IczEditClass", 0
AppName         DB "IczEdit wersja 2.0", 0
RichEditDLL     DB "riched20.dll", 0
RichEditClass   DB "RichEdit20A", 0
NoRichEdit      DB "Nie można odnaleźć biblioteki riched20.dll", 0
ASMFilterString DB "Kod źródłowy ASM (*.asm)", 0, "*.asm", 0,
                   "Wszystkie pliki (*.*)", 0, "*.*", 0, 0
OpenFileFail    DB "Nie można otworzyć pliku", 0
WannaSave       DB "Dane w edytorze zostały zmodyfikowane. Zapisać je?", 0
FileOpened      DD FALSE
BackgroundColor DD 0FFFFFFh ; standardowy kolor tła - biały
TextColor       DD 0        ; standardowy kolor tekstu - czarny
hSearch         DD ?        ; uchwyt okna dialogowego wyszukiwania/zamiany
hAccel          DD ?

.DATA?

hInstance         DD ?
hRichEdit         DD ?
hwndRichEdit      DD ?
FileName          DB 256 DUP(?)
AlternateFileName DB 256 DUP(?)
CustomColors      DD  16 DUP(?)
FindBuffer        DB 256 DUP(?)
ReplaceBuffer     DB 256 DUP(?)
uFlags            DD ?
findtext          FINDTEXTEX <>

.CODE

start:

    mov    BYTE PTR [FindBuffer], 0
    mov    BYTE PTR [ReplaceBuffer], 0
    INVOKE GetModuleHandle, NULL
    mov    hInstance, eax
    INVOKE LoadLibrary, ADDR RichEditDLL
    .IF eax!=0
        mov       hRichEdit, eax
        INVOKE WinMain, hInstance, 0, 0, SW_SHOWDEFAULT
        INVOKE FreeLibrary, hRichEdit
    .ELSE
        INVOKE MessageBox, 0, ADDR NoRichEdit, ADDR AppName,
                           MB_OK OR MB_ICONERROR
    .ENDIF
    INVOKE ExitProcess, eax
   
WinMain PROC hInst:DWORD, hPrevInst:DWORD, CmdLine:DWORD, CmdShow:DWORD

LOCAL wc   : WNDCLASSEX
LOCAL msg  : MSG
LOCAL hwnd : DWORD

    mov    wc.cbSize, SIZEOF WNDCLASSEX
    mov    wc.style, CS_HREDRAW OR CS_VREDRAW
    mov    wc.lpfnWndProc, OFFSET WndProc
    mov    wc.cbClsExtra, NULL
    mov    wc.cbWndExtra, NULL
    push   hInst
    pop    wc.hInstance
    mov    wc.hbrBackground, COLOR_WINDOW+1
    mov    wc.lpszMenuName, IDR_MAINMENU
    mov    wc.lpszClassName, OFFSET ClassName
    INVOKE LoadIcon, NULL, IDI_APPLICATION
    mov    wc.hIcon, eax
    mov    wc.hIconSm, eax
    INVOKE LoadCursor, NULL, IDC_ARROW
    mov    wc.hCursor, eax
    INVOKE RegisterClassEx, ADDR wc
    INVOKE CreateWindowEx, NULL, ADDR ClassName, ADDR AppName,
                           WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
                           CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                           NULL, NULL, hInst, NULL
    mov    hwnd, eax
    INVOKE ShowWindow, hwnd, SW_SHOWNORMAL
    INVOKE UpdateWindow, hwnd
    INVOKE LoadAccelerators, hInstance, IDR_MAINACCEL
    mov    hAccel, eax

    .WHILE TRUE
        INVOKE GetMessage, ADDR msg, 0, 0, 0
        .BREAK .IF (!eax)
        INVOKE IsDialogMessage, hSearch, ADDR msg
        .IF eax==FALSE
            INVOKE TranslateAccelerator, hwnd, hAccel, ADDR msg
            .IF eax==0
                INVOKE TranslateMessage, ADDR msg
                INVOKE DispatchMessage, ADDR msg
            .ENDIF
        .ENDIF
    .ENDW

    mov eax, msg.wParam
    ret

WinMain ENDP

StreamInProc PROC hFile:      DWORD,
                  pBuffer:    DWORD,
                  NumBytes:   DWORD,
                  pBytesRead: DWORD

    INVOKE ReadFile, hFile, pBuffer, NumBytes, pBytesRead, 0
    xor    eax, 1
    ret

StreamInProc ENDP

StreamOutProc PROC hFile:         DWORD,
                   pBuffer:       DWORD,
                   NumBytes:      DWORD,
                   pBytesWritten: DWORD

    INVOKE WriteFile, hFile, pBuffer, NumBytes, pBytesWritten, 0
    xor    eax, 1
    ret

StreamOutProc ENDP

CheckModifyState PROC hWnd:DWORD

    INVOKE SendMessage, hwndRichEdit, EM_GETMODIFY, 0, 0
    .IF eax!=0
        INVOKE MessageBox, hWnd, ADDR WannaSave, ADDR AppName,
                           MB_YESNOCANCEL
        .IF eax==IDYES
            INVOKE SendMessage, hWnd, WM_COMMAND, IDM_SAVE, 0
        .ELSEIF eax==IDCANCEL
            mov eax, FALSE
            ret
        .ENDIF
    .ENDIF
    mov eax, TRUE
    ret

CheckModifyState ENDP

SetColor PROC

LOCAL cfm: CHARFORMAT

    INVOKE SendMessage, hwndRichEdit, EM_SETBKGNDCOLOR, 0, BackgroundColor
    INVOKE RtlZeroMemory, ADDR cfm, SIZEOF cfm
    mov    cfm.cbSize, SIZEOF cfm
    mov    cfm.dwMask, CFM_COLOR
    push   TextColor
    pop    cfm.crTextColor
    INVOKE SendMessage, hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, ADDR cfm
    ret

SetColor ENDP

OptionProc PROC hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

LOCAL clr:CHOOSECOLOR

    .IF uMsg==WM_INITDIALOG
    .ELSEIF uMsg==WM_COMMAND
        mov ax, WORD PTR wParam + 2
        .IF ax==BN_CLICKED
            mov eax, wParam
            .IF ax==IDCANCEL
                INVOKE SendMessage, hWnd, WM_CLOSE, 0, 0
            .ELSEIF ax==IDC_BACKCOLORBOX
                INVOKE RtlZeroMemory, ADDR clr, SIZEOF clr
                mov    clr.lStructSize, SIZEOF clr
                push   hWnd
                pop    clr.hwndOwner
                push   hInstance
                pop    clr.hInstance
                push   BackgroundColor
                pop    clr.rgbResult
                mov    clr.lpCustColors, OFFSET CustomColors
                mov    clr.Flags, CC_ANYCOLOR OR CC_RGBINIT
                INVOKE ChooseColor, ADDR clr
                .IF eax!=0
                    push   clr.rgbResult
                    pop    BackgroundColor
                    INVOKE GetDlgItem, hWnd, IDC_BACKCOLORBOX
                    INVOKE InvalidateRect, eax, 0, TRUE
                .ENDIF
            .ELSEIF ax==IDC_TEXTCOLORBOX
                INVOKE RtlZeroMemory, ADDR clr, SIZEOF clr
                mov    clr.lStructSize, SIZEOF clr
                push   hWnd
                pop    clr.hwndOwner
                push   hInstance
                pop    clr.hInstance
                push   TextColor
                pop    clr.rgbResult
                mov    clr.lpCustColors, OFFSET CustomColors
                mov    clr.Flags, CC_ANYCOLOR OR CC_RGBINIT
                INVOKE ChooseColor, ADDR clr
                .IF eax!=0
                    push   clr.rgbResult
                    pop    TextColor
                    INVOKE GetDlgItem, hWnd, IDC_TEXTCOLORBOX
                    INVOKE InvalidateRect, eax, 0, TRUE
                .ENDIF
            .ELSEIF ax==IDOK

; Zachowujemy znacznik modyfikacji kontrolki RichEdit, ponieważ
; zmiana tekstu powoduje również zmianę tego znacznika

                INVOKE SendMessage, hwndRichEdit, EM_GETMODIFY, 0, 0
                push   eax
                INVOKE SetColor
                pop    eax
                INVOKE SendMessage, hwndRichEdit, EM_SETMODIFY, eax, 0
                INVOKE EndDialog, hWnd, 0
            .ENDIF
        .ENDIF
    .ELSEIF uMsg==WM_CTLCOLORSTATIC
        INVOKE GetDlgItem, hWnd, IDC_BACKCOLORBOX
        .IF eax==lParam
            INVOKE CreateSolidBrush, BackgroundColor           
            ret
        .ELSE
            INVOKE GetDlgItem, hWnd, IDC_TEXTCOLORBOX
            .IF eax==lParam
                INVOKE CreateSolidBrush, TextColor
                ret
            .ENDIF
        .ENDIF
        mov eax, FALSE
        ret
    .ELSEIF uMsg==WM_CLOSE
        INVOKE EndDialog, hWnd, 0
    .ELSE
        mov eax, FALSE
        ret
    .ENDIF
    mov eax, TRUE
    ret

OptionProc ENDP

SearchProc PROC hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

    .IF uMsg==WM_INITDIALOG
        push   hWnd
        pop    hSearch

; Wybierama standardowo opcję szukania w dół

        INVOKE CheckRadioButton, hWnd, IDC_DOWN, IDC_UP, IDC_DOWN
        INVOKE SendDlgItemMessage, hWnd, IDC_FINDEDIT, WM_SETTEXT,
                                   0, ADDR FindBuffer
    .ELSEIF uMsg==WM_COMMAND
        mov ax, WORD PTR wParam + 2
        .IF ax==BN_CLICKED
            mov eax, wParam
            .IF ax==IDOK
                INVOKE SendMessage, hwndRichEdit, EM_EXGETSEL, 0,
                                    ADDR findtext.chrg
                INVOKE GetDlgItemText, hWnd, IDC_FINDEDIT,
                                       ADDR FindBuffer, SIZEOF FindBuffer
                .IF eax!=0
                    INVOKE IsDlgButtonChecked, hWnd, IDC_DOWN
                    .IF eax==BST_CHECKED
                        or   uFlags, FR_DOWN
                        mov eax, findtext.chrg.cpMin
                        .IF eax!=findtext.chrg.cpMax
                            push findtext.chrg.cpMax
                            pop  findtext.chrg.cpMin
                        .ENDIF
                        mov findtext.chrg.cpMax, -1
                    .ELSE
                        mov findtext.chrg.cpMax, 0
                    .ENDIF
                    INVOKE IsDlgButtonChecked, hWnd, IDC_MATCHCASE
                    .IF eax==BST_CHECKED
                        or uFlags, FR_MATCHCASE
                    .ENDIF
                    INVOKE IsDlgButtonChecked, hWnd, IDC_WHOLEWORD
                    .IF eax==BST_CHECKED
                        or uFlags, FR_WHOLEWORD
                    .ENDIF
                    mov    findtext.lpstrText, OFFSET FindBuffer
                    INVOKE SendMessage, hwndRichEdit, EM_FINDTEXTEX,
                                        uFlags, ADDR findtext
                    .IF eax!=-1
                        INVOKE SendMessage, hwndRichEdit, EM_EXSETSEL,
                                            0, ADDR findtext.chrgText
                    .ENDIF
                .ENDIF
            .ELSEIF ax==IDCANCEL
                INVOKE SendMessage, hWnd, WM_CLOSE, 0, 0
            .ELSE
                mov eax, FALSE
                ret
            .ENDIF
        .ENDIF
    .ELSEIF uMsg==WM_CLOSE
        mov    hSearch, 0
        INVOKE EndDialog, hWnd, 0
    .ELSE
        mov eax, FALSE
        ret
    .ENDIF
    mov eax, TRUE
    ret

SearchProc ENDP

ReplaceProc PROC hWnd:   DWORD,
                 uMsg:   DWORD,
                 wParam: DWORD,
                 lParam: DWORD

LOCAL settext: SETTEXTEX

    .IF uMsg==WM_INITDIALOG
        push   hWnd
        pop    hSearch
        INVOKE SetDlgItemText, hWnd, IDC_FINDEDIT, ADDR FindBuffer
        INVOKE SetDlgItemText, hWnd, IDC_REPLACEEDIT, ADDR ReplaceBuffer
    .ELSEIF uMsg==WM_COMMAND
        mov ax, WORD PTR wParam + 1
        .IF ax==BN_CLICKED
            mov eax, wParam
            .IF ax==IDCANCEL
                INVOKE SendMessage, hWnd, WM_CLOSE, 0, 0
            .ELSEIF ax==IDOK
                INVOKE GetDlgItemText, hWnd, IDC_FINDEDIT,
                                       ADDR FindBuffer, SIZEOF FindBuffer
                INVOKE GetDlgItemText, hWnd, IDC_REPLACEEDIT,
                                       ADDR ReplaceBuffer, SIZEOF ReplaceBuffer
                mov    findtext.chrg.cpMin, 0
                mov    findtext.chrg.cpMax, -1
                mov    findtext.lpstrText, OFFSET FindBuffer
                mov    settext.flags, ST_SELECTION
                mov    settext.codepage, CP_ACP

                .WHILE TRUE
                    INVOKE SendMessage, hwndRichEdit, EM_FINDTEXTEX,
                                        FR_DOWN, ADDR findtext
                    .BREAK .IF eax==-1
                    INVOKE SendMessage, hwndRichEdit, EM_EXSETSEL,
                                        0, ADDR findtext.chrgText
                    INVOKE SendMessage, hwndRichEdit, EM_SETTEXTEX,
                                        ADDR settext, ADDR ReplaceBuffer
                .ENDW
            .ENDIF
        .ENDIF
    .ELSEIF uMsg==WM_CLOSE
        mov hSearch, 0
        INVOKE EndDialog, hWnd, 0
    .ELSE
        mov eax, FALSE
        ret
    .ENDIF
    mov eax, TRUE
    ret

ReplaceProc ENDP

GoToProc PROC hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

LOCAL LineNo: DWORD
LOCAL chrg:   CHARRANGE

    .IF uMsg==WM_INITDIALOG
        push hWnd
        pop   hSearch
    .ELSEIF uMsg==WM_COMMAND
        mov ax, WORD PTR wParam + 2
        .IF ax==BN_CLICKED
            .IF WORD PTR wParam==IDCANCEL
                INVOKE SendMessage, hWnd, WM_CLOSE, 0, 0
            .ELSEIF WORD PTR wParam==IDOK
                INVOKE GetDlgItemInt, hWnd, IDC_LINENO, NULL, FALSE
                mov    LineNo, eax
                INVOKE SendMessage, hwndRichEdit, EM_GETLINECOUNT, 0, 0
                .IF eax>LineNo
                    INVOKE SendMessage, hwndRichEdit, EM_LINEINDEX, LineNo, 0
                    INVOKE SendMessage, hwndRichEdit, EM_SETSEL, eax, eax
                    INVOKE SetFocus, hwndRichEdit
                .ENDIF
            .ENDIF
        .ENDIF
    .ELSEIF uMsg==WM_CLOSE
        xor    eax, eax
        mov    hSearch, eax
        INVOKE EndDialog, hWnd, eax
    .ELSE
        mov eax, FALSE
        ret
    .ENDIF
    mov eax, TRUE
    ret

GoToProc ENDP

PrepareEditMenu PROC hSubMenu:DWORD

LOCAL chrg: CHARRANGE


; Sprawdzamy, czy w schowku znajduje się jakiś tekst.
; Jeśli tak, to włączamy element menu Wklej

    INVOKE SendMessage, hwndRichEdit, EM_CANPASTE, CF_TEXT, 0
    .IF eax==0  ; w schowku nie ma tekstu
        INVOKE EnableMenuItem, hSubMenu, IDM_PASTE, MF_GRAYED
    .ELSE
        INVOKE EnableMenuItem, hSubMenu, IDM_PASTE, MF_ENABLED
    .ENDIF

; Sprawdzamy, czy kolejka cofnięć jest pusta

    INVOKE SendMessage, hwndRichEdit, EM_CANUNDO, 0, 0
    .IF eax==0
        INVOKE EnableMenuItem, hSubMenu, IDM_UNDO, MF_GRAYED
    .ELSE
        INVOKE EnableMenuItem, hSubMenu, IDM_UNDO, MF_ENABLED
    .ENDIF

; Sprawdzamy, czy kolejka powtórzeń jest pusta

    INVOKE SendMessage, hwndRichEdit, EM_CANREDO, 0, 0
    .IF eax==0
        INVOKE EnableMenuItem, hSubMenu, IDM_REDO, MF_GRAYED
    .ELSE
        INVOKE EnableMenuItem, hSubMenu, IDM_REDO, MF_ENABLED
    .ENDIF

; Sprawdzamy, czy w kontrolce zaznaczono jakiś tekst.
; Jeśli tak, to uaktywniamy opcje Wytnij/Kopiuj/Usuń

    INVOKE SendMessage, hwndRichEdit, EM_EXGETSEL, 0, ADDR chrg
    mov    eax, chrg.cpMin
    .IF eax==chrg.cpMax  ; brak zaznaczenia tekstu
        INVOKE EnableMenuItem, hSubMenu, IDM_COPY, MF_GRAYED
        INVOKE EnableMenuItem, hSubMenu, IDM_CUT, MF_GRAYED
        INVOKE EnableMenuItem, hSubMenu, IDM_DELETE, MF_GRAYED
    .ELSE
        INVOKE EnableMenuItem, hSubMenu, IDM_COPY, MF_ENABLED
        INVOKE EnableMenuItem, hSubMenu, IDM_CUT, MF_ENABLED
        INVOKE EnableMenuItem, hSubMenu, IDM_DELETE, MF_ENABLED
    .ENDIF
    ret

PrepareEditMenu ENDP

WndProc PROC hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

LOCAL ofn:         OPENFILENAME
LOCAL buffer[256]: BYTE
LOCAL editstream:  EDITSTREAM
LOCAL hFile:       DWORD
LOCAL hPopup:      DWORD
LOCAL pt:          POINT
LOCAL chrg:        CHARRANGE

    .IF uMsg==WM_CREATE
        INVOKE CreateWindowEx, WS_EX_CLIENTEDGE, ADDR RichEditClass, 0,
                               WS_CHILD OR WS_VISIBLE OR \
                               ES_MULTILINE OR WS_VSCROLL OR \
                               WS_HSCROLL OR ES_NOHIDESEL,
                               CW_USEDEFAULT, CW_USEDEFAULT,
                               CW_USEDEFAULT, CW_USEDEFAULT,
                               hWnd, RichEditID, hInstance, 0
        mov    hwndRichEdit, eax
        INVOKE SendMessage, hwndRichEdit, EM_SETLANGOPTIONS, 0, 0

; Ustawiamy limit tekstu - standardowo jest 64KB.

        INVOKE SendMessage, hwndRichEdit, EM_LIMITTEXT, -1, 0

; Ustawiamy standardowy kolor tła i tekstu
       
        INVOKE SetColor
        INVOKE SendMessage, hwndRichEdit, EM_SETMODIFY, FALSE, 0

; Ustawiamy maskę zdarzeń

        INVOKE SendMessage, hwndRichEdit, EM_SETEVENTMASK, 0,
                            ENM_MOUSEEVENTS
        INVOKE SendMessage, hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0
    .ELSEIF uMsg==WM_NOTIFY
        push    esi
        mov     esi, lParam

ASSUME esi: PTR NMHDR

        .IF [esi].code==EN_MSGFILTER

ASSUME esi: PTR MSGFILTER

            .IF [esi].msg==WM_RBUTTONDOWN
                INVOKE GetMenu, hWnd
                INVOKE GetSubMenu, eax, 1
                mov    hPopup, eax
                INVOKE PrepareEditMenu, hPopup
                xor    ecx, ecx
                mov    cx, WORD PTR [esi].lParam
                mov    pt.x, ecx
                mov    cx, WORD PTR [esi].lParam + 2
                mov    pt.y, ecx
                INVOKE ClientToScreen, hWnd, ADDR pt
                INVOKE TrackPopupMenu, hPopup, TPM_LEFTALIGN OR \
                                       TPM_BOTTOMALIGN, pt.x, pt.y,
                                       NULL, hWnd, NULL
            .ENDIF
        .ENDIF
        pop esi
    .ELSEIF uMsg==WM_INITMENUPOPUP
        mov eax, lParam
        .IF ax==0  ; menu Plik
            .IF FileOpened==TRUE ; otwarto już jakiś plik
                INVOKE EnableMenuItem, wParam, IDM_OPEN, MF_GRAYED
                INVOKE EnableMenuItem, wParam, IDM_CLOSE, MF_ENABLED
                INVOKE EnableMenuItem, wParam, IDM_SAVE, MF_ENABLED
                INVOKE EnableMenuItem, wParam, IDM_SAVEAS, MF_ENABLED
            .ELSE
                INVOKE EnableMenuItem, wParam, IDM_OPEN, MF_ENABLED
                INVOKE EnableMenuItem, wParam, IDM_CLOSE, MF_GRAYED
                INVOKE EnableMenuItem, wParam, IDM_SAVE, MF_GRAYED
                INVOKE EnableMenuItem, wParam, IDM_SAVEAS, MF_GRAYED
            .ENDIF
        .ELSEIF ax==1  ; menu Edycja
            INVOKE PrepareEditMenu, wParam
        .ELSEIF ax==2  ; menu Znajdź
            .IF FileOpened==TRUE
                INVOKE EnableMenuItem, wParam, IDM_FIND, MF_ENABLED
                INVOKE EnableMenuItem, wParam, IDM_FINDNEXT, MF_ENABLED
                INVOKE EnableMenuItem, wParam, IDM_FINDPREV, MF_ENABLED
                INVOKE EnableMenuItem, wParam, IDM_REPLACE, MF_ENABLED
                INVOKE EnableMenuItem, wParam, IDM_GOTOLINE, MF_ENABLED
            .ELSE
                INVOKE EnableMenuItem, wParam, IDM_FIND, MF_GRAYED
                INVOKE EnableMenuItem, wParam, IDM_FINDNEXT, MF_GRAYED
                INVOKE EnableMenuItem, wParam, IDM_FINDPREV, MF_GRAYED
                INVOKE EnableMenuItem, wParam, IDM_REPLACE, MF_GRAYED
                INVOKE EnableMenuItem, wParam, IDM_GOTOLINE, MF_GRAYED
            .ENDIF
        .ENDIF
    .ELSEIF uMsg==WM_COMMAND
        .IF lParam==0 ; polecenia menu
            mov eax, wParam
            .IF ax==IDM_OPEN
                INVOKE RtlZeroMemory, ADDR ofn, SIZEOF ofn
                mov    ofn.lStructSize, SIZEOF ofn
                push   hWnd
                pop    ofn.hwndOwner
                push   hInstance
                pop    ofn.hInstance
                mov    ofn.lpstrFilter, OFFSET ASMFilterString
                mov    ofn.lpstrFile, OFFSET FileName
                mov    BYTE PTR [FileName], 0
                mov    ofn.nMaxFile, SIZEOF FileName
                mov    ofn.Flags, OFN_FILEMUSTEXIST OR \
                                  OFN_HIDEREADONLY OR OFN_PATHMUSTEXIST
                INVOKE GetOpenFileName, ADDR ofn
                .IF eax!=0
                    INVOKE CreateFile, ADDR FileName, GENERIC_READ,
                                       FILE_SHARE_READ, NULL,
                                       OPEN_EXISTING,
                                       FILE_ATTRIBUTE_NORMAL, 0
                    .IF eax!=INVALID_HANDLE_VALUE
                        mov hFile, eax

; Przesyłamy strumień tekstu do kontrolki RichEdit

                        mov    editstream.dwCookie, eax
                        mov    editstream.pfnCallback, OFFSET StreamInProc
                        INVOKE SendMessage, hwndRichEdit, EM_STREAMIN,
                                            SF_TEXT, ADDR editstream

; Inicjujemy znacznik modyfikacji na FALSE

                        INVOKE SendMessage, hwndRichEdit, EM_SETMODIFY,
                                            FALSE, 0
                        INVOKE CloseHandle, hFile
                        mov    FileOpened, TRUE
                    .ELSE
                        INVOKE MessageBox, hWnd, ADDR OpenFileFail, ADDR AppName,
                                           MB_OK OR MB_ICONERROR
                    .ENDIF
                .ENDIF
            .ELSEIF ax==IDM_CLOSE
                INVOKE CheckModifyState, hWnd
                .IF eax==TRUE
                    INVOKE SetWindowText, hwndRichEdit, 0
                    mov       FileOpened, FALSE
                .ENDIF
            .ELSEIF ax==IDM_SAVE
                INVOKE CreateFile, ADDR FileName, GENERIC_WRITE,
                                   FILE_SHARE_READ, NULL, CREATE_ALWAYS,
                                   FILE_ATTRIBUTE_NORMAL, 0
                .IF eax!=INVALID_HANDLE_VALUE
@@:               
                    mov    hFile, eax

; Przesyłamy strumień tekstu do pliku

                    mov    editstream.dwCookie, eax
                    mov    editstream.pfnCallback, OFFSET StreamOutProc
                    INVOKE SendMessage, hwndRichEdit, EM_STREAMOUT,
                                        SF_TEXT, ADDR editstream

; Inicjujemy znacznik modyfikacji na FALSE

                    INVOKE SendMessage, hwndRichEdit, EM_SETMODIFY, FALSE, 0
                    INVOKE CloseHandle, hFile
                .ELSE
                    INVOKE MessageBox, hWnd, ADDR OpenFileFail, ADDR AppName,
                                       MB_OK OR MB_ICONERROR
                .ENDIF
            .ELSEIF ax==IDM_COPY
                INVOKE SendMessage, hwndRichEdit, WM_COPY, 0, 0
            .ELSEIF ax==IDM_CUT
                INVOKE SendMessage, hwndRichEdit, WM_CUT, 0, 0
            .ELSEIF ax==IDM_PASTE
                INVOKE SendMessage, hwndRichEdit, WM_PASTE, 0, 0
            .ELSEIF ax==IDM_DELETE
                INVOKE SendMessage, hwndRichEdit, EM_REPLACESEL, TRUE, 0
            .ELSEIF ax==IDM_SELECTALL
                mov    chrg.cpMin, 0
                mov    chrg.cpMax, -1
                INVOKE SendMessage, hwndRichEdit, EM_EXSETSEL, 0, ADDR chrg
            .ELSEIF ax==IDM_UNDO
                INVOKE SendMessage, hwndRichEdit, EM_UNDO, 0, 0
            .ELSEIF ax==IDM_REDO
                INVOKE SendMessage, hwndRichEdit, EM_REDO, 0, 0
            .ELSEIF ax==IDM_OPTION
                INVOKE DialogBoxParam, hInstance, IDD_OPTIONDLG, hWnd,
                                       ADDR OptionProc, 0
            .ELSEIF ax==IDM_SAVEAS
                INVOKE RtlZeroMemory, ADDR ofn, SIZEOF ofn
                mov    ofn.lStructSize, SIZEOF ofn
                push   hWnd
                pop    ofn.hwndOwner
                push   hInstance
                pop    ofn.hInstance
                mov    ofn.lpstrFilter, OFFSET ASMFilterString
                mov    ofn.lpstrFile, OFFSET AlternateFileName
                mov    BYTE PTR [AlternateFileName], 0
                mov    ofn.nMaxFile, SIZEOF AlternateFileName
                mov    ofn.Flags, OFN_FILEMUSTEXIST OR\
                                  OFN_HIDEREADONLY OR OFN_PATHMUSTEXIST
                INVOKE GetSaveFileName, ADDR ofn
                .IF eax!=0
                    INVOKE CreateFile, ADDR AlternateFileName,
                                       GENERIC_WRITE, FILE_SHARE_READ,
                                       NULL, CREATE_ALWAYS,
                                       FILE_ATTRIBUTE_NORMAL, 0
                    .IF eax!=INVALID_HANDLE_VALUE
                        jmp @B
                    .ENDIF
                .ENDIF
            .ELSEIF ax==IDM_FIND
                .IF hSearch==0
                    INVOKE CreateDialogParam, hInstance, IDD_FINDDLG,
                                              hWnd, ADDR SearchProc, 0
                .ENDIF
            .ELSEIF ax==IDM_REPLACE
                .IF hSearch==0
                    INVOKE CreateDialogParam, hInstance, IDD_REPLACEDLG,
                                              hWnd, ADDR ReplaceProc, 0
                .ENDIF
            .ELSEIF ax==IDM_GOTOLINE
                .IF hSearch==0
                    INVOKE CreateDialogParam, hInstance, IDD_GOTODLG,
                                              hWnd, ADDR GoToProc, 0
                .ENDIF
            .ELSEIF ax==IDM_FINDNEXT
                INVOKE lstrlen, ADDR FindBuffer
                .IF eax!=0
                    INVOKE SendMessage, hwndRichEdit, EM_EXGETSEL, 0,
                                        ADDR findtext.chrg
                    mov             eax, findtext.chrg.cpMin
                    .IF eax!=findtext.chrg.cpMax
                        push findtext.chrg.cpMax
                        pop  findtext.chrg.cpMin
                    .ENDIF
                    mov    findtext.chrg.cpMax, -1
                    mov    findtext.lpstrText, OFFSET FindBuffer
                    INVOKE SendMessage, hwndRichEdit, EM_FINDTEXTEX,
                                        FR_DOWN, ADDR findtext
                    .IF eax!=-1
                        INVOKE SendMessage, hwndRichEdit, EM_EXSETSEL,
                                            0, ADDR findtext.chrgText
                    .ENDIF
                .ENDIF
            .ELSEIF ax==IDM_FINDPREV
                INVOKE lstrlen, ADDR FindBuffer
                .IF eax!=0
                    INVOKE SendMessage, hwndRichEdit, EM_EXGETSEL, 0,
                                        ADDR findtext.chrg
                    mov    findtext.chrg.cpMax, 0
                    mov    findtext.lpstrText, OFFSET FindBuffer
                    INVOKE SendMessage, hwndRichEdit, EM_FINDTEXTEX, 0,
                                        ADDR findtext
                    .IF eax!=-1
                        INVOKE SendMessage, hwndRichEdit, EM_EXSETSEL,
                                            0, ADDR findtext.chrgText
                    .ENDIF
                .ENDIF
            .ELSEIF ax==IDM_EXIT
                INVOKE SendMessage, hWnd, WM_CLOSE, 0, 0
            .ENDIF
        .ENDIF
    .ELSEIF uMsg==WM_CLOSE
        INVOKE CheckModifyState, hWnd
        .IF eax==TRUE
            INVOKE DestroyWindow, hWnd
        .ENDIF
    .ELSEIF uMsg==WM_SIZE
        movzx  eax, WORD PTR lParam
        movzx  edx, WORD PTR lParam + 2
        INVOKE MoveWindow, hwndRichEdit, 0, 0, eax, edx, TRUE       
    .ELSEIF uMsg==WM_DESTROY
        INVOKE PostQuitMessage, NULL
    .ELSE
        INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam       
        ret
    .ENDIF

    xor eax, eax
    ret

WndProc ENDP

END start

 

Plik ICZEDIT.RC

 

#include "resource.h"

#define IDC_NEXT          1003
#define IDR_MAINMENU       101
#define IDD_OPTIONDLG      101
#define IDD_FINDDLG        102
#define IDD_GOTODLG        103
#define IDD_REPLACEDLG     104
#define IDR_MAINACCEL      105
#define IDC_BACKCOLORBOX  1000
#define IDC_FINDEDIT      1000
#define IDC_TEXTCOLORBOX  1001
#define IDC_MATCHCASE     1001
#define IDC_REPLACEEDIT   1001
#define IDC_WHOLEWORD     1002
#define IDC_DOWN          1003
#define IDC_UP            1004
#define IDC_LINENO        1005
#define IDM_OPEN         40001
#define IDM_SAVE         40002
#define IDM_CLOSE        40003
#define IDM_SAVEAS       40004
#define IDM_EXIT         40005
#define IDM_COPY         40006
#define IDM_CUT          40007
#define IDM_PASTE        40008
#define IDM_DELETE       40009
#define IDM_SELECTALL    40010
#define IDM_OPTION       40011
#define IDM_UNDO         40012
#define IDM_REDO         40013
#define IDM_FIND         40014
#define IDM_FINDNEXT     40015
#define IDM_REPLACE      40016
#define IDM_GOTOLINE     40017
#define IDM_FINDPREV     40018

IDR_MAINMENU MENU DISCARDABLE 
{
    POPUP "&Plik"
    {
        MENUITEM "&Otwórz", IDM_OPEN
        MENUITEM "Za&mknij", IDM_CLOSE
        MENUITEM "&Zapisz", DM_SAVE
        MENUITEM "Z&apisz Jako", IDM_SAVEAS
        MENUITEM SEPARATOR
        MENUITEM "Za&kończ", IDM_EXIT
   
    }
    POPUP "&Edycja"
    {
        MENUITEM "&Cofnij",IDM_UNDO
        MENUITEM "&Ponów", IDM_REDO
        MENUITEM "&Kopiuj", IDM_COPY
        MENUITEM "Wyt&nij", IDM_CUT
        MENUITEM "Wkl&ej", IDM_PASTE
        MENUITEM SEPARATOR
        MENUITEM "&Usuń", IDM_DELETE
        MENUITEM SEPARATOR
        MENUITEM "Z&aznacz Wszystko", IDM_SELECTALL   
    }
    POPUP "&Znajdź"
    {
        MENUITEM "&Znajdź...\tCtrl+F", IDM_FIND
        MENUITEM "Znajdź &Następny\tF3", IDM_FINDNEXT
        MENUITEM "Znajdź &Poprzedni\tCtrl+F3", IDM_FINDPREV
        MENUITEM "Za&mień..\tCtrl+R", IDM_REPLACE
        MENUITEM SEPARATOR
        MENUITEM "&Idź do wiersza\tCtrl+G", IDM_GOTOLINE
   
    }
    MENUITEM "&Opcje", IDM_OPTION
}

IDD_OPTIONDLG DIALOG DISCARDABLE 0, 0, 183, 54

STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION |
      WS_SYSMENU

CAPTION "Opcje"

FONT 8, "MS Sans Serif"
{
    DEFPUSHBUTTON "OK", IDOK, 137, 7, 39, 14
    PUSHBUTTON    "Anuluj", IDCANCEL, 137, 25, 39, 14
    GROUPBOX      "", IDC_STATIC, 5, 0, 124, 49
    LTEXT         "Kolor Tła:", IDC_STATIC, 20, 14, 60, 8
    LTEXT         "", IDC_BACKCOLORBOX, 85, 11, 28, 14, SS_NOTIFY | WS_BORDER
    LTEXT         "Kolor Tekstu:", IDC_STATIC, 20, 33, 60, 8
    LTEXT         "", IDC_TEXTCOLORBOX, 85, 29, 28, 14, SS_NOTIFY | WS_BORDER
}

IDD_FINDDLG DIALOG DISCARDABLE 0, 0, 216, 53

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

CAPTION "Znajdź..."

FONT 8, "MS Sans Serif"
{
    EDITTEXT      IDC_FINDEDIT, 34, 3, 132, 13, ES_AUTOHSCROLL
    CONTROL       "Uwzględnij wielkość liter", IDC_MATCHCASE, "Button",
                  BS_AUTOCHECKBOX | WS_TABSTOP, 6, 24, 90, 11
    CONTROL       "Znajdź tylko całe wyrazy", IDC_WHOLEWORD, "Button",
                  BS_AUTOCHECKBOX | WS_TABSTOP, 6, 36, 90, 11
    CONTROL       "W dół", IDC_DOWN, "Button",
                  BS_AUTORADIOBUTTON | WS_TABSTOP, 108, 25, 36, 11
    CONTROL       "W górę", IDC_UP, "Button",
                  BS_AUTORADIOBUTTON | WS_TABSTOP, 108, 36, 42, 11
    DEFPUSHBUTTON "OK", IDOK, 172, 3, 40, 13
    PUSHBUTTON    "Anuluj", IDCANCEL, 172, 18, 40, 13
    LTEXT         "Znajdź:", IDC_STATIC, 2, 5, 26, 9
    GROUPBOX      "Kierunek", IDC_STATIC, 100, 18, 64, 33
}

IDD_GOTODLG DIALOGEX 0, 0, 106, 30

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

EXSTYLE WS_EX_TOOLWINDOW

CAPTION "Idź do wiersza"

FONT 8, "MS Sans Serif", 0, 0, 0x1
{
    EDITTEXT      IDC_LINENO, 28, 3, 36, 11, ES_AUTOHSCROLL | ES_NUMBER, WS_EX_CLIENTEDGE
    DEFPUSHBUTTON "OK", IDOK, 70, 3, 32, 11
    PUSHBUTTON    "Anuluj", IDCANCEL, 70, 16, 32, 11
    LTEXT         "Wiersz :", IDC_STATIC, 2, 5, 26, 9
}

IDD_REPLACEDLG DIALOG DISCARDABLE     0, 0, 186, 33

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

CAPTION "Zamień"

FONT 8, "MS Sans Serif"
{
    EDITTEXT      IDC_FINDEDIT, 51, 3, 84, 12, ES_AUTOHSCROLL
    EDITTEXT      IDC_REPLACEEDIT, 51, 17, 84, 11, ES_AUTOHSCROLL
    DEFPUSHBUTTON "OK", IDOK, 142, 3, 39, 11
    PUSHBUTTON    "Anuluj", IDCANCEL, 142, 17, 39, 11
    LTEXT         "Znajdź:", IDC_STATIC, 3, 4, 34, 8
    LTEXT         "Zamień z", IDC_STATIC, 3, 18, 42, 8
}

IDR_MAINACCEL ACCELERATORS DISCARDABLE
{
    "F", IDM_FIND, VIRTKEY, CONTROL, NOINVERT
    "G", IDM_GOTOLINE, VIRTKEY, CONTROL, NOINVERT
    "R", IDM_REPLACE, VIRTKEY, CONTROL, NOINVERT
    VK_F3, IDM_FINDNEXT, VIRTKEY, NOINVERT
    VK_F3, IDM_FINDPREV, VIRTKEY, CONTROL, NOINVERT
}

 

Analiza

Operacja wyszukiwania tekstu została zaimplementowana za pomocą wiadomości EM_FINDTEXTEX. Gdy użytkownik kliknie myszką na elemencie menu Znajdź, wysłana zostaje wiadomość IDM_FIND i pojawia się okno dialogowe wyszukiwania tekstu.

 

 

    INVOKE GetDlgItemText, hWnd, IDC_FINDEDIT,
                           ADDR FindBuffer, SIZEOF FindBuffer
    .IF eax!=0

 

Gdy użytkownik wpisze tekst do wyszukania i kliknie przycisk OK, odczytujemy ten tekst do bufora FindBuffer.

 

    mov    uFlags, 0 
    INVOKE SendMessage, hwndRichEdit, EM_EXGETSEL, 0, ADDR findtext.chrg

 

Jeśli tekst nie jest pusty, kontynuujemy inicjując zmienną uFlags na 0. Zmienna ta jest używana do przechowywania znaczników poszukiwań wykorzystywanych przez wiadomość EM_FINDTEXTEX. Po tej czynności pobieramy bieżące zaznaczenie za pomocą wiadomości EM_EXGETSEL, ponieważ jest nam potrzebny punkt startowy, od którego rozpoczniemy nasze poszukiwania.

 

    INVOKE IsDlgButtonChecked, hWnd, IDC_DOWN
    .IF eax==BST_CHECKED
        or  uFlags, FR_DOWN
        mov eax, findtext.chrg.cpMin
        .IF eax!=findtext.chrg.cpMax
            push findtext.chrg.cpMax
            pop  findtext.chrg.cpMin
        .ENDIF
        mov findtext.chrg.cpMax, -1
    .ELSE
        mov findtext.chrg.cpMax, 0
    .ENDIF

 

Następny fragment kodu jest troszeczkę zagmatwany. Sprawdzamy kontrolkę kierunku poszukiwań, aby upewnić się w którą stronę prowadzić poszukiwania. Jeśli zostało zaznaczone poszukiwanie w dół, w zmiennej uFlags ustawiamy znacznik FR_DOWN. Następnie sprawdzamy, czy użytkownik dokonał zaznaczenia bloku tekstu w kontrolce porównując ze sobą wartości pól cpMin i cpMax. Jeśli nie są sobie równe, to mamy potwierdzenie istnienia zaznaczenia bloku tekstu i musimy kontynuować poszukiwania od końca tego zaznaczenia do końca tekstu w kontrolce. Zatem musimy zastąpić wartość cpMin zawartością cpMax, a do cpMax wprowadzić -1 (0FFFFFFFFh). Jeśli nie został zaznaczony żaden obszar tekstu w kontrolce, to poszukujemy od bieżącej pozycji kursora do końca tekstu.

Jeśli użytkownik wybrał poszukiwanie w górę, korzystamy z zakresu od początku zaznaczenia do początku tekstu w kontrolce. Dlatego modyfikujemy jedynie wartość cpMax na 0. W przypadku poszukiwania w górę cpMin zawiera indeks ostatniego znaku w zakresie poszukiwań, a cpMax zawiera indeks pierwszego znaku tego zakresu. Jest to odwrotność poszukiwania w dół.

 

    INVOKE IsDlgButtonChecked, hWnd, IDC_MATCHCASE
    .IF eax==BST_CHECKED
        or uFlags, FR_MATCHCASE
    .ENDIF
    INVOKE IsDlgButtonChecked, hWnd, IDC_WHOLEWORD
    .IF eax==BST_CHECKED
        or uFlags, FR_WHOLEWORD
    .ENDIF
    mov findtext.lpstrText, OFFSET FindBuffer

 

Kontynuujemy sprawdzanie wyboru opcji w okienku dialogowym ustawiając w zmiennej uFlags odpowiednie znaczniki poszukiwań, tj. FR_MATCHCASE i FR_WHOLEWORD. Na koniec w polu lpstrText umieszczamy adres tekstu do wyszukania.

 

    INVOKE SendMessage, hwndRichEdit, EM_FINDTEXTEX,
                            uFlags, ADDR findtext
        .IF eax!=-1
            INVOKE SendMessage, hwndRichEdit, EM_EXSETSEL,
                                0, ADDR findtext.chrgText
        .ENDIF
    .ENDIF

 

Jesteśmy już gotowi do wysłania wiadomości EM_FINDTEXTEX. Po tej operacji sprawdzamy wynik poszukiwania zwrócony przez funkcję SendMessage. Jeśli wartość zwrotna wynosi -1, tekst nie został znaleziony w zakresie poszukiwań. W przeciwnym razie pole chrgText struktury FINDTEXTEX zostało wypełnione indeksami znakowymi poszukiwanego tekstu w obrębie kontrolki RichEdit. Zaznaczamy ten obszar przy pomocy wiadomości EM_EXSETSEL.Operacja zastępowania tekstu wykonywana jest w większości w ten sam sposób.

 

 

    INVOKE GetDlgItemText, hWnd, IDC_FINDEDIT,
                           ADDR FindBuffer, SIZEOF FindBuffer
    INVOKE GetDlgItemText, hWnd, IDC_REPLACEEDIT,
                           ADDR ReplaceBuffer, SIZEOF ReplaceBuffer

 

Odczytujemy tekst do wyszukania oraz tekst, który ma go zastąpić.

 

    mov findtext.chrg.cpMin, 0
    mov findtext.chrg.cpMax, -1
    mov findtext.lpstrText, OFFSET FindBuffer

 

Aby ułatwić zadanie, operacja zastępowania tekstu jest globalna dla całego tekstu w kontrolce. Stąd indeks startowy wynosi 0 a indeks końcowy -1.

 

    mov settext.flags, ST_SELECTION
    mov settext.codepage, CP_ACP

 

Inicjujemy strukturę SETTEXTEX, aby zaznaczyć, iż chcemy zastąpić bieżący wybór i stosować standardową stronę kodową systemu.

 

    .WHILE TRUE
        INVOKE SendMessage, hwndRichEdit, EM_FINDTEXTEX,
                            FR_DOWN, ADDR findtext
        .BREAK .IF eax==-1
        INVOKE SendMessage, hwndRichEdit, EM_EXSETSEL,
                            0, ADDR findtext.chrgText
        INVOKE SendMessage, hwndRichEdit, EM_SETTEXTEX,
                            ADDR settext, ADDR ReplaceBuffer
    .ENDW

 

Wchodzimy w nieskończoną pętlę szukając wystąpień poszukiwanego tekstu w zawartości kontrolki RichEdit. Jeśli znajdziemy go, zaznaczamy ten obszar przy pomocy wiadomości EM_EXSETSEL i zastępujemy za pomocą EM_SETTEXTEX. Gdy brak już wystąpień poszukiwanego tekstu, przerywamy pętlę.

Opcje Znajdź Następny i Znajdź Poprzedni wykorzystują wiadomość EM_FINDTEXTEX w podobny sposób do operacji wyszukiwania.

W następnej kolejności przeanalizujemy operację przejścia do wskazanego wiersza. Gdy użytkownik wybierze z menu opcję Idź Do Wiersza, wyświetlamy odpowiednie okno dialogowe.

 

 

Gdy użytkownik wpisze numer wiersza i kliknie przycisk OK, rozpoczynamy operację.

 

    INVOKE GetDlgItemInt, hWnd, IDC_LINENO, NULL, FALSE
    mov    LineNo, eax

 

Odczytujemy z kontrolki edycyjnej numer wiersza.

 

    INVOKE SendMessage, hwndRichEdit, EM_GETLINECOUNT, 0, 0
    .IF eax>LineNo

 

Odczytujemy liczbę wierszy w kontrolce. Sprawdzamy, czy wartość podana przez użytkownika leży w zakresie.

 

    INVOKE SendMessage, hwndRichEdit, EM_LINEINDEX, LineNo, 0

 

Jeśli numer wiersza jest poprawny, to chcemy umieścić na początku tego wiersza kursor. Zatem wysyłamy do kontrolki RichEdit wiadomość EM_LINEINDEX. Wiadomość ta zwraca pozycję znakową pierwszego znaku w podanym wierszu. Numer wiersza wysyłamy w parametrze wParam, a w zamian dostajemy pozycję znakową w rejestrze eax.

 

    INVOKE SendMessage, hwndRichEdit, EM_SETSEL, eax, eax

 

Do ustawienia bieżącego zaznaczenia wykorzystujemy tym razem wiadomość EM_SETSEL, ponieważ indeksy znaków nie znajdują się w strukturze CHARRANGE i w ten sposób zaoszczędzamy dwie instrukcje na umieszczenie ich tam.

 

        INVOKE SetFocus, hwndRichEdit
    .ENDIF

 

Kursor nie zostanie wyświetlony, dopóki kontrolka RichEdit nie otrzyma skupienia. Zatem wywołujemy dla niej funkcję SetFocus.

 

Autorem kursu jest Iczelion. Kurs programowania Windows znalazł się na serwerze I LO w Tarnowie za pisemną zgodą autora.
Tłumaczenie z języka angielskiego, opracowanie HTML i konwersję przykładów programów wykonał mgr Jerzy Wałaszek.



List do administratora Serwisu Edukacyjnego Nauczycieli I LO

Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz  ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048

 

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień szeroko opisywanych w podręcznikach.



   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2017 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.