📄 lion-tut-c34.htm
字号:
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
.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
.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
.endif
.endif
.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
.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
;================================================================
; 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
.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
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
.endif
xor eax,eax
ret
WndProc endp
end start</B></FONT></PRE>
<H3><FONT color=#0000cc
face="Times New Roman, Times, serif">分析</FONT></H3>
<P><FONT face=Tahoma size=-1>文本搜索功能是使用<FONT color=#006666><B>EM_FINDTEXTEX</B></FONT> 来实现的。当用户点击Find菜单项时,<FONT color=#000099><B>IDM_FIND</B></FONT> 消息就会被发送,并显示一个 搜索 对话框。</FONT></P>
<P align=center><IMG height=120 src="" width=285></P><PRE><FONT face=Tahoma><B>
</B></FONT><FONT face=Tahoma><B> invoke GetDlgItemText,hWnd,IDC_FINDEDIT,addr FindBuffer,sizeof FindBuffer
.if eax!=0</B></FONT><FONT face=Tahoma><B></B></FONT></PRE>
<P><FONT face=Tahoma><FONT face=Tahoma size=-1>当用户输入搜索正文,按下Ok按钮后,我们从FindBuffer缓冲区中得到要搜索的正文串。 </FONT></FONT><FONT face=Tahoma><B></B></FONT></P><PRE><FONT face=Tahoma><B> mov uFlags,0
invoke SendMessage,hwndRichEdit,EM_EXGETSEL,0,addr findtext.chrg</B></FONT><FONT face=Tahoma><B></B></FONT></PRE>
<P><FONT face=Tahoma><FONT face=Tahoma><FONT face=Tahoma size=-1>如果正文串不为空,我们就继续初始化<FONT color=#0000cc><B>uFlags</B></FONT> 变量为 0 。</FONT></FONT><FONT face=Tahoma
size=-1>这个变量被用来保存跟<FONT color=#006666> <B>EM_FINDTEXTEX</B></FONT> 一起使用的搜索标志。之后,通过 <FONT color=#006666><B>EM_EXGETSEL</B></FONT> ,我们得到当前选定的正文,因为我们需要知道搜索操作的开始位置。</FONT><B><BR></B></FONT></P><PRE> <FONT face=Tahoma><B>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</B></FONT></PRE>
<P><FONT face=Tahoma><FONT size=-1>下一步就有一点精巧了。我们检查搜索方向Radio按钮来得到要按什么方向进行搜索。如果是向下搜索,我们设置 <FONT color=#0000cc><B>uFlags</B></FONT> 为<FONT color=#006666><B>FR_DOWN</B></FONT> 标志值。然后我们比较 <FONT color=#0000cc><B>cpMin</B></FONT> 和 <FONT color=#0000cc><B>cpMax</B></FONT>,检查是否要在选定的正文里搜索。
如果两者的值不相等,说明有当前选定正文,我们需要从选定正文的结尾开始搜索,到控件中的正文的结尾结束。从而我们需要替换 <FONT color=#0000cc><B>cpMax</B></FONT> 的值为 <FONT
color=#0000cc><B>cpMin</B></FONT> ,并改变 <FONT
color=#0000cc><B>cpMax</B></FONT> 的值为 -1 (0FFFFFFFFh)。如果没有当前选定正文,搜索的范围是从当前插入点(光标)到所有正文的结尾。</FONT></FONT></P>
<P><FONT face=Tahoma size=-1>如果用户选择了向前搜索,我们使用的范围是从选定正文的开始到控件中正文的开始处。这个就是我们只改变 <FONT color=#0000cc><B>cpMax</B></FONT> 的值为 0 原因。在使用向前搜索的情况下,<FONT color=#0000cc><B>cpMin</B></FONT> 包含搜索范围中最后一个字符的的字符索引。而<FONT color=#0000cc><B>cpMax</B></FONT> 则是搜索范围中第一个字符的字符索引。向后搜索则刚刚相反。</FONT><FONT face=Tahoma><B><BR></B></FONT></P><PRE><FONT face=Tahoma><B> 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</B></FONT></PRE>
<P><FONT face=Tahoma><FONT size=-1>我们继续检查搜索标志的检查框,也就是 <FONT color=#006666><B> FR_MATCHCASE</B></FONT> and <FONT color=#006666><B>FR_WHOLEWORD</B></FONT>。最后,我们把要搜索的正文串的偏移量放入 <FONT color=#006666><B>lpstrText</B></FONT> 成员中。<BR></FONT><B></B></FONT></P><PRE><FONT face=Tahoma><B> invoke SendMessage,hwndRichEdit,EM_FINDTEXTEX,uFlags,addr findtext
.if eax!=-1
invoke SendMessage,hwndRichEdit,EM_EXSETSEL,0,addr findtext.chrgText
.endif
.endif</B></FONT></PRE>
<P><FONT face=Tahoma size=-1>现在我们已经准备好发送 <FONT color=#006666><B>EM_FINDTEXTEX</B></FONT> 消息了。之后,我们检查通过 <FONT color=#990099><B>SendMessage</B></FONT> 返回的搜索结果。如果返回 -1, 表示没有找到匹配的正文串。否则,<FONT
color=#006666><B>FINDTEXTEX</B></FONT> 结构的 <FONT color=#0000cc><B>chrgText</B></FONT> 成员里会被填入匹配正文串的字符索引。因此我们继续使用 <FONT
color=#006666><B> EM_EXSETSEL</B></FONT></FONT><FONT
face=Tahoma><B> 消息来选定该正文串。</B></FONT></P>
<P><FONT face=Tahoma size=-1>替换操作也是以差不多的方式来完成。</FONT></P><PRE><FONT face=Tahoma><B> invoke GetDlgItemText,hWnd,IDC_FINDEDIT,addr FindBuffer,sizeof FindBuffer
invoke GetDlgItemText,hWnd,IDC_REPLACEEDIT,addr ReplaceBuffer,sizeof ReplaceBuffer</B></FONT></PRE>
<P><FONT face=Tahoma><FONT size=-1>我们先找到要搜索的正文串和用来替换的正文串。</FONT><B><BR></B></FONT></P><PRE><FONT face=Tahoma><B> mov findtext.chrg.cpMin,0
mov findtext.chrg.cpMax,-1
mov findtext.lpstrText,offset FindBuffer</B></FONT></PRE>
<P><FONT face=Tahoma><FONT size=-1>为容易起见,替换操作在整个控件的所有正文中进行。因此开始索引为 0 ,结束索引为 -1。</FONT><B><BR></B></FONT></P><PRE><FONT face=Tahoma><B> mov settext.flags,ST_SELECTION
mov settext.codepage,CP_ACP</B></FONT></PRE>
<P><FONT face=Tahoma><FONT size=-1>我们初始化 <FONT
color=#006666><B>SETTEXTEX</B></FONT> 结构来表明我们想替换当前选定的文本和使用系统缺省的代码页。</FONT><B><BR></B></FONT></P><PRE><FONT face=Tahoma><B> .while TRUE
invoke SendMessage,hwndRichEdit,EM_FINDTEXTEX,FR_DOWN,addr findtext
.if eax==-1
.break
.else
invoke SendMessage,hwndRichEdit,EM_EXSETSEL,0,addr findtext.chrgText
invoke SendMessage,hwndRichEdit,EM_SETTEXTEX,addr settext,addr ReplaceBuffer
.endif
.endw</B></FONT></PRE>
<P><FONT face=Tahoma size=-1>我们进入无限循环,来搜索匹配的正文。如果找到一个,我们就通过<FONT
color=#006666><B>EM_EXSETSEL</B></FONT> 来选定它,并通过<FONT
color=#006666><B>EM_SETTEXTEX</B></FONT> 替换它。当没找到其他匹配串时,我们就退出循环体。</FONT></P>
<P><FONT face=Tahoma size=-1><B><FONT color=#006666>Find Next </FONT></B>和
<FONT color=#006666><B>Find Prev.</B></FONT> 以跟Find操作相似方式使用 <FONT
color=#006666><B>EM_FINDTEXTEX</B></FONT> 消息实现的功能。
find operation.</FONT></P>
<P><FONT face=Tahoma size=-1>下一步我们检查 Go to Line 功能。当用户点击 Go To Line 菜单项,我们显示如下的对话框:</FONT></P>
<P align=center><IMG height=75 src="" width=165></P>
<P align=left><FONT face=Tahoma size=-1>用户输入行号并按下OK按钮后,我们就开始处理。</FONT></P><PRE align="left"><FONT face=Tahoma><B> invoke GetDlgItemInt,hWnd,IDC_LINENO,NULL,FALSE
mov LineNo,eax</B></FONT></PRE>
<P align=left><FONT face=Tahoma><FONT size=-1>从Edit控件中取得行号</FONT><B><BR></B></FONT></P><PRE align="left"><FONT face=Tahoma><B> invoke SendMessage,hwndRichEdit,EM_GETLINECOUNT,0,0
.if eax>LineNo</B></FONT></PRE>
<P align=left><FONT face=Tahoma><FONT size=-1>从Edit控件中取得行号并检查用户指定的行号是否超出发范围。</FONT><B><BR></B></FONT></P><PRE align="left"><FONT face=Tahoma><B> invoke SendMessage,hwndRichEdit,EM_LINEINDEX,LineNo,0</B></FONT></PRE>
<P align=left><FONT face=Tahoma><FONT size=-1>如果是有效行号,我们要移动插入点到该行的第一个字符处。因此我们发送 <FONT color=#006666><B>EM_LINEINDEX</B></FONT> 消息给RichEdit控件。这个消息返回指定行的第一个字母的字符索引。我们把行号放到wParam中发送消息,返回后我们就得到了该字符索引。</FONT><B><BR></B></FONT></P><PRE align="left"><FONT face=Tahoma><B> invoke SendMessage,hwndRichEdit,EM_SETSEL,eax,eax</B></FONT></PRE>
<P align=left><FONT face=Tahoma><FONT size=-1>设置选择正文,这次我们使用 <FONT color=#006666><B> EM_SETSEL</B></FONT> ,因为字符索引已经保存在 <FONT color=#006666><B>CHARRANGE</B></FONT>
结构中,因而省了两个结构(要将那些索引放入一个 <FONT color=#006666><B>CHARRANGE</B></FONT> 结构)。</FONT><B> </B></FONT></P><PRE align="left"><FONT face=Tahoma><B> invoke SetFocus,hwndRichEdit
.endif</B></FONT></PRE>
<P align=left><FONT face=Tahoma size=-1>除非RichEdit控件得到焦点,否则插入点将不会显示。因此我们调用 <FONT color=#006666><B>SetFocus</B></FONT> 使它得到焦点.</FONT><FONT face=Tahoma><B>
</B></FONT></P>
<HR SIZE=1>
<DIV align=center> <font face="宋体">
<SCRIPT language=JavaScript1.1 src="../lion-tut-c13.files/textclick"></SCRIPT>
<BR>
</font></DIV>
<font face="宋体"><!-- 10:1 文本广告交换 --> </font>
<DIV align=center> <font face="宋体">
<SCRIPT language=JavaScript1.1 src="../lion-tut-c13.files/c21.htm"></SCRIPT>
<!-- 10:1 文本广告交换 --></font></DIV>
<HR SIZE=1>
<P align=center><FONT face=Tahoma size=-1><B>翻译:farsky 来源:[<A
href="http://win32asm.cjb.net/">Iczelion's Win32 Assembly Homepage</A>]<br>
LuoYunBin's Win32 ASM Page, <a
href="http://asm.yeah.net/">http://asm.yeah.net</a></B></FONT></P>
<br>
</BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -