EM_FINDTEXT wParam == Search options. Can be any combination of the values in the table below.These options are identical for both EM_FINDTEXT and EM_FINDTEXTEX
FR_DOWN If 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't 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_MATCHCASE If this flag is specified, the search is case-sensitive. FR_WHOLEWORD If 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: chrg: CHARRANGE <> lpstrText: D§ ?] chrg is a CHARRANGE structure which is defined as follows: [CHARRANGE: cpMin: D§ ? cpMax: D§ ?] cpMin contains the character index of the first character in the character array (range). cpMax contains the character index of the character immediately 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 differ according to whether the search 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 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: chrg: CHARRANGE <> lpstrText: D§ ? chrgText: CHARRANGE <>] The first two members of FINDTEXTEX are identical to 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 that 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 we want to do more text operations on the string.
EM_SETTEXTEX wParam == pointer to SETTEXTEX structure. [SETTEXTEX: flags: D§ ? codepage: D§ ?] flags can be the combination of the following values:
ST_DEFAULT | Deletes the undo stack, discards rich-text formatting, replaces all text. |
ST_KEEPUNDO | Keeps the undo stack |
ST_SELECTION | Replaces selection and keeps rich-text formatting |
codepage is the constant that specifies the code page you want to text to be. Usually, we simply use CP_ACP.
EM_EXSETSEL wParam == not used. Must be 0 lParam == pointer to a CHARRANGE structure that contains the character range to be selected.
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_CHANGE | Sends EN_CHANGE notifications |
ENM_CORRECTTEXT | Sends EN_CORRECTTEXT notifications |
ENM_DRAGDROPDONE | Sends EN_DRAGDROPDONE notifications |
ENM_DROPFILES | Sends EN_DROPFILES notifications. |
ENM_KEYEVENTS | Sends EN_MSGFILTER notifications for keyboard events |
ENM_LINK | Rich 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_MOUSEEVENTS | Sends EN_MSGFILTER notifications for mouse events |
ENM_OBJECTPOSITIONS | Sends EN_OBJECTPOSITIONS notifications |
ENM_PROTECTED | Sends EN_PROTECTED notifications |
ENM_REQUESTRESIZE | Sends EN_REQUESTRESIZE notifications |
ENM_SCROLL | Sends EN_HSCROLL and EN_VSCROLL notifications |
ENM_SCROLLEVENTS | Sends EN_MSGFILTER notifications for mouse wheel events |
ENM_SELCHANGE | Sends EN_SELCHANGE notifications |
ENM_UPDATE | Sends EN_UPDATE
notifications.
Rich Edit 2.0 and later: this flag is ignored and the EN_UPDATE notifications are always sent. However, if Rich Edit 3.0 emulates Rich Edit 1.0, you must use this flag to send EN_UPDATE notifications |
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:
call 'USER32.SendMessageA' D§hwndRichEdit &EM_SETEVENTMASK 0 &ENM_MOUSEEVENTS ..... ..... Proc MainWindowProc:
Arguments @hWnd, @uMsg, @wParam, @lParam ..... .... .elseif D@uMsg = &WM_NOTIFY push esi mov esi D@lParam .if D§esi+NMHDR.code = &EN_MSGFILTER .... [ do something here] .... .endif pop esi
____________________________________________________________________________________________ [IDD_OPTIONDLG 1000 IDC_BACKCOLORBOX 1001 IDC_TEXTCOLORBOX 1002 IDD_FINDDLG 2000 IDD_GOTODLG 3000 IDD_REPLACEDLG 4000 IDC_FINDEDIT 1000 IDC_MATCHCASE 1001 IDC_REPLACEEDIT 1001 IDC_WHOLEWORD 1002 IDC_DOWN 1003 IDC_UP 1004 IDC_LINENO 1005] [RichEditID 300] [ClassName: B§ 'IczEditClass',0 AppName : B§ 'IczEdit version 1.0',0 RichEditDLL: B§ 'riched20.dll',0 RichEditClass: B§ 'RichEdit20A',0 NoRichEdit: B§ 'Cannot find riched20.dll',0 ASMFilterString: B§ 'ASM Source code (*.asm)',0,'*.asm',0 B§ 'All Files (*.*)',0,'*.*',0,0 OpenFileFail: B§ 'Cannot open the file',0 WannaSave: B§ 'The data in the control is modified. Want to save it?',0] [FileOpened: D§ &FALSE BackgroundColor: D§ 0FFFFFF ; default to white TextColor: D§ 0] ; default to black [hInstance: D§ ? hRichEdit: D§ ? hwndRichEdit: D§ ?] [FileName: B§ ? #260] [AlternateFileName: B§ ? #260] [CustomColors: D§ ? #16] [FindBuffer: B§ ? #260] [ReplaceBuffer: B§ ? #260] [uFlags: ?] [FINDTEXT: @chrg: @chrg@cpMin: D§ 0 @chrg@cpMax: D§ 0 @lpstrText: D§ 0 @chrgText: @chrgText@cpMin: D§ 0 @chrgText@cpMax: D§ 0] ____________________________________________________________________________________________ ____________________________________________________________________________________________ [WNDCLASSEX: @cbSize: D§ len @style: D§ &CS_HREDRAW__&CS_VREDRAW @lpfnWndProc: D§ MainWindowProc @cbClsExtra: D§ 0 @cbWndExtra: D§ 0 @hInstance: D§ 0 @hIcon: D§ 0 @hCursor: D§ 0 @hbrBackground: D§ &COLOR_WINDOW+1 @lpszMenuName: D§ M00_Menu @lpszClassName: D§ ClassName @hIconSm: D§ 0] [MSG: @hwnd: D§ 0 @message: D§ 0 @wParam: D§ 0 @lParam: D§ 0 @time: D§ 0 @MSG@pt: @MSG@pt@x: D§ 0 @MSG@pt@y: D§ 0] [hwnd: D§ 0] [M00_Menu 1000 M00_Open 1001 M00_Close 1002 M00_Save 1003 M00_save_As 1004 M00_Exit 1005 M00_Undo 1006 M00_Redo 1007 M00_Copy 1008 M00_Cut 1009 M00_Paste 1010 M00_Delete 1011 M00_select_All 1012 M00_Find 1013 M00_Find_Next 1014 M00_Find_Prev 1015 M00_Replace 1016 M00_Go_To_Line 1017 M00_Options 1018] ____________________________________________________________________________________________ ____________________________________________________________________________________________ [&SCF_ALL 4] [ACCELERATORS: U§ &FVIRTKEY__&FNOINVERT &VK_F3 M00_Find_Next &FVIRTKEY__&FCONTROL__&FNOINVERT &VK_F3 M00_Find_Prev &FVIRTKEY__&FCONTROL__&FNOINVERT 'F' M00_Find &FVIRTKEY__&FCONTROL__&FNOINVERT 'G' M00_Go_To_Line &FVIRTKEY__&FCONTROL__&FNOINVERT+FLAGLAST 'R' M00_Replace] [ACCELNUMBER 5 FLAGLAST 080] [AccelHandle: 0 hSearch: 0] ____________________________________________________________________________________________ ____________________________________________________________________________________________ Main: call 'KERNEL32.GetModuleHandleA' &NULL mov D§hInstance eax, D§WNDCLASSEX@hInstance eax call 'KERNEL32.LoadLibraryA' RichEditDLL .If eax <> 0 mov D§hRichEdit eax .Else call 'USER32.MessageBoxA' 0 NoRichEdit AppName &MB_OK__&MB_ICONERROR | jmp L9>> .End_If call 'USER32.LoadIconA' &NULL &IDI_APPLICATION mov D§WNDCLASSEX@hIcon eax, D§WNDCLASSEX@hIconSm eax call 'USER32.LoadCursorA' &NULL &IDC_ARROW mov D§WNDCLASSEX@hCursor eax call 'USER32.RegisterClassExA' WNDCLASSEX call 'USER32.CreateWindowExA' &NULL ClassName AppName, &WS_OVERLAPPEDWINDOW &CW_USEDEFAULT, &CW_USEDEFAULT &CW_USEDEFAULT &CW_USEDEFAULT &NULL &NULL, D§hInstance &NULL mov D§hwnd eax call 'USER32.ShowWindow' D§hwnd &SW_SHOWNORMAL call 'USER32.UpdateWindow' D§hwnd call 'USER32.CreateAcceleratorTableA' ACCELERATORS ACCELNUMBER mov D§AccelHandle eax L1: call 'USER32.GetMessageA' MSG 0 0 0 | On eax = 0, jmp L8> call 'USER32.IsDialogMessage' D§hSearch MSG .If eax = 0 call 'USER32.TranslateAccelerator' D§hwnd D§AccelHandle MSG If eax = 0 call 'USER32.TranslateMessage' MSG call 'USER32.DispatchMessageA' MSG End_If .End_If jmp L1< L8: call 'KERNEL32.FreeLibrary' D§hRichEdit call 'USER32.DestroyAcceleratorTable' D§AccelHandle L9: call 'KERNEL32.ExitProcess' 0 ____________________________________________________________________________________________ ____________________________________________________________________________________________ Proc StreamInProc: arguments @hFile @pBuffer @NumBytes @pBytesRead call 'KERNEL32.ReadFile' D@hFile D@pBuffer D@NumBytes D@pBytesRead 0 xor eax 1 EndP Proc StreamOutProc: Arguments @hFile @pBuffer @NumBytes @pBytesWritten call 'KERNEL32.WriteFile' D@hFile D@pBuffer D@NumBytes D@pBytesWritten 0 xor eax 1 EndP Proc CheckModifyState: Argument @hWnd call 'USER32.SendMessageA' D§hwndRichEdit &EM_GETMODIFY 0 0 .If eax <> 0 call 'USER32.MessageBoxA' D§hWnd WannaSave AppName &MB_YESNOCANCEL If eax = &IDYES call 'USER32.SendMessageA' D@hWnd &WM_COMMAND M00_SAVE 0 Else _If eax = &IDCANCEL mov eax &FALSE | Exit End_If .Endif mov eax &TRUE EndP [CHARFORMAT: @cbSize: D§ 60 @dwMask: D§ &CFM_COLOR @dwEffects: D§ 0 ; &CFE_AUTOCOLOR ; ? @yHeight: D§ 0 @yOffset: D§ 0 @crTextColor: D§ 0 @bCharSet: B§ 0 @bPitchAndFamily: B§ 0] [@szFaceName: B§ 0 #32] ; &LF_FACESIZE [wPad2: W§ 0] SetColor: call 'USER32.SendMessageA' D§hwndRichEdit &EM_SETBKGNDCOLOR 0 D§BackgroundColor move D§CHARFORMAT@crTextColor D§TextColor call 'USER32.SendMessageA' D§hwndRichEdit &EM_SETCHARFORMAT &SCF_ALL CHARFORMAT ret [CHOOSECOLOR: @lStructSize: D§ len @hwndOwner: D§ 0 @hInstance: D§ 0 @rgbResult: D§ 0 @lpCustColors: D§ CustomColors @Flags: D§ &CC_RGBINIT @lCustData: D§ 0 @lpfnHook: D§ 0 @lpTemplateName: D§ 0] Proc OptionProc: Arguments @hWnd @uMsg @wParam @lParam pushad ...If D@uMsg = &WM_INITDIALOG ; returns &TRUE ...Else_If D@uMsg = &WM_COMMAND mov eax D@wParam | shr eax 16 ..If ax = &BN_CLICKED mov eax D@wParam .If ax = &IDCANCEL call 'USER32.SendMessageA' D@hWnd &WM_CLOSE 0 0 .Else_If ax = IDC_BACKCOLORBOX move D§CHOOSECOLOR@hwndOwner D@hwnd move D§ CHOOSECOLOR@hInstance D§hInstance Move D§CHOOSECOLOR@rgbResult D§BackgroundColor call 'COMDLG32.ChooseColorA' CHOOSECOLOR If eax <> 0 move D§BackgroundColor D§CHOOSECOLOR@rgbResult call 'USER32.GetDlgItem' D@hWnd IDC_BACKCOLORBOX call 'USER32.InvalidateRect' eax 0 &TRUE End_If .Else_If ax = IDC_TEXTCOLORBOX move D§CHOOSECOLOR@hwndOwner D@hwnd move D§ CHOOSECOLOR@hInstance D§hInstance move D§CHOOSECOLOR@rgbResult D§TextColor call 'COMDLG32.ChooseColorA' CHOOSECOLOR If eax <> 0 move D§TextColor D§CHOOSECOLOR@rgbResult call 'USER32.GetDlgItem' D@hWnd IDC_TEXTCOLORBOX call 'USER32.InvalidateRect' eax 0 &TRUE End_If .Else_If ax = &IDOK ;================================================================================ ; Save the modify state of the richedit control because changing the text color changes the ; modify state of the richedit control. ;================================================================================== call 'USER32.SendMessageA' D§hwndRichEdit &EM_GETMODIFY 0 0 push eax call SetColor pop eax call 'USER32.SendMessageA' D§hwndRichEdit &EM_SETMODIFY eax 0 call 'USER32.EndDialog' D@hWnd 0 .End_If ..End_If ...Else_If D@uMsg = &WM_CTLCOLORSTATIC call 'USER32.GetDlgItem' D@hWnd IDC_BACKCOLORBOX .If eax = D@lParam popad call 'GDI32.CreateSolidBrush' D§BackgroundColor Exit .Else call 'USER32.GetDlgItem' D@hWnd IDC_TEXTCOLORBOX If eax = D@lParam popad call 'GDI32.CreateSolidBrush' D§TextColor Exit End_If .End_If popad | mov eax &FALSE | Exit ...Else_If D@uMsg = &WM_CLOSE call 'USER32.EndDialog' D@hWnd 0 ...Else popad | mov eax &FALSE | Exit ...End_If popad | mov eax &TRUE EndP ____________________________________________________________________________________________ ____________________________________________________________________________________________ Proc SearchProc: Arguments @hWnd, @uMsg, @wParam, @lParam pushad ...If D@uMsg = &WM_INITDIALOG move D§hSearch D@hWnd ;=================================================== ; Select the default search down option ;=================================================== call 'USER32.CheckRadioButton' D@hWnd IDC_DOWN IDC_UP IDC_DOWN call 'USER32.SendDlgItemMessageA' D@hWnd IDC_FINDEDIT &WM_SETTEXT 0 FindBuffer ...Else_If D@uMsg = &WM_COMMAND mov eax D@wParam | shr eax 16 ..If ax = &BN_CLICKED mov eax D@wParam On ax = &IDCANCEL, call 'USER32.SendMessageA' D@hWnd &WM_CLOSE 0 0 If ax <> &IDOK mov eax &FALSE | Exit End_If mov D§uFlags 0 call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXGETSEL 0 FINDTEXT@chrg call 'USER32.GetDlgItemTextA' D@hWnd IDC_FINDEDIT FindBuffer 260 If eax = 0 mov eax &TRUE | Exit End_If call 'USER32.IsDlgButtonChecked' D@hWnd IDC_DOWN If eax = &BST_CHECKED or D§uFlags &FR_DOWN mov eax D§FINDTEXT@chrg@cpMin On eax <> D§FINDTEXT@chrg@cpMax, move D§FINDTEXT@chrg@cpMin D§FINDTEXT@chrg@cpMax mov D§FINDTEXT@chrg@cpMax 0-1 Else mov D§FINDTEXT@chrg@cpMax 0 End_If call 'USER32.IsDlgButtonChecked' D@hWnd IDC_MATCHCASE On eax = &BST_CHECKED, or D§uFlags &FR_MATCHCASE call 'USER32.IsDlgButtonChecked' D@hWnd IDC_WHOLEWORD On eax = &BST_CHECKED, or D§uFlags &FR_WHOLEWORD mov D§FINDTEXT@lpstrText FindBuffer call 'USER32.SendMessageA' D§hwndRichEdit &EM_FINDTEXTEX D§uFlags FINDTEXT On eax <> 0-1, call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXSETSEL 0, FINDTEXT@chrgText ..Else popad | mov eax &FALSE | Exit ..End_If ...Else_If D@uMsg = &WM_CLOSE mov D§hSearch 0 call 'USER32.EndDialog' D@hWnd 0 ...Else popad | mov eax &FALSE | Exit ...End_If popad | mov eax &TRUE EndP [&ST_SELECTION 2 &CP_ACP 0 &EM_SETTEXTEX 0461] Proc ReplaceProc: Arguments @hWnd, @uMsg, @wParam, @lParam Structure @SETTEXT 8, @SETTEXT.flags 0, @SETTEXT.codepage 4 ...If D@uMsg = &WM_INITDIALOG move D§hSearch D@hwnd call 'USER32.SetDlgItemTextA' D@hWnd IDC_FINDEDIT FindBuffer call 'USER32.SetDlgItemTextA' D@hWnd IDC_REPLACEEDIT ReplaceBuffer call 'USER32.GetDlgItem' D@hWnd IDC_REPLACEEDIT call 'USER32.SetFocus' eax ...Else_If D@uMsg = &WM_COMMAND mov eax D@wParam | shr eax 16 ..If ax = &BN_CLICKED mov eax D@wParam .If ax = &IDCANCEL call 'USER32.SendMessageA' D@hWnd &WM_CLOSE 0 0 .Else_If ax = &IDOK call 'USER32.GetDlgItemTextA' D@hWnd IDC_FINDEDIT FindBuffer 260 call 'USER32.GetDlgItemTextA' D@hWnd IDC_REPLACEEDIT ReplaceBuffer 260 mov D§FINDTEXT@chrg@cpMin 0 mov D§FINDTEXT@chrg@cpMax 0-1 mov D§FINDTEXT@lpstrText FindBuffer mov D@SETTEXT.flags &ST_SELECTION mov D@SETTEXT.codepage &CP_ACP L1: call 'USER32.SendMessageA' D§hwndRichEdit &EM_FINDTEXTEX &FR_DOWN FINDTEXT On eax = 0-1, jp L2> call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXSETSEL 0 FINDTEXT@chrgText call 'USER32.SendMessageA' D§hwndRichEdit &EM_SETTEXTEX D@SETTEXT ReplaceBuffer jmp L1< L2: .End_If ..End_If ...Else_If D@uMsg = &WM_CLOSE mov D§hSearch 0 | call 'USER32.EndDialog' D@hWnd 0 ...Else mov eax &FALSE | Exit ...End_If mov eax &TRUE EndP Proc GoToProc: Arguments @hWnd, @uMsg, @wParam, @lParam LOCAL @LineNo ...If D@uMsg = &WM_INITDIALOG move D§hSearch D@hwnd ...Else_If D@uMsg = &WM_COMMAND mov eax D@wParam | shr eax 16 ..If ax = &BN_CLICKED mov eax D@wParam .If ax = &IDCANCEL call 'USER32.SendMessageA' D@hWnd &WM_CLOSE 0 0 .Else_If ax = &IDOK call 'USER32.GetDlgItemInt' D@hWnd IDC_LINENO &NULL &FALSE mov D@LineNo eax call 'USER32.SendMessageA' D§hwndRichEdit &EM_GETLINECOUNT 0 0 If eax > D@LineNo call 'USER32.SendMessageA' D§hwndRichEdit &EM_LINEINDEX D@LineNo 0 call 'USER32.SendMessageA' D§hwndRichEdit &EM_SETSEL eax eax call 'USER32.SetFocus' D§hwndRichEdit End_If .End_If ..End_If ...Else_If D@uMsg = &WM_CLOSE mov D§hSearch 0 | call 'USER32.EndDialog' D@hWnd 0 ...Else mov eax &FALSE | Exit ...End_If mov eax &TRUE EndP Proc PrepareEditMenu: Argument @hSubMenu Structure @CHARRANGE 8, @CHARRANGE.cpMin 0, @CHARRANGE.cpMax 4 ;============================================================================= ; Check whether there is some text in the clipboard. If so, we enable the paste menuitem ;============================================================================= call 'USER32.SendMessageA' D§hwndRichEdit &EM_CANPASTE &CF_TEXT 0 If eax = 0 ; no text in the clipboard call 'USER32.EnableMenuItem' D@hSubMenu M00_PASTE &MF_GRAYED Else call 'USER32.EnableMenuItem' D@hSubMenu M00_PASTE &MF_ENABLED End_If ;========================================================== ; check whether the undo queue is empty ;========================================================== call 'USER32.SendMessageA' D§hwndRichEdit &EM_CANUNDO 0 0 If eax = 0 call 'USER32.EnableMenuItem' D@hSubMenu M00_UNDO &MF_GRAYED Else call 'USER32.EnableMenuItem' D@hSubMenu M00_UNDO &MF_ENABLED End_If ;========================================================= ; check whether the redo queue is empty ;========================================================= call 'USER32.SendMessageA' D§hwndRichEdit &EM_CANREDO 0 0 If eax = 0 call 'USER32.EnableMenuItem' D@hSubMenu M00_REDO &MF_GRAYED Else call 'USER32.EnableMenuItem' D@hSubMenu M00_REDO &MF_ENABLED End_If ;========================================================= ; check whether there is a current selection in the richedit control. ; If there is, we enable the cut/copy/delete menuitem ;========================================================= call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXGETSEL 0 D@CHARRANGE mov eax D@CHARRANGE.cpMin If eax = D@CHARRANGE.cpMax ; no current selection call 'USER32.EnableMenuItem' D@hSubMenu M00_COPY &MF_GRAYED call 'USER32.EnableMenuItem' D@hSubMenu M00_CUT &MF_GRAYED call 'USER32.EnableMenuItem' D@hSubMenu M00_DELETE &MF_GRAYED Else call 'USER32.EnableMenuItem' D@hSubMenu M00_COPY &MF_ENABLED call 'USER32.EnableMenuItem' D@hSubMenu M00_CUT &MF_ENABLED call 'USER32.EnableMenuItem' D@hSubMenu M00_DELETE &MF_ENABLED End_If EndP ____________________________________________________________________________________________ ____________________________________________________________________________________________ ____________________________________________________________________________________________ [CHARRANGE: @cpMin: D§ 0 @cpMax: D§ 0] [OPENFILENAME: @lStructSize: D§ Len @hWndOwner: D§ 0 @hInstance: D§ 0 @lpstrFilter: D§ ASMFilterString @lpstrCustomFilter: D§ 0 @nMaxCustFilter: D§ 0 @nFilterIndex: D§ 0 @lpstrFile: D§ FileName @nMaxFile: D§ 260 @lpstrFileTitle: D§ 0 @nMaxFileTitle: D§ 260 @lpstrInitialDir: D§ 0 @lpstrTitle: D§ 0 @Flags: D§ 0 @nFileOffset: W§ 0 @nFileExtension: W§ 0 @lpstrDefExt: D§ 0 @lCustData: D§ 0 @lpfnHook: D§ 0 @lpTemplateName: D§ 0] [Buffer: B§ ? #256] [EDITSTREAM: @dwCookie: D§ 0 @dwError: D§ 0 @pfnCallback: D§ 0] [hFile: 0 hPopup: 0] [Pt: Pt.X: 0 Pt.Y: 0] Proc MainWindowProc: Arguments @hWnd @uMsg @wParam @lParam pushad ...If D@uMsg = &WM_CREATE call 'USER32.CreateWindowExA' &WS_EX_CLIENTEDGE RichEditClass 0, &WS_CHILD__&WS_VISIBLE__&ES_MULTILINE__&WS_VSCROLL__&WS_HSCROLL__&ES_NOHIDESEL, &CW_USEDEFAULT &CW_USEDEFAULT &CW_USEDEFAULT &CW_USEDEFAULT D@hWnd, RichEditID D§hInstance 0 mov D§hwndRichEdit eax ;============================================================= ; Set the text limit. The default is 64K ;============================================================= call 'USER32.SendMessageA' D§hwndRichEdit &EM_LIMITTEXT 0-1 0 ;============================================================= ; Set the default text/background color ;============================================================= call SetColor call 'USER32.SendMessageA' D§hwndRichEdit &EM_SETMODIFY &FALSE 0 call 'USER32.SendMessageA' D§hwndRichEdit &EM_EMPTYUNDOBUFFER 0 0 ...Else_If D@uMsg = &WM_NOTIFY ;[MSGFILTER: ; @nmhdr: @NMHDR@hwndFrom: D§ 0 ; +0 ; @NMHDR@idfrom: D§ 0 ; +4 ; @NMHDR@code: D§ 0 ; +8 ; @msg: D§ 0 ; +12 ; @wParam: D§ 0 ; +16 ; @lParam: D§ 0] ; +20 push esi mov esi D@lParam .If D§esi+8 = &EN_MSGFILTER .If D§esi+12 = &WM_RBUTTONDOWN call 'USER32.GetMenu' D@hWnd call 'USER32.GetSubMenu' eax 1 | mov D§hPopup eax call PrepareEditMenu D§hPopup mov edx D§esi+20, ecx edx and edx 0FFFF | shr ecx 16 mov D§Pt.X edx, D§Pt.Y ecx call 'USER32.ClientToScreen' D@hWnd Pt call 'USER32.TrackPopupMenu' D§hPopup &TPM_LEFTALIGN__&TPM_BOTTOMALIGN, D§Pt.X D§Pt.Y &NULL D@hWnd &NULL .End_If .End_If pop esi ...Else_If D@uMsg = &WM_INITMENUPOPUP mov eax D@lParam ..If ax = 0 ; file menu .If D§FileOpened = &TRUE ; a file is already opened call 'USER32.EnableMenuItem' D@wParam M00_OPEN &MF_GRAYED call 'USER32.EnableMenuItem' D@wParam M00_CLOSE &MF_ENABLED call 'USER32.EnableMenuItem' D@wParam M00_SAVE &MF_ENABLED call 'USER32.EnableMenuItem' D@wParam M00_SAVEAS &MF_ENABLED .Else call 'USER32.EnableMenuItem' D@wParam M00_OPEN &MF_ENABLED call 'USER32.EnableMenuItem' D@wParam M00_CLOSE &MF_GRAYED call 'USER32.EnableMenuItem' D@wParam M00_SAVE &MF_GRAYED call 'USER32.EnableMenuItem' D@wParam M00_SAVEAS &MF_GRAYED .End_If ..Else_If ax = 1 ; edit menu call PrepareEditMenu D@wParam ..Else_If ax = 2 ; search menu bar .If B§FileOpened = &TRUE call 'USER32.EnableMenuItem' D@wParam M00_FIND &MF_ENABLED call 'USER32.EnableMenuItem' D@wParam M00_FINDNEXT &MF_ENABLED call 'USER32.EnableMenuItem' D@wParam M00_FINDPREV &MF_ENABLED call 'USER32.EnableMenuItem' D@wParam M00_REPLACE &MF_ENABLED call 'USER32.EnableMenuItem' D@wParam M00_GOTOLINE &MF_ENABLED .Else call 'USER32.EnableMenuItem' D@wParam M00_FIND &MF_GRAYED call 'USER32.EnableMenuItem' D@wParam M00_FINDNEXT &MF_GRAYED call 'USER32.EnableMenuItem' D@wParam M00_FINDPREV &MF_GRAYED call 'USER32.EnableMenuItem' D@wParam M00_REPLACE &MF_GRAYED call 'USER32.EnableMenuItem' D@wParam M00_GOTOLINE &MF_GRAYED .End_If ..End_If ...Else_If D@uMsg = &WM_COMMAND ..If D@lParam = 0 ; menu commands mov eax D@wParam .If ax = M00_OPEN call OpenCommand D@hWnd .Else_If ax = M00_CLOSE call CheckModifyState D@hWnd If eax = &TRUE call 'USER32.SetWindowTextA' D§hwndRichEdit 0 mov D§FileOpened &FALSE End_If .Else_If ax = M00_SAVE call 'KERNEL32.CreateFileA' FileName &GENERIC_WRITE &FILE_SHARE_READ, &NULL &CREATE_ALWAYS &FILE_ATTRIBUTE_NORMAL 0 If eax <> &INVALID_HANDLE_VALUE call InvalidFile Else call 'USER32.MessageBoxA' D@hWnd OpenFileFail AppName, &MB_OK__&MB_ICONERROR End_If .Else_If ax = M00_COPY call 'USER32.SendMessageA' D§hwndRichEdit &WM_COPY 0 0 .Else_If ax = M00_CUT call 'USER32.SendMessageA' D§hwndRichEdit &WM_CUT 0 0 .Else_If ax = M00_PASTE call 'USER32.SendMessageA' D§hwndRichEdit &WM_PASTE 0 0 .Else_If ax = M00_DELETE call 'USER32.SendMessageA' D§hwndRichEdit &EM_REPLACESEL &TRUE 0 .Else_If ax = M00_SELECTALL mov D§CHARRANGE@cpMin 0 mov D§CHARRANGE@cpMax 0-1 call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXSETSEL 0 CHARRANGE .Else_If ax = M00_UNDO call 'USER32.SendMessageA' D§hwndRichEdit &EM_UNDO 0 0 .Else_If ax = M00_REDO call 'USER32.SendMessageA' D§hwndRichEdit &EM_REDO 0 0 .Else_If ax = M00_OPTIONS call 'USER32.DialogBoxParamA' D§hInstance IDD_OPTIONDLG D@hWnd OptionProc 0 .Else_If ax = M00_SAVEAS move D§OPENFILENAME@hwndOwner D@hwnd move D§OPENFILENAME@hInstance D§hInstance mov D§OPENFILENAME@lpstrFilter ASMFilterString mov D§OPENFILENAME@lpstrFile AlternateFileName mov D§AlternateFileName 0 mov D§OPENFILENAME@Flags &OFN_FILEMUSTEXIST__&OFN_HIDEREADONLY__&OFN_PATHMUSTEXIST call 'COMDLG32.GetSaveFileNameA' OPENFILENAME If eax <> 0 call 'KERNEL32.CreateFileA' AlternateFileName &GENERIC_WRITE, &FILE_SHARE_READ &NULL &CREATE_ALWAYS, &FILE_ATTRIBUTE_NORMAL 0 On eax <> &INVALID_HANDLE_VALUE, call InvalidFile End_If .Else_If ax = M00_FIND On D§hSearch = 0, call 'USER32.CreateDialogParamA' D§hInstance IDD_FINDDLG D@hWnd SearchProc 0 call 'USER32.GetDlgItem' eax IDC_FINDEDIT call 'USER32.SetFocus' eax .Else_If ax = M00_REPLACE On D§hSearch = 0, call 'USER32.CreateDialogParamA' D§hInstance IDD_REPLACEDLG D@hWnd, ReplaceProc 0 call 'USER32.GetDlgItem' eax IDC_FINDEDIT call 'USER32.SetFocus' eax .Else_If ax = M00_GO_TO_LINE On D§hSearch = 0 call 'USER32.CreateDialogParamA' D§hInstance IDD_GOTODLG D@hWnd GoToProc 0 call 'USER32.GetDlgItem' eax IDC_LINENO call 'USER32.SetFocus' eax .Else_If ax = M00_FIND_NEXT call 'KERNEL32.lstrlen' FindBuffer If eax = 0 popad | mov eax &FALSE | Exit End_If call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXGETSEL 0 FINDTEXT@chrg mov eax D§FINDTEXT@chrg@cpMin On eax <> D§FINDTEXT@chrg@cpMax, move D§FINDTEXT@chrg@cpMin, D§FINDTEXT@chrg@cpMax mov D§FINDTEXT@chrg@cpMax 0-1 mov D§FINDTEXT@lpstrText FindBuffer call 'USER32.SendMessageA' D§hwndRichEdit &EM_FINDTEXTEX &FR_DOWN, findtext On eax <> 0-1, call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXSETSEL 0, FINDTEXT@chrgText .Else_If ax = M00_FIND_PREV call 'KERNEL32.lstrlen' FindBuffer If eax <> 0 call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXGETSEL 0 FINDTEXT@chrg mov D§FINDTEXT@chrg@cpMax 0 mov D§FINDTEXT@lpstrText FindBuffer call 'USER32.SendMessageA' D§hwndRichEdit &EM_FINDTEXTEX 0 findtext On eax <> 0-1, call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXSETSEL 0, FINDTEXT@chrgText End_If .Else_If ax = M00_EXIT call 'USER32.SendMessageA' D@hWnd &WM_CLOSE 0 0 .End_If ..End_If ...Else_If D@uMsg = &WM_CLOSE call CheckModifyState D@hWnd On eax = &TRUE, call 'USER32.DestroyWindow' D@hWnd ...Else_If D@uMsg = &WM_SIZE mov eax D@lParam, edx eax and eax 0FFFF | shr edx 16 call 'USER32.MoveWindow' D§hwndRichEdit 0 0 eax edx &TRUE ...Else_If D@uMsg = &WM_DESTROY call 'USER32.PostQuitMessage' &NULL ...Else popad call 'USER32.DefWindowProcA' D@hWnd D@uMsg D@wParam D@lParam Exit ...End_If popad | mov eax &FALSE EndP InvalidFile: mov D§hFile eax _____________________________ ; stream the text to the file _____________________________ mov D§EDITSTREAM@dwCookie eax mov D§EDITSTREAM@pfnCallback StreamOutProc call 'USER32.SendMessageA' D§hwndRichEdit &EM_STREAMOUT &SF_TEXT EDITSTREAM ______________________________________ ; Initialize the modify state to false ______________________________________ call 'USER32.SendMessageA' D§hwndRichEdit &EM_SETMODIFY &FALSE 0 call 'KERNEL32.CloseHandle' D§hFile ret Proc OpenCommand: Argument @hWnd move D§OPENFILENAME@hwndOwner D@hWnd move D§OPENFILENAME@hInstance D§hInstance mov D§FileName 0 mov D§OPENFILENAME@Flags &OFN_FILEMUSTEXIST__&OFN_HIDEREADONLY__&OFN_PATHMUSTEXIST call 'COMDLG32.GetOpenFileNameA' OPENFILENAME ...If eax <> 0 call 'KERNEL32.CreateFileA' FileName &GENERIC_READ, &FILE_SHARE_READ &NULL, &OPEN_EXISTING &FILE_ATTRIBUTE_NORMAL 0 .If eax <> &INVALID_HANDLE_VALUE mov D§hFile eax ___________________________________________ ; stream the text into the richedit control ___________________________________________ mov D§EDITSTREAM@dwCookie eax mov D§EDITSTREAM@pfnCallback StreamInProc call 'USER32.SendMessageA' D§hwndRichEdit &EM_STREAMIN, &SF_TEXT EDITSTREAM ______________________________________ ; Initialize the modify state to false ______________________________________ call 'USER32.SendMessageA' D§hwndRichEdit &EM_SETMODIFY &FALSE 0 call 'KERNEL32.CloseHandle' D§hFile mov B§FileOpened &TRUE .Else call 'USER32.MessageBoxA' D@hWnd OpenFileFail AppName, &MB_OK__&MB_ICONERROR .End_If ...End_If EndP
call 'USER32.GetDlgItemTextA' D@hWnd IDC_FINDEDIT FindBuffer 260 If eax = 0When the user types the text to search for and then press OK button, we get the text to be searched for into FindBuffer.
mov D§uFlags 0 call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXGETSEL 0 FINDTEXT@chrgIf the text string is not null, we continue to initialize uFlags variable to 0.This variable is used to store the search flags used withEM_FINDTEXTEX. After that, we obtain the current selection with EM_EXGETSEL because we need to know the starting point of the search operation.
call 'USER32.IsDlgButtonChecked' D@hWnd IDC_DOWN If eax = &BST_CHECKED or D§uFlags &FR_DOWN mov eax D§FINDTEXT@chrg@cpMin On eax <> D§FINDTEXT@chrg@cpMax, move D§FINDTEXT@chrg@cpMin D§FINDTEXT@chrg@cpMax mov D§FINDTEXT@chrg@cpMax 0-1 Else mov D§FINDTEXT@chrg@cpMax 0 End_IfThe 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 that of cpMin and change the value of cpMax to -1 (0FFFFFFFFh). If there 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.
call 'USER32.IsDlgButtonChecked' D@hWnd IDC_MATCHCASE On eax = &BST_CHECKED, or D§uFlags &FR_MATCHCASE call 'USER32.IsDlgButtonChecked' D@hWnd IDC_WHOLEWORD On eax = &BST_CHECKED, or D§uFlags &FR_WHOLEWORD mov D§FINDTEXT@lpstrText FindBufferWe continue to check the checkboxes for the search flags, ie, FR_MATCHCASE and FR_WHOLEWORD. Lastly, we put the offset of the text to search for in lpstrText member.
call 'USER32.SendMessageA' D§hwndRichEdit &EM_FINDTEXTEX D§uFlags FINDTEXT On eax <> 0-1, call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXSETSEL 0, FINDTEXT@chrgTextWe 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 proceed to select it with EM_EXSETSEL.
The replace operation is done in much the same manner.
call 'USER32.GetDlgItemTextA' D@hWnd IDC_FINDEDIT FindBuffer 260 call 'USER32.GetDlgItemTextA' D@hWnd IDC_REPLACEEDIT ReplaceBuffer 260We retrieve the text to search for and the text used to replace.
mov D§FINDTEXT@chrg@cpMin 0 mov D§FINDTEXT@chrg@cpMax 0-1 mov D§FINDTEXT@lpstrText FindBufferTo make it easy, the replace operation affects all the text in the control. Thus the starting index is 0 and the ending index is -1.
mov D@SETTEXT.flags &ST_SELECTION mov D@SETTEXT.codepage &CP_ACPWe initialize SETTEXTEX structure to indicate that we want to replace the current selection and use the default system code page.
L1: call 'USER32.SendMessageA' D§hwndRichEdit &EM_FINDTEXTEX &FR_DOWN FINDTEXT On eax = 0-1, jp L2> call 'USER32.SendMessageA' D§hwndRichEdit &EM_EXSETSEL 0 FINDTEXT@chrgText call 'USER32.SendMessageA' D§hwndRichEdit &EM_SETTEXTEX D@SETTEXT ReplaceBuffer jmp L1<We enter an infinite loop, searching 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. When the user clicks Go To Line menuitem, we display a dialog box below:
When the user types a line number and presses Ok button, we begin the operation.
call 'USER32.GetDlgItemInt' D@hWnd IDC_LINENO &NULL &FALSE mov D@LineNo eaxObtain the line number from the edit control
call 'USER32.SendMessageA' D§hwndRichEdit &EM_GETLINECOUNT 0 0 If eax > D@LineNoObtain the number of lines in the control. Check whether the user specifies the line number that is out of the range.
call 'USER32.SendMessageA' D§hwndRichEdit &EM_LINEINDEX D@LineNo 0If 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.
call 'USER32.SendMessageA' D§hwndRichEdit &EM_SETSEL eax eaxTo 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).
call 'USER32.SetFocus' D§hwndRichEdit End_IfThe caret will not be displayed unless the richedit control has the focus. So we call SetFocus on it.