cnpaf.net - 中国协议分析网

投递文章 投稿指南 RSS订阅 网站通告:
搜索: 您的位置主页>网络安全>工具使用>阅读文章

RichEdit 控件:更多的正文操作

12-20 13:41 来源: 作者: 【 评论:0 浏览:
Theory

Searching for Text

RichEdit 控件具有几种正文操作,搜索指定正文就是其中的一种。
搜索正文是通过发送 EM_FINDTEXT 或者 EM_FINDTEXTEX 消息来完成的。
这两个消息有一点很小的不同点。

EM_FINDTEXTwParam == 搜索选项。 可以是下表中的任意组合值。
这些选项对 EM_FINDTEXT 和 EM_FINDTEXTEX 都是一样的。
FR_DOWN如果指定了这个标志值,搜索操作从当前选定的 end 位置开始,直到控件中正文的 end 位置结束(向下搜索)。这个标志仅影响 RichEdit 2.0 和以后版本: 这个是 RichEdit 1.0 的缺省行为。RichEdit 2.0 或以后版本的缺省行为是在当前选定正文内的从结尾搜索到开始位置(向前搜索)。
概括来说就是,如果你使用 RichEdit 1.0, 无论你做什么都没法影响搜索的方向:它总使用向后搜索。但是如果你使用 RichEdit 2.0 而且你想使用向后搜索的话,你必须指定这个标志值,否则使用的是向前搜索了。
FR_MATCHCASE如果指定了这个标志值,搜索操作是大小写敏感的,即区分大小写。
FR_WHOLEWORD如果设置了这个标志值,搜索操作就搜寻匹配指定搜索串的整个词。
实际上,还有更多的标志值,但是它们都是跟非英语系正文操作相关的。lParam == FINDTEXT 结构的指针。			FINDTEXT STRUCT			  chrg          CHARRANGE  <>			  lpstrText     DWORD      ?			FINDTEXT ENDSchrg 是一个 CHARRANGE 结构,其定义如下:			CHARRANGE STRUCT			  cpMin  DWORD      ?			  cpMax  DWORD      ?			CHARRANGE ENDScpMin 包含字符数组中第一个字符的字符索引。cpMax 包含紧跟在字符数组中最后一个字符的字符的字符索引。
基本上,要搜索一个正文串,你必须指定要搜索的字符范围。
cpMin 和 cpMax 的具体意义根据搜索是向后还是向前是不同的。
如果是向后搜索,cpMin 指定搜索的开始字符索引,
而 cpMax 则是结束字符索引。
如果是向前搜索,则反过来才对,
也就是说 cpMin 包含结束字符索引而cpMax 包含开始字符索引。
lpstrText 是要搜索的正文串的指针。
EM_FINDTEXT 返回控件中跟搜索串匹配的的正文串的一个字符的索引。
如果没找到匹配的则返回 -1。
EM_FINDTEXTEXwParam == 搜索选项,跟 EM_FINDTEXT 的一样。lParam == FINDTEXTEX 结构的指针。			FINDTEXTEX STRUCT			  chrg          CHARRANGE  <>			  lpstrText     DWORD      ?			  chrgText	CHARRANGE <>			FINDTEXTEX ENDSFINDTEXTEX 中开始的两个成员是跟 FINDTEXT 结构中的一样的。
chrgText 是一个 CHARRANGE 结构,如果搜索到匹配串的话,
其开始/结束字符索引会被填入这个结构中。
EM_FINDTEXTEX 的返回值跟 EM_FINDTEXT的是一样的。
EM_FINDTEXT 跟 EM_FINDTEXTEX 的不同处
是 FINDTEXTEX 结构有一个另外的chrgText成员,
如果搜索到匹配串的话, 其开始/结束字符索引会被填入这个成员中。
如果我们想对这个正文串进行更多的正文操作的话,有这个就方便多了。

替换/插入正文

RichEdit 控件提供了 EM_SETTEXTEX 来进行正文替换/插入操作。
这个消息混合了 WM_SETTEXT 和 EM_REPLACESEL 的功能. 它具有以下语法:

	EM_SETTEXTEX	wParam == SETTEXTEX 结构的指针。			SETTEXTEX STRUCT			  flags          DWORD      ?			  codepage       DWORD      ?			SETTEXTEX ENDS	flags 可以是以下值的组合:
