Aprenderás más acera de la operaciones de texto bajo control RichEdit. Especíificamente sabrás como buscar/reemplazar texto, saltando a un número especifico de línea.
Baja el ejemplo.
Hay varias operaciones de texto bajo control RichEdit. Buscar texto es una de ellas. La búsqueda de texto se hace enviando el mensaje EM_FINDTEXT o EM_FINDTEXTEX. Estos mensajes tienen una pequeña diferencia.
EM_FINDTEXT wParam == opciones de búsqueda. Puede ser cualquier combinación de los valores de la siguiente tabla. Estas opciones son identicas para ambos EM_FINDTEXT y EM_FINDTEXTEX
FR_DOWN Si esta bandera [flag] esta especificado la búsqueda comienza desde el final de la actual selección hasta el final del texto en el control (downward). Esta bandera [flag] tiene efecto solo para el RichEdit 2.0 o posterio. Este comportamiento es por defecto para el RichEdit 1.0. El comportamiento por defecto del RichEdit 2.0 o posterior es buscar desde el final de la actual selección hasta el comienzo del texto upward).
En resumen, si usas RichEdit 1.0, no puedes hacer nada sobre la dirección de búsqueda, siempre busca hacia abajo. Si usas RichEdit 2.0 y quieres buscar hacia abajo debes especificar esta bandera [flag] de otro modo la búsqueda será hacia arriba. FR_MATCHCASE Con esta bandera [flag] , la búsqueda es sensible a la diferencia entre mayúsculas y minúsculas. FR_WHOLEWORD Con esta bandera [flag] , se buscarán las palabras completas coincidentes con la cadena de búsqueda.Actualmente hay unos pocos flags más pero no son relevantes para lenguajes no-Ingleses. lParam== puntero a la estructura FINDTEXT. FINDTEXT STRUCT chrg CHARRANGE <> lpstrText DWORD ? FINDTEXT ENDS chrg Es una estructura CHARRANGE la cual se define como sigue: CHARRANGE STRUCT cpMin DWORD ? cpMax DWORD ? CHARRANGE ENDS cpMin contiene el índice del primer caracter en el array de caracteres (rango). cpMax contiene el índice del caracter inmediatamente siguiente al último caracter en el array de caracteres. En esencia, para buscar un texto, tienes que especificar el rango en el cual buscar. El significado de cpMin y cpMax difiere en cuanto a si la búsqueda es hacia arriba o hacia abajo. Si la búsqueda es hacia abajo, cpMin especifica el índice del caracter de comienzo de la búsqueda y cpMax el índice del caracter del final. Si la búsqueda es hacia arriba será al revés, por ej. cpMin contiene el índice del caracter final mientras cpMax el índice del caracter del principio. lpstrText es el puntero a la cadena de texto a buscar. EM_FINDTEXT devuelve el índice del primer caracter del texto coincidente en el control RichEdit. Si devuelve -1 es que no se encontró nada. EM_FINDTEXTEX wParam == las opciones de búsqueda. Como en EM_FINDTEXT. lParam == puntero a la estructura FINDTEXTEX. FINDTEXTEX STRUCT chrg CHARRANGE <> lpstrText DWORD ? chrgText CHARRANGE <> FINDTEXTEX ENDS Los dos primeros miembros de FINDTEXTEX son idénticos a los de la estructura FINDTEXT. chrgText es una estructura CHARRANGE que será rellenada con los índices de comienzo/final si se encuentra alguna coincidencia. El valor de retorno de EM_FINDTEXTEX es el mismo que en EM_FINDTEXT. La diferencia entre EM_FINDTEXT y EM_FINDTEXTEX es que la estructura FINDTEXTEX tiene un miembro adicional, chrgText, el cual será rellenado con el índice de comienzo/final si se encuentra coincidencia. Esto es conveniente si queremos hacer mas operaciones de texto sobre la cadena.
El control RichEdit provee EM_SETTEXTEX para reemplazar/insertar texto. Este mensaje combina la funcionalidad de WM_SETTEXT y EM_REPLACESEL.Y tiene la siguiente sintaxis:
EM_SETTEXTEX wParam == puntero a la estructura SETTEXTEX.
SETTEXTEX STRUCT
flags DWORD ?
codepage DWORD ?
SETTEXTEX ENDS
flags [banderas] puede ser una combinación de los siguientes valores:
|
ST_DEFAULT
|
Borra la pila [stack] de 'undo'. Descarta el formato
de texto enrriquecido [RTF] , reemplazando todo el texto.
|
|
ST_KEEPUNDO
|
Mantiene la pila [stack] de 'undo'.
|
|
ST_SELECTION
|
Reemplaza la selección y mantiene formato
de texto enrriquecido [RTF]
|
codepage Es la constante que especifica la página de códigos que quieres usar. Usualmente, solemos usar CP_ACP.
Podemos seleccionar texto programáticamente
con EM_SETSEL o EM_EXSETSEL. Los dos funcionan muy bien. El mensaje que escojamos
depende del formato disponible para los índices de caracteres. Si ya
están almacenados en una estructura CHARRANGE es mas facil usar EM_EXSETSEL.
EM_EXSETSEL wParam == no usado. Debe ser cero lParam == puntero a una estructura CHARRANGE que contiene el rango de caracteres que serán seleccionados.
En el caso de un control edit multilíneas, tienes subclases en orden a obtener mensajes de entrada tales como eventos del ratón/teclado. El control RichEdit provee un mejor esquema que notificará a la ventana padre de tales eventos. Para registrar las notificaciones, la ventana padre envía el mensaje EM_SETEVENTMASK al control RichEdit, especificando en cuáles eventos está interesado. EM_SETEVENTMASK tiene la siguiente sintaxis:
EM_SETEVENTMASK wParam == no usado. Debe ser cero lParam == Valor de la mascara del evento. Puede ser una combinación de los siguientes banderas.
|
ENM_CHANGE
|
Envía notificaciones EN_CHANGE
|
|
ENM_CORRECTTEXT
|
Envía notificaciones EN_CORRECTTEXT
|
|
ENM_DRAGDROPDONE
|
Envía notificaciones EN_DRAGDROPDONE
|
|
ENM_DROPFILES
|
Envía notificaciones EN_DROPFILES
|
|
ENM_KEYEVENTS
|
Envía notificaciones EN_MSGFILTER para
eventos de teclado
|
|
ENM_LINK
|
Rich Edit 2.0 y posterior: Envía notificaciones
EN_LINK cuando el puntero del ratón está
sobre el texto que tiene CFE_LINK y son realizadas una o varias acciones
del ratón.
|
|
ENM_MOUSEEVENTS
|
Envía notificaciones EN_MSGFILTER para eventos del ratón
|
|
ENM_OBJECTPOSITIONS
|
Envía notificaciones EN_OBJECTPOSITIONS
|
|
ENM_PROTECTED
|
Envía notificaciones EN_PROTECTED
|
|
ENM_REQUESTRESIZE
|
Envía notificaciones EN_REQUESTRESIZE
|
|
ENM_SCROLL
|
Envía notificaciones EN_HSCROLL y EN_VSCROLL
|
|
ENM_SCROLLEVENTS
|
Envía notificaciones EN_MSGFILTER para eventos de la rueda del ratón
|
|
ENM_SELCHANGE
|
Envía notificaciones EN_SELCHANGE
|
|
ENM_UPDATE
|
Envía notificaciones EN_UPDATE
Rich Edit 2.0 and later: esta bandera [flag] es ignoradoay las notificaciones EN_UPDATE son siempre enviadas. Sin embargo, si Rich Edit 3.0 emula a Rich Edit 1.0, debes usar esta bandera [flag] para enviar notificaciones EN_UPDATE |
Todas las notificaciones de arriba seran enviadas como mensajes WM_NOTIFY:Tienes que mirar el código del miembro de la estructura NMHDR para el mensaje de notificación. Por ejemplo, si quieres registrar eventos del ratón (ej. quieres proveer un contexto sensitivo popup menu), debes hacer algo como esto:
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
El siguiente ejemplo es la actualización del IczEdit en tutorial no. 33. añadido buscar/reemplazar funcionalidad y teclas aceleradoras al programa. También procesa los eventos del ratón y provee un menú emergente al hacer click en el botón derecho del ratón.
.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\kernel32.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 1005
IDM_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 control is modified. Want to save it?",0
FileOpened dd FALSE
BackgroundColor dd 0FFFFFFh ; blanco por defecto
TextColor dd 0 ; negro por defecto
hSearch dd ? ; handle al cuadro de diálogo buscar/reemplazar [search/replace]
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
.else
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_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
.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, pBytesWritten: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 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
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 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
.endif
.endif
mov eax,FALSE
ret
.elseif uMsg==WM_CLOSE
invoke EndDialog,hWnd,0
.else
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
.else
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
.else
mov eax,FALSE
ret
.endif
.endif
.elseif uMsg==WM_CLOSE
mov hSearch,0
invoke EndDialog,hWnd,0
.else
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 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
.endif
.endif
.elseif uMsg==WM_CLOSE
mov hSearch,0
invoke EndDialog,hWnd,0
.else
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_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
.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
.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 hay selección en este momento
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
.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 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 ; menú 'file'
.if FileOpened==TRUE ; ya está abierto un archivo
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 ; órdenes del menú
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
;================================================================
; introduce el stream de texto en el control richedit
;================================================================
mov editstream.dwCookie,eax
mov editstream.pfnCallback,offset StreamInProc
invoke SendMessage,hwndRichEdit,EM_STREAMIN,SF_TEXT,addr editstream
;==========================================================
; Inicializa el estado de notificación poniéndolo 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
;==========================================================
; Lleva el stream de texto al archivo
; ==========================================================
mov editstream.dwCookie,eax
mov editstream.pfnCallback,offset StreamOutProc
invoke SendMessage,hwndRichEdit,EM_STREAMOUT,SF_TEXT,addr editstream
;==========================================================
; Inicializa el estado de notificación poniéndolo 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
La capacidad de búsqueda de texto es implementada con EM_FINDTEXTEX. Cuando el usuario hace click sobre el ítem de menú 'Find', el mensaje IDM_FIND es enviado y será mostrado el diálogo de búsqueda.

