WIN32汇编 Richedit控件的使用

Posted 小哈龙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WIN32汇编 Richedit控件的使用相关的知识,希望对你有一定的参考价值。

这次来介绍一下一个独特的控件------Richedit    说实话这次也是第一次接触到这个控件,以前虽然听说过但是不知道具体它是干什么的,从字面上看好像是edit控件的扩展一样,其实这样只说对了一半,Richedit控件确实比edit控件功能强大丰富,但是它们的使用位置不同,edit控件以前在学习控件的时候,就出现了许多edit控件,那时候用edit控件主要是实现向一个小的文本框中输入文本而且基本都是用在对话框中,而且大小也有限制,在单行模式下能容纳的文本不能超过32KB,在多行模式下也不能超过64KB,加上这个限制想要实现多文本的输入那就有点麻烦了,而且不能实现文本格式,大小颜色等属性的设置,出于此种原因,Richedit控件就有了大显身手的机会,它可以实现多文本的输入,但是需要指定大小(发送EM_EXLIMITTEXT,因为默认情况下控件还是将最大字符数限制为64KB),这个控件因为功能复杂,代码量较大,微软给它独立使用一个动态链接库存储(Riched32.dll  1.0版,Riched20.dll(2.0和3.0版)),具体功能看一下下表(罗云斌老师书中的一张介绍图)

不同版本Richedit控件之间的区别
  1.0版 2.0版 3.0版
DLL库文件名 Riched32.dll Riched32.dll Riched32.dll
控件的类名 Richedit Richedit20A
Richedit20W
Richedit20A
Richedit20W
拖放编辑 支持 支持 支持
流输入输出 支持 支持 支持 
Unicode编辑 不支持 支持 支持
非窗口操作 不支持 支持 支持
自动URL识别 不支持 支持 支持
加速键 不支持 支持 支持
分行符 CR+LF CR CR(可模拟1.0版)
撤销/重做 支持单级 支持多级 支持多级
文本搜索 向前搜索 向前/向后搜索 向前/向后搜索
       

知道了Richedit控件的大致功能,接下来就需要知道怎么来实现相关的功能,分为如下几步来实现:

资源文件
菜单 IDR_MENU1  
加速键 IDR_ACCELERATOR1
光标 IDI_ICON1 

实现过程
控件的流操作 _ProcStream()
文件的保存 _SaveFile()
打开文件 _OpenFile()
检测文件修改 _CheckModify()
查找文字 _FindText()
实时改变菜单项状态 _SetStatus()
窗口内容初始化 _Init()
退出程序 _Quit()
窗口过程 _ProcWinMain()
主函数 _WinMain()

下面来回顾一下写程序的时候遇见的一些问题:

首先是资源文件,依然使用ResEdit编写,这次的资源文件需要定义的有图标,菜单,另外一个就是加速键(这个加速键好久没有写过了感觉有点陌生了,以前还是和菜单一起学习的,菜单现在已经非常熟练了,要写加速键还要再翻一下以前的文章。。。)下面简单总结一下:

键名-----表示加速键对应的按钮可以有3种方式定义:

     1.“^字母”:  表示Ctrl加上字母键

     2.“字母” :    表示字母,这时的类型必须指明是VIRTKEY

     3.  数值    :表示ASCII码为该数值的字母,这是类型必须指明为ASCII    

(在使用ResEdit编写的时候直接在键名这一项输入相应的字母,就可以了,工具已经自动处理过了)


命令ID------按下加速键后,windows向程序发送的命令ID,如果要把加速键和菜单关联起来,这里就是要关联菜单项的命令ID。这个容易理解其实就是命令ID


类型---------用来指定键的定义方式,可以是VIRKEY和 ASCII,分别用来表示“键名”字段定义的是虚拟键还是ASCII码


选项-------- 可以是ALt,Control或Shift中的单个或多个,如果指定多个,则中间用逗号隔开,表示加速键是按键加上这些控制键的组合键。

这样就清楚多了。

在使用ResEdit工具添加图标资源的时候,在创建新的图标资源的时候程序总会崩溃(有时候不会),这个我也没有解决,工具出错退出,一开始我以为是误删了什么文件但是从新安装之后还是如此,但是在创建资源文件的时候首先定义图标文件,创建新图标这样一般可以。下面看一下资源代码:

// Generated by ResEdit 1.6.6
// Copyright (C) 2006-2015
// http://www.resedit.net
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "resource.h"
//
// Menu resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDR_MENU1 MENU
{
    POPUP "文件(&F)"
    {
        MENUITEM "打开文件(&O)...\tCtrl+O", IDM_OPEN
        MENUITEM "保存文件(&S)\tCtrl+S", IDM_SAVE
        MENUITEM SEPARATOR
        MENUITEM "退出(&X)", IDM_EXIT
    }
    POPUP "编辑(&E)"
    {
        MENUITEM "撤销(&Z)\tCtrl+Z", IDM_UNDO
        MENUITEM "重复(&Y)\tCtrl+Y", IDM_REDO
        MENUITEM SEPARATOR
        MENUITEM "全选(&A)\tCtrl+A", IDM_SELALL
        MENUITEM "拷贝(&C)\tCtrl+C", IDM_COPY
        MENUITEM "剪切(&X)\tCtrl+X", IDM_CUT
        MENUITEM "粘贴(&V)\tCtrl+V", IDM_PASTE
        MENUITEM SEPARATOR
        MENUITEM "查找(&F)\tCtrl+F", IDM_FIND
        MENUITEM "查找上一个(&P)\tF2", IDM_FINDPREV
        MENUITEM "查找下一个(&N)\tF3", IDM_FINDNEXT
    }
}
// Accelerator resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDR_ACCELERATOR1 ACCELERATORS
{
    VK_F2,         IDM_FINDPREV, VIRTKEY
    VK_F3,         IDM_FINDNEXT, VIRTKEY
    "O",            IDM_OPEN, ASCII
    "S",            IDM_SAVE, ASCII
    "Z",            IDM_UNDO, ASCII
    "Y",            IDM_REDO, ASCII
    "A",            IDM_SELALL, ASCII
    "C",            IDM_COPY, ASCII
    "X",            IDM_CUT, ASCII
    "V",            IDM_PASTE, ASCII
    "F",            IDM_FIND, ASCII
}
//
// Icon resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDI_ICON1          ICON           ".\\IDI_ICON1.ico"



下面来看一下程序实现过称中遇见的问题:

首先是一个以前接触很少的问题:文本流(流入流出),说到流操作首先我想到的是C++里面的流输入输出(我接触的编程语言比较少。。只懂点C/C++和汇编)文件流的基本操作:1、打开文件 2、读取数据 3、处理数据 4、数据写回 5、关闭文件。WIN32汇编语言中文件流的操作的相关函数有两个(读入流入:ReadFile()    写出流出:WriteFile()  ),其他的就涉及到需要发送的windows消息。当需要将文件读入到控件的时候,可以向控件发送EM_STREAMIN消息,当需要将文件从控件保存到文本文件时发送EM_STREAMOUT,消息的参数中附带需要流入的文本内容格式,以及回调函数(提前自定义的函数实现读写文件的功能模块)等信息,Richedit控件会循环调用回调函数直到处理完全部的文本内容,在控件每次调用回调函数的时候,控件通过参数(控件会将流操作函数中需要的参数指定,然后再传递给回调函数,我感觉那些参数是控件内部整理的,不需要我们来指定)告诉回调函数要读写的字节数和缓冲区的地址,在程序中流入流出操作的回调函数使用的是同一个子程序_ProcStream(),在该子程序中通过判断 向控件发送的消息中的lParam参数中的lpStream指向的一个EDITSTREAM结构中的dwCookie字段(这个字段可以由我们自己定义程序中定义的是TRUE和FALSE,这些定义都无所谓,都是一样的)来确定是要进行流入(TRUE)还是流出(FALSE)操作,接下来就要使用上面介绍的那两个API函数了,这个问题刚接触很不好理解,有些地方现在依然理解的不到位。


下一个问题就是在查找文字子函数_FindText()中,在设置查找选项的时候程序代码入如下:

                mov  @stFindText.lpstrText,offset szFindText          ;将szFindText变量的地址传递给                                                                                                       FINDTEXTEX结构体类型的变量@stFindText的lpstrText字段
mov  ecx,stFind.Flags        ;
将stFind结构体变量查找标识字段内容传递给ecx

andecx,FR_MATCHCASE or FR_DOWN or FR_WHOLEWORD     ;将stFind结构体变量中的所有查找字符标示屏蔽除了   FR_MATCHCASE or FR_DOWN or FR_WHOLEWORD这几个标识.


在上面的代码中使用了and运算(按位相与 1 and 1 =1       1 and  0  =0)将其他不需要的标识屏蔽掉(不同的位代表不同的标识)这是我的理解,可能也有错误。



下面就是在保存文件功能模块中遇见的问题

使用两个函数将文件清空,代码如下:

                 invoke      SetFilePointer,hFile,0,0,FILE_BEGIN
                 invoke      SetEndOfFile,hFile

利用SetFilePointer函数返回当前的文件指针,然后再使用SetEndOfFile函数从当前文件指针处截断,除去后面的内容,从而达到将文件清空的目的。这个有点不容易理解。


下面看一下程序源代码:

                 .386
                 .model flat,stdcall
                 option casemap:none
                
include          windows.inc
include          user32.inc
includelib       user32.lib
include          kernel32.inc
includelib       kernel32.lib
include          comdlg32.inc
includelib       comdlg32.lib


IDR_MENU1        equ        100
IDR_ACCELERATOR1 equ        101
IDI_ICON1        equ        103
IDM_OPEN         equ        40000
IDM_SAVE         equ        40001
IDM_COPY         equ        40002
IDM_EXIT         equ        40003
IDM_UNDO         equ        40004
IDM_REDO         equ        40005
IDM_SELALL       equ        40006
IDM_CUT          equ        40007
IDM_PASTE        equ        40008
IDM_FIND         equ        40009
IDM_FINDPREV     equ        40010
IDM_FINDNEXT     equ        40011


                 .data?
hInstance        dd          ?
hWinMain         dd          ?
hMenu            dd          ?
hWinEdit         dd          ?
hFile            dd          ?
hFindDialog      dd          ?
idFindMessage    dd          ?
szFileName       db          MAX_PATH  dup (?)
szFindText       db          100 dup   (?)
                 .data
stFind           FINDREPLACE <sizeof FINDREPLACE,0,0,FR_DOWN,szFindText,0,sizeof szFindText,0,0,0,0>
                 .const
FINDMSGSTRING    db          ‘commdlg_FindReplace‘,0
szClassName      db          ‘wordpad‘,0
szCaptionMain    db          ‘记事本‘,0
szDllEdit        db          ‘RichEd20.dll‘,0
szClassEdit      db          ‘RichEdit20A‘,0
szNotFound       db          ‘字符串未找到!‘,0
szFilter        db          ‘Text Files(*.txt)‘,0,‘*.txt‘,0
                 db          ‘All  Files(*.*)‘,0,‘*.*‘,0,0
szDefaultExt     db          ‘txt‘,0
szErrOpenFile    db          ‘无法打开文件!‘,0
szModify         db          ‘文件已修改,是否保存?‘,0
szFont           db          ‘宋体‘,0


                 .code
_ProcStream      proc        uses ebx edi esi _dwCookie,_lpBuffer,_dwBytes,_lpBytes

        .if         _dwCookie
            invoke ReadFile,hFile,_lpBuffer,_dwBytes,_lpBytes,0        ;读入
        .else       
                    invoke WriteFile,hFile,_lpBuffer,_dwBytes,_lpBytes,0       ;读出
        .endif  
        xor         eax,eax
        ret
_ProcStream endp    


_SaveFile        proc
                 LOCAL       @stES:EDITSTREAM    
                 invoke      SetFilePointer,hFile,0,0,FILE_BEGIN
                 invoke      SetEndOfFile,hFile
                 mov         @stES.dwCookie,FALSE
                 mov         @stES.pfnCallback,offset _ProcStream
                 invoke      SendMessage,hWinEdit,EM_STREAMOUT,SF_TEXT,addr @stES
                 invoke      SendMessage,hWinEdit,EM_SETMODIFY,FALSE,0
                 ret
_SaveFile        endp


