?? 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 + -