Tutorial 34: Richedit Control: More Text Operations
You'll Learn More About Text Operations Under Richedit Control. Specify, You'll Know How To Search for / Replace Text, Jumping To Specific Line Number.
Download The Example.
THEORY
Searching for text
TheRe Several Text Operations Under Richedit Control. Searching for Text Is Done by Sending Em_FindText or EM_FINDTEXTEX. These Messages Has A Small Difference.
EM_FINDTEXT
WPARAM == Search Options. can be any combination of the value in the table below.these Options Are Identical For Both
EM_FINDTEXT AND EM_FINDTEXTEX
FR_DOWNIf this flag is specified, the search starts from the end of the current selection to the end of the text in the control (downward) This flag has effect only for RichEdit 2.0 or later:. This behavior is the default for RichEdit 1.0 The. default behavior of RichEdit 2.0 or later is to search from the end of the current selection to the beginning of the text (upward) .In summary, if you use RichEdit 1.0, you can not do anything about the search direction: it always searches downward. If you use RichEdit 2.0 and you want to search downward, you must specify this flag else the search would be upward.FR_MATCHCASEIf this flag is specified, the search is case-sensitive.FR_WHOLEWORDIf this flag is set, the search finds the whole Word That Matches The Specified Search String.
Actually, There Are A Few More Flags But They Are Relevant To Non-English Languages.
LPARAM == Pointer to the FindText Structure.
Findtext struct
CHRG Charrange <>
LPSTRTEXT DWORD?
FindText Ends
Chrg Is a Charrange Structure Which is defined as Follows:
Charrange struct
CPMIN DWORD? CPMAX DWORD?
Charrange Ends
Cpmin contains the character in the character array (range).
CPMAX Contains The Character Index of The Character Immediely Following The Last Character in The Character Array.
In Essence, To Search for a Text String, You Have to Specify The Character Range In Which To Search. The meaning of cpmin
And cpmax diffording to WHETHER THETY IS DOWNWARD or UPWARD. IF The search is Downward, CPMIN
Specifies The Starting Character Index To Search In and Cpmax The Ending Character Index. if The Search IS Upward, The Search Is Upward, The
Reverse is true, ie. cpmin contains the ending character index while cpmax the starting character index.
LPSTRTEXT IS The Pointer To The Text String to Search for.
EM_FINDTEXT RETURns The Character Index of The First Character in The matching text string in the richedit control. It Returns -1 IF
No match is found.
EM_FINDTEXTEX
WPARAM == The Search Options. Same As Those of EM_FINDTEXT.
LPARAM == Pointer to the Findtextex Structure.
FindtexTex Struct
CHRG Charrange <>
LPSTRTEXT DWORD?
Chrgtext Charrange <>
FindtexTex Ends
THE FIRST TWO MEMBERS OF FINDTEXTEX THOSE OF FINDTEXT STRUCTURE. Chrgtext Is A Charrange Structure That Will
BE Filled with the starting / ending characterindices if a match is found.
The return value of em_findtextex is the Same as this of em_findtext.
The Difference Between EM_FINDTEXT AND EM_FINDTEXTEX IS That The Findtextex Structure Has An Additional MEMBER,
Chrgtext, Which Will Be Filled with The Starting / Ending Character Indices IF A Match Is Found. This is Convenient IF WA WANT To DO
More text operations on the string.replace / insert text
Richedit Control Provides EM_SETTEXTEX for Replacing / Inserting Text. This Message Combines The FunctionAlity Of WM_SETTEXT AND EM_REPLACESEL. IT HAS The FOLLOWING SYNTAX:
EM_SETTEXTEX
WPARAM == Pointer to settextex structure.
Settextex struct
Flags DWORD?
CodePage DWORD?
SetTexTex Ends
Flags Can Be The Combination of The Following Values:
ST_DEFAULTDELETES The undo stack, discards rich-text formatting, replaces all text.st_keepundokeeps the undo stackst_selectionReplaces Selection and Keeps Rich-text Formatting
.
Text Selection
We can select the text programmatically with EM_SETSEL or EM_EXSETSEL. Either one works fine. Choosing which message to use depends on the available format of the character indices. If they are already stored in a CHARRANGE structure, it's easier to use EM_EXSETSEL.
EM_EXSETSEL
WPARAM == NOT USED. Must BE 0
LPARAM == Pointer to a Charrange Structure That Contains the Character Range to Be SELECTED.
Event notification
In the case of a multiline edit control, you have to subclass it in order to obtain the input messages such as mouse / keyboard events. RichEdit control provides a better scheme that will notify the parent window of such events. In order to register for notifications , The Parent WinDow Sends Em_seteventmask Message To The Richedit Control, Specifying Which Events It's INTERESTED IN. EM_SETEVENTMASK HAS THE FOLLOWING SYNTAX:
EM_SETEVENTMASK
WPARAM == NOT USED. Must BE 0
. LParam == event mask value It can be the combination of the flags in the table below.ENM_CHANGESends EN_CHANGE notificationsENM_CORRECTTEXTSends EN_CORRECTTEXT notificationsENM_DRAGDROPDONESends EN_DRAGDROPDONE notificationsENM_DROPFILESSends EN_DROPFILES notifications.ENM_KEYEVENTSSends EN_MSGFILTER notifications for keyboard eventsENM_LINKRich Edit 2.0 and later: Sends EN_LINK notifications when the mouse pointer is over text that has the CFE_LINK and one of several mouse actions is performed.ENM_MOUSEEVENTSSends EN_MSGFILTER notifications for mouse eventsENM_OBJECTPOSITIONSSends EN_OBJECTPOSITIONS notificationsENM_PROTECTEDSends EN_PROTECTED notificationsENM_REQUESTRESIZESends EN_REQUESTRESIZE notificationsENM_SCROLLSends EN_HSCROLL and EN_VSCROLL notificationsENM_SCROLLEVENTSSends EN_MSGFILTER notifications for mouse wheel eventsENM_SELCHANGESends EN_SELCHANGE notificationsENM_UPDATE Sends EN_UPDATE notifications.Rich Edit 2.0 and later: this flag Is Ignored and The En_Update Noti Fications Are Always Sent. However, IF Rich Edit 3.0 Emulates Rich Edit 1.0, You Must Use this flag to send en_update notification
All the above notifications will be sent as WM_NOTIFY message: you have to check the code member of NMHDR structure for the notification message For example, if you want to register for mouse events. (Eg you want to provide a context sensitive popup menu.) You Must Do Something Like this:
Invoke SendMask, 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
....
[Do Something Here]
....
.endifpop ESI
EXAMPLE:
The following example is the update of IczEdit in tutorial no. 33. It adds search / replace functionality and accelerator keys to the program. It also processes the mouse events and provides a popup menu on right mouse click.
.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 / WANEL32.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
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
IDD_OPTIONDLG EQU 101
IDC_BACKCOLORBOX EQU 1000
IDC_TextColorBox EQU 1001
IDR_MAINACCEL EQU 105
IDD_FINDDLG EQU 102
IDD_GOTODLG EQU 103
IDD_REPLACEDLG EQU 104
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 1005IDM_FIND EQU 40014
IDM_FINDNEXT EQU 40015
IDM_REPLACE EQU 40016
IDM_GOTOLINE EQU 40017
IDM_FINDPREV EQU 40018
Richeditid EQU 300
.DATA
ClassName DB "iczeditclass", 0
Appname DB "iczedit Version 2.0", 0
Richeditdll DB "Riched20.dll", 0
Richeditclass DB "Richedit20a", 0
Norichedit DB "Cannot Find Riched20.dll", 0
Asmfilterstring DB "ASM Source Code (* .asm)", 0, "*. ASM", 0
DB "all files (*. *)", 0, "*. *", 0, 0
OpenFileFail DB "Cannot Open THE FILE", 0
Wannasave DB "The Data IN THE CONTOL IS MODIFIED. WANT TO SAVE IT?", 0
FILEOPENED DD FALSE
BackgroundColor DD 0FFFFFFH; Default to White
TextColor DD 0; Default to Black
HSEARCH DD?; Handle to The Search / Replace Dialog Box
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
.lse
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_vredrawmov 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 loadingAccelerators, 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, PBYTESWRITEN: 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 RTLZERMEMORY, 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 Eax, WPARAM
SHR EAX, 16
.IF AX == BN_Clicked
Mov Eax, WPARAM
.IF AX == idcancel
Invoke SendMessage, HWnd, WM_Close, 0, 0
.ELSEIF AX == IDC_BACKCOLORBOX
Invoke RTLZERMEMORY, 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 InvalidateERECT, EAX, 0, TRUE
.endif
.ELSEIF AX == IDC_TextColorBox
Invoke RTLZERMEMORY, 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 InvalidateERECT, EAX, 0, TRUE
.endif
.ELSEIF AX == IDOK
Invoke SendMessage, Hwndrichedit, EM_GETMODIFY, 0, 0
Push EAX
Invoke setColor
POP EAX
Invoke SendMessage, HwndrichEdit, Em_SetModify, Eax, 0invoke Enddialog, HWnd, 0
.endif
.endif
.ELSEIF uMSG == WM_CTLCOLORSTATIC
Invoke getdlgitem, hwnd, idc_backcolorbox
.IF EAX == LPARAM
Invoke Createsolidbrush, BackgroundColor
RET
.lse
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
.lse
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
Invoke CheckRadiobutton, HWnd, IDC_Down, IDC_UP, IDC_DOWN
Invoke Senddlgitemmessage, HWnd, IDC_Findedit, WM_SETTEXT, 0, AddR Findbuffer
.ELSEIF uMSG == WM_COMMAND
Mov Eax, WPARAM
SHR EAX, 16
.IF AX == BN_Clicked
Mov Eax, WPARAM
.IF AX == iDOK
Mov uflags, 0
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
.lse
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
.lse
Mov Eax, False
RET
.endif
.endif
.ELSEIF uMSG == WM_Close
Mov HSearch, 0
Invoke EndDialog, HWND, 0
.lse
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 Eax, WPARAM
SHR EAX, 16
.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 findxt
.IF EAX == - 1
.break
.lse
Invoke SendMessage, HwndrichEdit, EM_EXSETSEL, 0, AddR FindText.chrgtext
Invoke SendMessage, Hwndrichedit, EM_SETTEXTEX, ADDR Settext, Addr ReplaceBuffer
.endif
.endw
.endif
.endif
.ELSEIF uMSG == WM_Close
Mov HSearch, 0
Invoke EndDialog, HWND, 0
.lse
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_Commandmov Eax, WPARAM
SHR EAX, 16
.IF AX == BN_Clicked
Mov Eax, WPARAM
.IF AX == idcancel
Invoke SendMessage, HWnd, WM_Close, 0, 0
.ELSEIF AX == IDOK
Invoke getdlgitemint, hwnd, IDC_LINENO, NULL, FALSE
Mov Lineno, EAX
Invoke SendMessage, Hwndrichedit, EM_GETLINECUNT, 0, 0
.IF EAX> Lineno
Invoke SendMessage, Hwndrichedit, EM_LINEINDEX, LINENO, 0
Mov Chrg.cpmin, EAX
Mov Chrg.cpmax, EAX
Invoke SendMessage, Hwndrichedit, EM_EXSETSEL, 0, AddR chrg
Invoke setfocus, HWNDRICHEDIT
.endif
.endif
.endif
.ELSEIF uMSG == WM_Close
Mov HSearch, 0
Invoke EndDialog, HWND, 0
.lse
Mov Eax, False
RET
.endif
Mov Eax, True
RET
Gotoproc ENDP
PrepareEditmenu Proc Hsubmenu: DWORD
Local Chrg: Charrange
Invoke SendMessage, Hwndrichedit, EM_CANPASTE, CF_TEXT, 0
.IF EAX == 0; No Text in the clipboard
Invoke EnableMenuItem, HSubmenu, IDM_Paste, MF_GRAYED
.lse
Invoke EnableMenuItem, HSubmenu, IDM_Paste, MF_ENABLED
.endif
Invoke SendMessage, Hwndrichedit, EM_CANUNDO, 0, 0
.IF EAX == 0
Invoke EnableMenuItem, HSubmenu, IDM_UNDO, MF_GRAYED
.lse
Invoke EnableMenuItem, HSubmenu, IDM_UNDO, MF_ENABLED
.endif
Invoke SendMessage, Hwndrichedit, EM_CANREDO, 0, 0
.IF EAX == 0
Invoke EnableMenuItem, Hsubmenu, IDM_REDO, MF_GRAYED
.lse
Invoke EnableMenuItem, HSubmenu, IDM_REDO, MF_ENABLED
.endif
Invoke SendMessage, Hwndrichedit, EM_EXGETSEL, 0, AddR chrg
Mov Eax, Chrg.cpmin
.IF eax == chrg.cpmax; no current selection
Invoke EnableMenuItem, HSubmenu, IDM_COPY, MF_GRAYED
Invoke EnableMenuItem, HSubmenu, IDM_CUT, MF_GRAYED
Invoke EnablemenuItem, HSubmenu, IDM_DELETE, MF_GRAYED
.lse
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_LIMITTEXT, -1, 0
Invoke setColor
Invoke SendMessage, Hwndrichedit, EM_SETMODIFY, FALSE, 0
Invoke SendMask, Hwndrichedit, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS
Invoke SendMessage, Hwndrichedit, EM_EMPTYUNDOBUFER, 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
Mov Edx, [ESI] .lparam
MOV ECX, EDX
And EDX, 0FFFFH
SHR ECX, 16
MOV PT.X, EDX
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; File Menu
.IF fileopened == true; a file is already OPENED
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
.lse
Invoke EnableMenuItem, WPARAM, IDM_OPEN, MF_ENABLINVOKE ENABLEMENUITEM, WPARAM, IDM_CLOSE, MF_GRAYED
Invoke EnableMenuItem, WPARAM, IDM_SAVE, MF_GRAYED
Invoke EnableMenuItem, WPARAM, IDM_SAVEAS, MF_GRAYED
.endif
.ELSEIF AX == 1; Edit Menu
Invoke PrepareEditmenu, WPARAM
.ELSEIF AX == 2; Search Menu Bar
.IF fileopened == TRUE
Invoke EnableMenuItem, WPARAM, IDM_FIND, MF_ENABLED
Invoke EnableMenuItem, WPARAM, IDM_FINDNEXT, MF_ENABED
Invoke EnableMenuItem, WPARAM, IDM_FINDPREV, MF_ENABLED
Invoke EnableMenuItem, WPARAM, IDM_REPLACE, MF_ENABLED
Invoke EnableMenuItem, WPARAM, IDM_GOTOLINE, MF_ENABLED
.lse
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; Menu Commands
Mov Eax, WPARAM
.IF AX == idm_open
Invoke RTLZERMEMORY, ADDR OFN, SIZEOF OFN
Mov ofn.lstructsize, Sizeof off
Push hwnd
POP OFN.HWNDOWNER
Push hinstance
POP OFN.HINSTANCE
Mov off.lpstrfilter, offset asmfilterstring
Mov ofn.lpstrfile, offset filename
MOV BYTE PTR [filename], 0
Mov ofn.nmaxfile, Sizeof FileName
Mov off.flags, OFN_FILEMUSTEXIST or OFN_HIDEREADOSLY 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
; ================================================== ===============; stream the text int Into the Richedit Control
; ================================================== ================
Mov EditStream.dwcookie, EAX
Mov EditStream.pfncallback, Offset StreamInproc
Invoke SendMessage, Hwndrichedit, EM_STREAMIN, SF_TEXT, ADDR EditStream
; ================================================== =========
; Initialize the Modify State To False
; ================================================== =========
Invoke SendMessage, Hwndrichedit, EM_SETMODIFY, FALSE, 0
Invoke Closehandle, HFile
Mov FileOpened, True
.lse
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, 0mov FileOpened, False
.endif
.ELSEIF AX == IDM_SAVE
Invoke CreateFile, Addr FileName, Generic_Write, File_Share_read, null, crete_always, file_attribute_normal, 0
.IF EAX! = INVALID_HANDLE_VALUE
@@:
Mov Hfile, EAX
; ================================================== ================
Stream the text to the file
; ================================================== ================
Mov EditStream.dwcookie, EAX
Mov EditStream.pfncallback, Offset streamoutproc
Invoke SendMessage, Hwndrichedit, EM_STREAMOUT, SF_TEXT, AddR EditStream
; ================================================== =========
; Initialize the Modify State To False
; ================================================== =========
Invoke SendMessage, HwndrichEdit, Em_SetModify, False, 0Invoke Closehandle, Hfile
.lse
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 RTLZERMEMORY, ADDR OFN, SIZEOF OFN
Mov ofn.lstructsize, Sizeof off
Push hwnd
POP OFN.HWNDOWNER
Push hinstance
POP OFN.HINSTANCE
Mov off.lpstrfilter, offset asmfilterstring
Mov ofn.lpstrfile, Offset AlternateFileName
MOV BYTE PTR [AlternateFileName], 0
Mov ofn.nmaxfile, Sizeof AlternateFileName
Mov off.flags, OFN_FILEMUSTEXIST or OFN_HIDEREADOSLY 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_Findlg, Hwnd, AddR searchProc, 0
.endif
.ELSEIF AX == IDM_REPLACE
.IF hSearch == 0
Invoke CreateDialogparam, Hinstance, IDD_REPLAG, 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 findxt
.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
Mov Eax, LPARAM
Mov Edx, EAX
And Eax, 0FFFFH
SHR EDX, 16
Invoke MoveWindow, Hwndrichedit, 0,0, Eax, EDX, True
.ELSEIF uMSG == WM_DESTROY
Invoke PostquitMessage, NULL
.lse
Invoke DefWindowProc, Hwnd, UMSG, WPARAM, LPARAM
RET
.endif
XOR EAX, EAX
RET
WNDPROC ENDP
End Start
Analysis
The search-for-text capability is implemented with EM_FINDTEXTEX. When the user clicks on Find menuitem, IDM_FIND message is sent and the Find dialog box is displayed.invoke GetDlgItemText, hWnd, IDC_FINDEDIT, addr FindBuffer, sizeof FindBuffer
.IF EAX! = 0
.
Mov uflags, 0
Invoke SendMessage, Hwndrichedit, EM_EXGETSEL, 0, AddR FindText.chrg
If the text string is not null, we continue to initialize uFlags variable to 0.This variable is used to store the search flags used with EM_FINDTEXTEX. After that, we obtain the current selection with EM_EXGETSEL because we need to know the starting point of the Search Operation.
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
.lse
MOV Findtext.chrg.cpmax, 0
.endif
The next part is a little tricky. We check the direction radio button to ascertain which direction the search should go. If the downward search is indicated, we set FR_DOWN flag to uFlags. After that, we check whether a selection is currently in effect by comparing the values of cpMin and cpMax. If both values are not equal, it means there is a current selection and we must continue the search from the end of that selection to the end of text in the control. Thus we need to replace the value Of cpmax with what of cpmin and change the value of cpmax to -1 (0ffffffh). if it is no current selection, The Range To Search Is from The Current Caret Position To The End of Text.
If the user chooses to search upward, we use the range from the start of the selection to the beginning of the text in the control. That's why we only modify the value of cpMax to 0. In the case of upward search, cpMin contains the character index of the last character in the search range and cpMax the character index of the first char in the search range. It's the inverse of the downward search.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
WE Continue to Check The Checkboxes for the search Flags, IE, fr_matchcase and fr_wholeword. Lastly, We Put The Offset of the text.
Invoke SendMessage, Hwndrichedit, EM_FINDTEXTEX, UFLAGS, AddR Findtext
.IF EAX! = - 1
Invoke SendMessage, HwndrichEdit, EM_EXSETSEL, 0, AddR FindText.chrgtext
.endif
.endif
We are now ready to issue EM_FINDTEXTEX. After that, we examine the search result returned by SendMessage. If the return value is -1, no match is found in the search range. Otherwise, chrgText member of FINDTEXTEX structure is filled with the character indices Of the matching text. we thus proced to select it with em_exsetsel.
The Replace Operation Is Done in Much The Same Manner.
Invoke getdlgitemtext, hwnd, idc_findedit, AddR Findbuffer, Sizeof Findbuffer
Invoke getdlgitemtext, hwnd, idc_replaceEdit, AddR ReplaceBuffer, Sizeof ReplaceBuffer
We Retrieve the text to search for and the text used to replace.
Mov Findtext.chrg.cpmin, 0
MOV Findtext.chrg.cpmax, -1
MOV FindText.lpstrText, Offset Findbuffer
To make it it is -1.mov setText.Flags, ST_SELECTION AFFECTES
MOV setText.codepage, CP_ACP
................ ..
.While true
Invoke SendMessage, Hwndrichedit, EM_FINDTEXTEX, fr_down, addr findxt
.IF EAX == - 1
.break
.lse
Invoke SendMessage, HwndrichEdit, EM_EXSETSEL, 0, AddR FindText.chrgtext
Invoke SendMessage, Hwndrichedit, EM_SETTEXTEX, ADDR Settext, Addr ReplaceBuffer
.endif
.endw
We enter an infinite loop, search for the matching text. If one is found, We select it with em_exsetsel and replace it with em_settextex. When no more match is found, we exit the loop.
Find next and find prev. Features Use em_findtextex message in the Similar Manner to the find operation.
WE WILL EXAMINE THE Go To Line Feature Next .hen The User Clicks Go To Line MenuItem, We Display a Dialog BoX Below:
.
Invoke getdlgitemint, hwnd, IDC_LINENO, NULL, FALSE
Mov Lineno, EAX
Obtain the line number from the ed control
Invoke SendMessage, Hwndrichedit, EM_GETLINECUNT, 0, 0
.IF EAX> Lineno
Obtain the number of lines in the control. Check WHETER THE USER SPECIFIES The LINE NUMBER That Out of the Range.
Invoke SendMessage, Hwndrichedit, EM_LINEINDEX, LINENO, 0
If the line number is valid, we want to move the caret to the first character of that line. So we send EM_LINEINDEX message to the richedit control. This message returns the character index of the first character in the specified line. We send the line Number in WParam and in Return, We Has The Character Index.Invoke SendMessage, HwndrichEdit, EM_SETSEL, EAX, EAX
To set the current selection, this time we use EM_SETSEL because the character indices are not already in a CHARRANGE structure thus it saves us two instructions (to put those indices into a CHARRANGE structure).
Invoke setfocus, HWNDRICHEDIT
.endif
The Caret Will Not Be Displayed Unless The Richedit Control Has The Focus. So We call setfocus on it.