ST_DEFAULT删除Undo堆栈,丢弃RTF格式,替换所有的正文。
ST_KEEPUNDO保留Undo堆栈。
ST_SELECTION替换选定正文并且保留RTF格式
	codepage 是一个常量,指定你的正文想要的代码页。我们通常简单的使用 CP_ACP。

正文选择

我们可以使用消息 EM_SETSEL 或者 EM_EXSETSEL 来编程选择正文.
其中任意的一个都可以工作的很好。要使用哪一个消息要根据可用的字符索引格式来选择。
如果它们保存在一个 CHARRANGE 结构中,则使用 EM_EXSETSEL更容易实现。

	EM_EXSETSEL	wParam == 没有使用,必须为 0 。	lParam == CHARRANGE 结构的指针,包含想要选定的正文字符范围。

事件通知

在使用多行Edit控件时,你必须子类化它以便得到输入信息象鼠标/键盘事件等。
RichEdit 控件提供了一个更好的方案,它可以把这些消息通知父窗口。
为了注册得到通知消息,父窗口发送 EM_SETEVENTMASK 消息给 RichEdit 控件,
指定它对哪些消息感兴趣。
EM_SETEVENTMASK 具有以下的语法:

	EM_SETEVENTMASK	wParam == 没有使用,必须为 0 。	lParam == 事件掩码值。他可以是以下表格里标志值的任意组合。
ENM_CHANGE发送 EN_CHANGE 通知
ENM_CORRECTTEXT发送 EN_CORRECTTEXT 通知
ENM_DRAGDROPDONE发送 EN_DRAGDROPDONE 通知
ENM_DROPFILES发送 EN_DROPFILES 通知
ENM_KEYEVENTS为键盘消息发送 EN_MSGFILTER 通知
ENM_LINKRich Edit 2.0 或以后版本: 当鼠标在具有 CFE_LINK 风格的正文上面移过,而且执行了一个或几个鼠标动作时,就发送 EN_LINK 通知。
ENM_MOUSEEVENTS为鼠标消息发送 EN_MSGFILTER 通知。
ENM_OBJECTPOSITIONS发送 EN_OBJECTPOSITIONS 通知
ENM_PROTECTED发送 EN_PROTECTED 通知
ENM_REQUESTRESIZE发送 EN_REQUESTRESIZE 通知
ENM_SCROLL发送 EN_HSCROLL 和 EN_VSCROLL 通知
ENM_SCROLLEVENTS为鼠标滑轮发送 EN_MSGFILTER 通知。
ENM_SELCHANGE发送 EN_SELCHANGE 通知
ENM_UPDATE

发送 EN_UPDATE 通知
Rich Edit 2.0 和以后版本: 这个标志值会被忽略,而经常发送 EN_UPDATE 通知。然而如果 RichEdit 3.0 模拟 RichEdit 1.0的话,你必须使用这个标志值来发送 EN_UPDATE 通知

上面的所有通知都被做为 WM_NOTIFY 消息来发送:你必须检查 NMHDR 结构的
code 成员来得到通知消息。譬如,如果你想注册得到鼠标消息(也就是说,
你想提供一给上下文相关的弹出菜单), 你需要象下面这样做:

	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 .... [ do something here] .... .endif pop esi

例子:

下面的例子是第33篇指南里的 IczEdit 的改进版。
它为程序增加了搜索/替换功能和加速键。同时它处理鼠标消息,点右键时会出现一个弹出菜单。

.386.model flat,stdcalloption casemap:noneinclude \masm32\include\windows.incinclude \masm32\include\user32.incinclude \masm32\include\comdlg32.incinclude \masm32\include\gdi32.incinclude \masm32\include\kernel32.incincludelib \masm32\lib\gdi32.libincludelib \masm32\lib\comdlg32.libincludelib \masm32\lib\user32.libincludelib \masm32\lib\kernel32.libWinMain proto :DWORD,:DWORD,:DWORD,:DWORD.constIDR_MAINMENU                   equ 101IDM_OPEN                      equ  40001IDM_SAVE                       equ 40002IDM_CLOSE                      equ 40003IDM_SAVEAS                     equ 40004IDM_EXIT                       equ 40005IDM_COPY                      equ  40006IDM_CUT                       equ  40007IDM_PASTE                      equ 40008IDM_DELETE                     equ 40009IDM_SELECTALL                  equ 40010IDM_OPTION 			equ 40011IDM_UNDO			equ 40012IDM_REDO			equ 40013IDD_OPTIONDLG                  equ 101IDC_BACKCOLORBOX               equ 1000IDC_TEXTCOLORBOX               equ 1001IDR_MAINACCEL                 equ  105IDD_FINDDLG                    equ 102IDD_GOTODLG                    equ 103IDD_REPLACEDLG                 equ 104IDC_FINDEDIT                  equ  1000IDC_MATCHCASE                  equ 1001IDC_REPLACEEDIT                 equ 1001IDC_WHOLEWORD                  equ 1002IDC_DOWN                       equ 1003IDC_UP                       equ   1004IDC_LINENO                   equ   1005IDM_FIND                       equ 40014IDM_FINDNEXT                  equ  40015IDM_REPLACE                     equ 40016IDM_GOTOLINE                   equ 40017IDM_FINDPREV                  equ  40018RichEditID 			equ 300.dataClassName db "IczEditClass",0AppName  db "IczEdit version 2.0",0RichEditDLL db "riched20.dll",0RichEditClass db "RichEdit20A",0NoRichEdit db "Cannot find riched20.dll",0ASMFilterString 		db "ASM Source code (*.asm)",0,"*.asm",0				db "All Files (*.*)",0,"*.*",0,0OpenFileFail db "Cannot open the file",0WannaSave db "The data in the control is modified. Want to save it?",0FileOpened dd FALSEBackgroundColor dd 0FFFFFFh		; default to whiteTextColor dd 0		; default to blackhSearch dd ?		; handle to the search/replace dialog boxhAccel 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 <>.codestart:	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 .end if 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 .end if .end if .endw mov eax,msg.wParam retWinMain endpStreamInProc proc hFile:
DWORD,pBuffer:DWORD, NumBytes:DWORD, pBytesRead:DWORD invoke ReadFile,hFile,pBuffer,NumBytes,pBytesRead,0 xor eax,1 retStreamInProc endpStreamOutProc proc hFile:DWORD,
pBuffer:DWORD, NumBytes:DWORD, pBytesWritten:DWORD invoke WriteFile,hFile,pBuffer,NumBytes,pBytesWritten,0 xor eax,1 retStreamOutProc endpCheckModifyState 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 .end if .end if mov eax,TRUE retCheckModifyState endpSetColor 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 retSetColor endpOptionProc 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 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 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 .end if .end if mov eax,FALSE ret .elseif uMsg==WM_CLOSE invoke EndDialog,hWnd,0 .else mov eax,FALSE ret .end if mov eax,TRUE retOptionProc endpSearchProc 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 .end if mov findtext.chrg.cpMax,-1 .else mov findtext.chrg.cpMax,0 .end if invoke IsDlgButtonChecked,hWnd,IDC_MATCHCASE .if eax==BST_CHECKED or uFlags,FR_MATCHCASE .end if invoke IsDlgButtonChecked,hWnd,IDC_WHOLEWORD .if eax==BST_CHECKED or uFlags,FR_WHOLEWORD .end if 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 .end if .end if .elseif ax==IDCANCEL invoke SendMessage,hWnd,WM_CLOSE,0,0 .else mov eax,FALSE ret .end if .end if .elseif uMsg==WM_CLOSE mov hSearch,0 invoke EndDialog,hWnd,0 .else mov eax,FALSE ret .end if mov eax,TRUE retSearchProc endpReplaceProc 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,hwndRichEd
it,EM_FINDTEXTEX,FR_DOWN,addr findtext .if eax==-1 .break .else invoke SendMessage,hwndRichEd
it,EM_EXSETSEL,0,addr findtext.chrgText invoke SendMessage,hwndRichEd
it,EM_SETTEXTEX,addr settext,addr ReplaceBuffer .end if .endw .end if .end if .elseif uMsg==WM_CLOSE mov hSearch,0 invoke EndDialog,hWnd,0 .else mov eax,FALSE ret .endif mov eax,TRUE retReplaceProc endpGoToProc 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 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_GETLINECOUNT,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 .else mov eax,FALSE ret .end if mov eax,TRUE retGoToProc endpPrepareEditMenu 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 .else 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 .else 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 .else 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 .else invoke EnableMenuItem,hSubMenu,IDM_COPY,MF_ENABLED invoke EnableMenuItem,hSubMenu,IDM_CUT,MF_ENABLED invoke EnableMenuItem,hSubMenu,IDM_DELETE,MF_ENABLED .end if retPrepareEditMenu endpWndProc 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 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 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 .end if .end if 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 .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 ; 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_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 .end if .end if .elseif uMsg==WM_COMMAND .if lParam==0 ; menu commands 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 ;============================================== ; stream the text 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 .else invoke MessageBox,hWnd,addr OpenFileFail
,addr AppName,MB_OK or MB_ICONERROR .end if .end if .elseif ax==IDM_CLOSE invoke CheckModifyState,hWnd .if eax==TRUE invoke SetWindowText,hwndRichEdit,0 mov FileOpened,FALSE .end if .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 ;============================================== ; 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,0 invoke CloseHandle,hFile .else invoke MessageBox,hWnd,addr OpenFileFail
,addr AppName,MB_OK or MB_ICONERROR .end if .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 .end if .end if .elseif ax==IDM_FIND .if hSearch==0 invoke CreateDialogParam,hInstance
,IDD_FINDDLG,hWnd,addr SearchProc,0 .end if .elseif ax==IDM_REPLACE .if hSearch==0 invoke CreateDialogParam,hInstance
,IDD_REPLACEDLG,hWnd,addr ReplaceProc,0 .end if .elseif ax==IDM_GOTOLINE .if hSearch==0 invoke CreateDialogParam,hInstance
,IDD_GOTODLG,hWnd,addr GoToProc,0 .end if .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 .end if 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 .end if .end if .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 .end if .end if .elseif ax==IDM_EXIT invoke SendMessage,hWnd,WM_CLOSE,0,0 .end if .end if .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 .else invoke DefWindowProc,hWnd,uMsg,wParam,lParam ret .end if xor eax,eax retWndProc endpend start

