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