_OpenFile        proc

        LOCAL @stOF:OPENFILENAME
        LOCAL @stES:EDITSTREAM
        invoke    RtlZeroMemory,addr @stOF,sizeof @stOF
        mov       @stOF.lStructSize,sizeof @stOF
        push      hWinMain
        pop       @stOF.hWndOwner
        mov       @stOF.lpstrFilter,offset szFilter
        mov       @stOF.lpstrFile,offset szFileName
        mov       @stOF.nMaxFile,MAX_PATH
        mov       @stOF.Flags,OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST
        mov       @stOF.lpstrDefExt,offset szDefaultExt
        invoke    GetOpenFileName,addr @stOF
        .if       eax       ;0
          invoke   CreateFile,addr szFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,\
                   0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
          .if      eax  ==  INVALID_HANDLE_VALUE
            invoke   MessageBox,hWinMain,addr szErrOpenFile,NULL,MB_OK or MB_ICONSTOP
            ret
          .endif
          push     eax
          .if      hFile
            invoke CloseHandle,hFile
          .endif
          pop      eax
          mov      hFile,eax
          mov      @stES.dwCookie,TRUE
          mov      @stES.dwError,NULL
          mov      @stES.pfnCallback,offset _ProcStream
          invoke   SendMessage,hWinEdit,EM_STREAMIN,SF_TEXT,addr @stES
          invoke   SendMessage,hWinEdit,EM_SETMODIFY,FALSE,0 
        .endif
ret


_OpenFile endp


_CheckModify     proc

        LOCAL     @dwReturn
        mov       @dwReturn,TRUE
        invoke    SendMessage,hWinEdit,EM_GETMODIFY,0,0
        .if       eax && hFile
          invoke   MessageBox,hWinMain,addr szModify,addr szCaptionMain,MB_YESNOCANCEL or MB_ICONQUESTION
          .if      eax  ==  IDYES
            call     _SaveFile
          .elseif  eax  ==  IDCANCEL
            mov      @dwReturn,FALSE
          .endif
        .endif
        mov       eax,@dwReturn
        ret


_CheckModify endp


_FindText proc
local @stFindText:FINDTEXTEX
invoke SendMessage,hWinEdit,EM_EXGETSEL,0,addr @stFindText.chrg
.if stFind.Flags & FR_DOWN
push @stFindText.chrg.cpMax
pop @stFindText.chrg.cpMin
.endif
mov @stFindText.chrg.cpMax,-1
mov @stFindText.lpstrText,offset szFindText
mov ecx,stFind.Flags
and ecx,FR_MATCHCASE or FR_DOWN or FR_WHOLEWORD
invoke SendMessage,hWinEdit,EM_FINDTEXTEX,ecx,addr @stFindText
.if eax ==-1
mov ecx,hWinMain
.if hFindDialog
mov ecx,hFindDialog
.endif
invoke MessageBox,ecx,addr szNotFound,NULL,MB_OK or MB_ICONINFORMATION
ret
.endif
invoke SendMessage,hWinEdit,EM_EXSETSEL,0,addr @stFindText.chrgText
invoke SendMessage,hWinEdit,EM_SCROLLCARET,NULL,NULL
ret


_FindText endp
_SetStatus proc
local @stRange:CHARRANGE


invoke SendMessage,hWinEdit,EM_EXGETSEL,0,addr @stRange
mov eax,@stRange.cpMin
.if eax ==@stRange.cpMax
invoke EnableMenuItem,hMenu,IDM_COPY,MF_GRAYED
invoke EnableMenuItem,hMenu,IDM_CUT,MF_GRAYED
.else
invoke EnableMenuItem,hMenu,IDM_COPY,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_CUT,MF_ENABLED
.endif
invoke SendMessage,hWinEdit,EM_CANPASTE,0,0
.if eax
invoke EnableMenuItem,hMenu,IDM_PASTE,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_PASTE,MF_GRAYED
.endif
invoke SendMessage,hWinEdit,EM_CANREDO,0,0
.if eax
invoke EnableMenuItem,hMenu,IDM_REDO,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_REDO,MF_GRAYED
.endif
invoke SendMessage,hWinEdit,EM_CANUNDO,0,0
.if eax
invoke EnableMenuItem,hMenu,IDM_UNDO,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_UNDO,MF_GRAYED
.endif
invoke GetWindowTextLength,hWinEdit
.if eax
invoke EnableMenuItem,hMenu,IDM_SELALL,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_SELALL,MF_GRAYED
.endif
invoke SendMessage,hWinEdit,EM_GETMODIFY,0,0
.if eax && hFile
invoke EnableMenuItem,hMenu,IDM_SAVE,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_SAVE,MF_GRAYED
.endif
.if szFindText
invoke EnableMenuItem,hMenu,IDM_FINDNEXT,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_FINDPREV,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_FINDNEXT,MF_GRAYED
invoke EnableMenuItem,hMenu,IDM_FINDPREV,MF_GRAYED
.endif
ret