分析

文本搜索功能是使用EM_FINDTEXTEX 来实现的。当用户点击Find菜单项时,
IDM_FIND 消息就会被发送,并显示一个 搜索 对话框。

	invoke GetDlgItemText,
hWnd,IDC_FINDEDIT,addr FindBuffer,sizeof FindBuffer .if eax!=0

当用户输入搜索正文,按下Ok按钮后,我们从FindBuffer缓冲区中得到要搜索的正文串。

		mov uFlags,0 		invoke SendMessage,
hwndRichEdit,EM_EXGETSEL,0,addr findtext.chrg

如果正文串不为空,我们就继续初始化uFlags 变量为 0 。
这个变量被用来保存跟 EM_FINDTEXTEX 一起使用的搜索标志。
之后,通过 EM_EXGETSEL ,我们得到当前选定的正文,
因为我们需要知道搜索操作的开始位置。

	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

下一步就有一点精巧了。我们检查搜索方向Radio按钮来得到要按什么方向进行搜索。
如果是向下搜索,我们设置 uFlags 为FR_DOWN 标志值。然后我们比较 cpMin 和 cpMax,
检查是否要在选定的正文里搜索。如果两者的值不相等,说明有当前选定正文,
我们需要从选定正文的结尾开始搜索,到控件中的正文的结尾结束。
从而我们需要替换 cpMax 的值为 cpMin ,并改变 cpMax 的值为 -1 (0FFFFFFFFh)。
如果没有当前选定正文,搜索的范围是从当前插入点(光标)到所有正文的结尾。