invoke GetDlgItemText,hWnd,IDC_FINDEDIT,addr FindBuffer,sizeof FindBuffer .if eax!=0
Cuando el usuario pone el texto de búsqueda y presiona el boton OK, obtenemos el texto a buscar en FindBuffer.
mov uFlags,0 invoke SendMessage,hwndRichEdit,EM_EXGETSEL,0,addr findtext.chrg
Si la cadena de texto no es NULL, continuamos
para inicializar la variable uFlags a cero. Esta variable es usada para guardar las banderas
[flags] de búsqueda usadas con EM_FINDTEXTEX. Tras esto, obtenemos la actual selección con EM_EXGETSEL ya que necesitamos conocer el punto de comienzo de la
operación de búsqueda.
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
La siguiente parte es un poqueño truco. Miramos el botón 'radio' de dirección para saber que dirección de búsqueda debe tomar, si está indicada la dirección de búsqueda hacia abajo ponemos la bandera [flag] FR_DOWN a uFlags. Tra esto, miramos si una selección esta actualmente en efecto comparando los valores de cpMin y cpMax. Si estos valores no son iguales, significa que hay una selección y debemos continuar la búsqueda desde el final de esa selección hasta el final del texto en el control. Así necesitamos reemplazar el valor de cpMax con el de cpMin y cambiar el valor de cpMax a -1 (0FFFFFFFFh). Si no hay selección, el rango de búsqueda es desde la posición actual del cursor hasta el final del texto.
Si el usuario escoge buscar hacia arriba, usamos
el rango desde el comienzo de la selección hasta el comienzo del texto.
Esto es porque sólo modifica el valor de cpMax a cero. En el caso de búsqueda hacia arriba, cpMin contiene el índice del último caracter en
el rango de búsqueda y cpMax el índice
del primer caracter en el rango de búsqueda; es lo contrario de buscar
hacia abajo.
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
Continuamos para revisar los 'checkboxes' [casillas
de chequeo] para los banderas [flags] de búsqueda, por ej. FR_MATCHCASE y FR_WHOLEWORD. Por ultimo ponemos el desplazamiento del texto a buscar en el
miembro lpstrText.
invoke SendMessage,hwndRichEdit,EM_FINDTEXTEX,uFlags,addr findtext
.if eax!=-1
invoke SendMessage,hwndRichEdit,EM_EXSETSEL,0,addr findtext.chrgText
.endif
.endif
Ahora estamos listos para emitir EM_FINDTEXTEX. Después de esto, examinamos el resultado de la búsqueda devuelto por SendMessage. Si el valor de retorno es -1, no se encontraron coincidencias en el rango de búsqueda. De otra forma el miembro chrgText de la estructura FINDTEXTEX es llenado con el índice del caracter del texto que coincidió. Asi que procedemos a seleccionarlo con EM_EXSETSEL.
La operación de reemplazo se hace de la misma forma.
invoke GetDlgItemText,hWnd,IDC_FINDEDIT,addr FindBuffer,sizeof FindBuffer invoke GetDlgItemText,hWnd,IDC_REPLACEEDIT,addr ReplaceBuffer,sizeof ReplaceBuffer
Obtenemos el texto a buscar y el texto usado para
hacer el reemplazo.
mov findtext.chrg.cpMin,0 mov findtext.chrg.cpMax,-1 mov findtext.lpstrText,offset FindBuffer
para hacerlo facil, la operación de reemplazo
afecta a todo el texto en el control. Asi que el índice del comienzo
es cero y el índice final es -1.
mov settext.flags,ST_SELECTION mov settext.codepage,CP_ACP
Inicializamos la estructura SETTEXTEX para indicar que queremos reemplazar la actual selección
y usar la pagina de códigos por defecto del sistema.
.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
Entramos en un bucle infinito buscando el texto coincidente. Si se encuentra alguno lo seleccionamos con EM_EXSETSEL y lo reemplazamos con EM_SETTEXTEX. Cuando no se encuentran mas , salimos del bicle.
Find Next y Find Prev usan el mensaje EM_FINDTEXTEX de manera similar a la operación de búsqueda.
Ahora examinaremos la caracteristica "Go to Line". Cuando el usuario hace click en el menu "Go To Line", mostramos el diálogo de abajo:

Cuando el usuario pone un numero de linea y presiona el boton Ok,comenzamos la operacion.
invoke GetDlgItemInt,hWnd,IDC_LINENO,NULL,FALSE mov LineNo,eax
Obtiene
el numero de linea del edit control
invoke SendMessage,hwndRichEdit,EM_GETLINECOUNT,0,0 .if eax>LineNo
Obtiene el numero de lineas del control.
Revisa si el número de linea especificado por el usuario esta fuera de
rango.
invoke SendMessage,hwndRichEdit,EM_LINEINDEX,LineNo,0
Si el número de línea
es válido, queremos mover el cursor al primer caracter de esa línea.
Asi que enviamos el mensaje EM_LINEINDEX al control RichEdit. Este mensaje devuelve el índice
del primer caracter en la línea especificada. Enviamos el número
de linea en wParam y en el retorno tenemos el caracter índice.
invoke SendMessage,hwndRichEdit,EM_SETSEL,eax,eax
Para poner la actual selección esta vez usamos EM_SETSEL ya que el caracter índice ya no está en una estructura CHARRANGE así ahorramos dos instrucciones ( para poner estos índices en una estructura CHARRANGE ).
invoke SetFocus,hwndRichEdit .endif
El cursor no será mostrado a menos que el control RichEdit tenga el foco. Así que llamaremos a SetFocus sobre él.
[Iczelion's Win32 Assembly Homepage]
n u M I T_o r's Programming Page
Este tutorial, original de Iczelion, ha sido traducido por: n u M I T_o r