_SetStatus endp
_Init proc
local @stCf:CHARFORMAT
push hWinMain
pop stFind.hwndOwner
invoke RegisterWindowMessage,addr FINDMSGSTRING
mov idFindMessage,eax
invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassEdit,NULL,\
WS_CHILD OR WS_VISIBLE OR WS_VSCROLL ORWS_HSCROLL \
OR ES_MULTILINE or ES_NOHIDESEL,\
0,0,0,0,\
hWinMain,0,hInstance,NULL
mov hWinEdit,eax


invoke SendMessage,hWinEdit,EM_SETTEXTMODE,TM_PLAINTEXT,0
invoke RtlZeroMemory,addr @stCf,sizeof @stCf
mov @stCf.cbSize,sizeof @stCf
mov @stCf.yHeight,9 * 20
mov @stCf.dwMask,CFM_FACE or CFM_SIZE or CFM_BOLD
invoke lstrcpy,addr @stCf.szFaceName,addr szFont
invoke SendMessage,hWinEdit,EM_SETCHARFORMAT,0,addr @stCf
invoke SendMessage,hWinEdit,EM_EXLIMITTEXT,0,-1
ret


_Init endp


_Quit proc


invoke _CheckModify
.if eax
invoke DestroyWindow,hWinMain
invoke PostQuitMessage,NULL
.if hFile
invoke CloseHandle,hFile
.endif
.endif
ret


_Quit endp


_ProcWinMain procuses ebx edi esi hWnd,uMsg,wParam,lParam
local @stRange:CHARRANGE
local @stRect:RECT


mov eax,uMsg
.if eax ==WM_SIZE
invoke GetClientRect,hWinMain,addr @stRect
invoke MoveWindow,hWinEdit,0,0,@stRect.right,@stRect.bottom,TRUE
.elseif eax == WM_COMMAND
mov eax,wParam
movzx eax,ax
.if eax ==IDM_OPEN
invoke _CheckModify
.if eax
call _OpenFile
.endif
.elseif eax == IDM_SAVE
call _SaveFile
.elseif eax == IDM_EXIT
invoke _Quit
.elseif eax == IDM_UNDO
invoke SendMessage,hWinEdit,EM_UNDO,0,0
.elseif eax == IDM_REDO
invoke SendMessage,hWinEdit,EM_REDO,0,0
.elseif eax == IDM_SELALL
mov @stRange.cpMin,0
mov @stRange.cpMax,-1
invoke SendMessage,hWinEdit,EM_EXSETSEL,0,addr @stRange
.elseif eax == IDM_COPY
invoke SendMessage,hWinEdit,WM_COPY,0,0
.elseif eax == IDM_CUT
invoke SendMessage,hWinEdit,WM_CUT,0,0
.elseif eax == IDM_PASTE
invoke SendMessage,hWinEdit,WM_PASTE,0,0
.elseif eax == IDM_FIND
and stFind.Flags,not FR_DIALOGTERM
invoke FindText,addr stFind
.if eax
mov hFindDialog,eax
.endif
.elseif eax == IDM_FINDPREV
and stFind.Flags,not FR_DOWN
invoke _FindText
.elseif eax == IDM_FINDNEXT
or stFind.Flags,FR_DOWN
invoke _FindText
.endif
.elseif eax == WM_INITMENU
call _SetStatus
.elseif eax == idFindMessage
.if stFind.Flags & FR_DIALOGTERM
mov hFindDialog,0
.else
invoke _FindText
.endif
.elseif eax == WM_ACTIVATE
mov eax,wParam
.if (ax ==WA_CLICKACTIVE ) || (ax == WA_ACTIVE)
invoke SetFocus,hWinEdit
.endif
.elseif eax == WM_CREATE
push hWnd
pop hWinMain
invoke _Init
.elseif eax == WM_CLOSE
call _Quit
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret


_ProcWinMain endp
_WinMain proc
local @stWndClass:WNDCLASSEX
local @stMsg:MSG
local @hAccelerator,@hRichEdit


invoke LoadLibrary,offset szDllEdit
mov @hRichEdit,eax
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke LoadMenu,hInstance,IDR_MENU1  
mov hMenu,eax
invoke LoadAccelerators,hInstance,IDR_ACCELERATOR1
mov @hAccelerator,eax
invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
invoke LoadIcon,hInstance,IDI_ICON1 
mov @stWndClass.hIcon,eax
mov @stWndClass.hIconSm,eax
invoke LoadCursor,0,IDC_ARROW
mov @stWndClass.hCursor,eax
push hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize,sizeof WNDCLASSEX
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW
mov @stWndClass.lpfnWndProc,offset _ProcWinMain
mov @stWndClass.hbrBackground,COLOR_BTNFACE+1
mov @stWndClass.lpszClassName,offset szClassName
invoke RegisterClassEx,addr @stWndClass
invoke CreateWindowEx,NULL,\
offset szClassName,offset szCaptionMain,\
WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT,CW_USEDEFAULT,700,500,\
NULL,hMenu,hInstance,NULL
mov hWinMain,eax
invoke ShowWindow,hWinMain,SW_SHOWNORMAL
invoke UpdateWindow,hWinMain
.while TRUE
invoke GetMessage,addr @stMsg,NULL,0,0
.break .if eax == 0
invoke TranslateAccelerator,hWinMain,@hAccelerator,addr @stMsg
.if eax == 0
invoke TranslateMessage,addr @stMsg
invoke DispatchMessage,addr @stMsg
.endif
.endw
invoke FreeLibrary,@hRichEdit
ret


_WinMain endp
start:
call _WinMain
invoke ExitProcess,NULL
end start

下面介绍一下一些陌生的结构和API函数以及几个消息:


结构:

EDITSTREAM              STRUCT

       dwCookie              DWORD       ?              ;用户自定义值

       dwError                 DWORD        ?              ;用来返回流操作过程中的错误信息 

       pfnCallback           DWORD        ?              ;   回调函数地址

EDITSTREAM               ENDS

 dwCookie
用户值作为第一个参数传递给回调。指定富编辑控件的应用程序定义的值传递到指定的 pfnCallback 成员的 EditStreamCallback 回调函数。
dwError
指示流入 (读取) 或流出 (写入) 操作的结果。值为 0 表示没有错误。一个非零值,可以是 EditStreamCallback 函数或一个代码,指示该控件遇到一个错误的返回值。
pfnCallback
回调函数的地址


FINDTEXTEX      STRUCT

     chrg                CHARRANGE  <>     ;查找区域

     lpstrText         DWORD            ?      ;查找字符串地址

     chrgtext          CHARRANGE  <>     ; 如果找到则在这里返回找到文字的起始/结束位置

FINDTEXTEX      ENDS



CHARRANGE     STRUCT

        cpMin          DWORD            ?       ;选择区域的起始位置

        cpMax         DWORD             ?      ;选择区域的结束位置

CHARRANGE    ENDS


CHARFORMAT2    STRUCT

   cbSize                  DWORD     ?            ;结构的长度

   dwMask                DWORD     ?            ;字段掩码

   dwEffects            DWORD      ?            ;字段效果

   yHeight                 DWORD     ?            ;文字的高度

   yOffset                 DWORD      ?             ;

   crTextColor          DWORD     ?             ;文本的颜色

      bCharSet             BYTE           ?            ;

    bPitchAndFamily   BYTE      ?             ;

   szFaceName        BYTE          LF_FACESIZE    dup(?)                   ;字体名称

   ;CHARFORMAT   结构的定义到此结束

  wWeight                  WORD        ?

  sSpacing                 WORD        ?

以上是关于WIN32汇编 Richedit控件的使用的主要内容,如果未能解决你的问题,请参考以下文章

自定义编辑控件win32

riched32.dll riched20.dll msftedit.dll 解析

如何修改汇编win32中 static控件的字体颜色

RichEdit控件中的字符间距

如何在MFC中使用richedit控件_RICHEDIT_VER over 2.1

无窗口 RichEdit 控件无法输入表情符号