如果用户选择了向前搜索,我们使用的范围是从选定正文的开始到控件中正文的开始处。
这个就是我们只改变 cpMax 的值为 0 原因。在使用向前搜索的情况下,
cpMin 包含搜索范围中最后一个字符的的字符索引。
而cpMax 则是搜索范围中第一个字符的字符索引。向后搜索则刚刚相反。

		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

我们继续检查搜索标志的检查框,也就是 FR_MATCHCASE and FR_WHOLEWORD。
最后,我们把要搜索的正文串的偏移量放入 lpstrText 成员中。

		invoke SendMessage,hwndRichEdit,EM_FINDTEXTEX,uFlags,addr findtext		.if eax!=-1			invoke SendMessage,hwndRichEdit,
EM_EXSETSEL,0,addr findtext.chrgText .endif .endif

现在我们已经准备好发送 EM_FINDTEXTEX 消息了。之后,
我们检查通过 SendMessage 返回的搜索结果。如果返回 -1,
表示没有找到匹配的正文串。否则,FINDTEXTEX 结构的 chrgText
成员里会被填入匹配正文串的字符索引。
因此我们继续使用 EM_EXSETSEL 消息来选定该正文串。

替换操作也是以差不多的方式来完成。

	invoke GetDlgItemTe
xt,hWnd,IDC_FINDEDIT,addr FindBuffer,sizeof FindBuffer invoke GetDlgItemText,hWnd,IDC_REPLACEED
IT,addr ReplaceBuffer,sizeof ReplaceBuffer

我们先找到要搜索的正文串和用来替换的正文串。

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

为容易起见,替换操作在整个控件的所有正文中进行。因此开始索引为 0 ,结束索引为 -1。

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

我们初始化 SETTEXTEX 结构来表明我们想替换当前选定的文本和使用系统缺省的代码页。

	.while TRUE		invoke SendMessage,hwndRichEdit,
EM_FINDTEXTEX,FR_DOWN,addr findtext .if eax==-1 .break .else invoke SendMessage,hwndRichEd
it,EM_EXSETSEL,0,addr findtext.chrgText invoke SendMessage,hwndRichEd
it,EM_SETTEXTEX,addr settext,addr ReplaceBuffer .endif .endw

我们进入无限循环,来搜索匹配的正文。如果找到一个,
我们就通过EM_EXSETSEL 来选定它,并通过EM_SETTEXTEX 替换它。
当没找到其他匹配串时,我们就退出循环体。

Find Next 和 Find Prev. 以跟Find操作相似方式使用 EM_FINDTEXTEX 消息实现的功能。
find operation.

下一步我们检查 Go to Line 功能。当用户点击 Go To Line 菜单项,
我们显示如下的对话框:

用户输入行号并按下OK按钮后,我们就开始处理。

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

从Edit控件中取得行号

	invoke SendMessage,hwndRichEdit,EM_GETLINECOUNT,0,0	.if eax>LineNo

从Edit控件中取得行号并检查用户指定的行号是否超出发范围。

		invoke SendMessage,hwndRichEdit,EM_LINEINDEX,LineNo,0

如果是有效行号,我们要移动插入点到该行的第一个字符处。
因此我们发送 EM_LINEINDEX 消息给RichEdit控件。
这个消息返回指定行的第一个字母的字符索引。
我们把行号放到wParam中发送消息,返回后我们就得到了该字符索引。

		invoke SendMessage,hwndRichEdit,EM_SETSEL,eax,eax

设置选择正文,这次我们使用 EM_SETSEL ,
因为字符索引已经保存在 CHARRANGE 结构中,
因而省了两个结构(要将那些索引放入一个 CHARRANGE 结构)。

		invoke SetFocus,hwndRichEd	.endif

除非RichEdit控件得到焦点,否则插入点将不会显示。因此我们调用 SetFocus 使它得到焦点.

收藏此篇文章内容到:
Tags:
责任编辑:
  • 请文明参与讨论,禁止漫骂攻击。 用户名:新注册) 密码: 匿名:
    评论总数:0 [ 查看全部 ] 网友评论
    关于我们 - 广告合作 - 网站地图 - 版权说明 - 网站历史 - 世界排名 - 加入收藏 - 设为首页 - 返回顶部