WIN32汇编 Richedit控件的使用

时间:2022-03-17 01:18:54

这次来介绍一下一个独特的控件------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        ?

  crBackColor            DWORD        ?

  lcid                            DWORD       ?

  dwReserved            DWORD       ?

   sStyle                       WORD         ?

   wKerning                 WORD          ?

   bUnderlineType       BYTE          ?

   bAnimation               BYTE          ?

  bRevAuthor               BYTE           ?

   bReservedl               BYTE          ?

CHARFORMAT2           ENDS       


字段解释:

成员
cbSize:

结构的大小,由于控件使用该字段来判断结构的版本是CHARFORMAT还是CHARFORMAT2,所以在将结构传递给控件前必须将这个字段设置为正确的的数值。


dwMask:

字段掩码,用来指定结构中哪些字段是有效的,如果没有使用对应的标志,即使某些字段的内容被被设置,控件也不会使用它,dwMask中可以使用的标志可以是下列数值的组合:
CFM_BOLD------dwEffects字段中CFE_BOLDZ值是有效的。

CFM_CHARSET---------bCharSet字段是有效的。

CFM_COLOR---------crTextColor字段和dwEffects中的CFE_AUTOCOLOR值是有效的。

CFM_FACE-----------szFaceName字段的值是有效的。

CFM_ITALIC---------dwEffects字段中CFE_ITATIC值是有效的。

CFM_OFFSET--------yOffset字段是有效的。

CFM_PROTECTED-----dwEffects字段中的CFE_PROTECTED值是有效的。

CFM_SIZE------------yHeight字段是有效的。

CFM_STRIKEOUT-------dwEffects字段中的CFE_STRIKEOUT值是有效的。

CFM_UNDERLINE-------dwEffects字段中的CFE_UNDERLINE值是有效的。


dwEffects:

字符效果,可以是下列值的组合

CFE_AUTOCOLOR------使用系统正文颜色

CFE_BOLD,CFE_ITALIC,CFE_STRIKEOUT和CFE_UNDERLINE--------粗体字符,斜体字符,带删除线和带下划线。

CFE_PROTECTED--------字符是受保护的,企图改变字符的话,控件会向父窗口发送一个EN_PROTECTED通知消息

yHeight:

字符高度,单位是1/1440英寸(或1/20磅),如果这里是180,换算到“字体选择”通用对话框中的尺寸就是9磅(180* 1/20=9)。

yOffset:

从基线算起的字符偏移,单位同上,如果该成员是正值,字符显示为上标;如果是负值,字符显示为下标。


crTextColor:

正文颜色,如果在dwEffects字段中指定了CFE_AUTOCOLOR标志,那么这个值就会被忽略。


bCharSet:
字符集
bPitchAndFamily
字符集
szFaceName
用字符串表示的字体名字。


下面总结一下使用的陌生的API函数
ReadFile() 功能: 文件指针指向的位置开始将数据读入到一个文件中 原型及参数:

BOOL ReadFile(

HANDLE hFile, //文件的句柄

LPVOID lpBuffer, //用于保存读入数据的一个缓冲区

DWORD nNumberOfBytesToRead, //要读入的字节数

LPDWORD lpNumberOfBytesRead, //指向实际读取字节数的指针

LPOVERLAPPED lpOverlapped) //如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须,用这个参数引用一个特殊的结构。该结构定义了一次异步读取操作。否则,应将这个参数设为NULL  

FILE_FLAG_OVERLAPPED

文件或设备被打开或创建异步I / O。

当后续的I / O操作完成这个句柄,OVERLAPPED结构中指定的事件 将被设置为有信号状态。

如果这个标志被指定,该文件可用于同时读取和写入操作。

如果没有指定这个标志,然后被序列化I / O操作,即使调用读写函数指定一个OVERLAPPED结构。

返回值:

调用成功,返回非0

调用不成功,返回为0




WriteFile() 功能: 从文件指针指向的位置开始将数据写入到一个文件中(读出) 原型及参数:

BOOL WriteFile(

HANDLE hFile, // 文件句柄

LPCVOID lpBuffer, // 数据缓存区指针

DWORD nNumberOfBytesToWrite, // 你要写的字节数

LPDWORD lpNumberOfBytesWritten, // 用于保存实际写入字节数的存储区域的指针

LPOVERLAPPED lpOverlapped // OVERLAPPED结构体指针

);

返回值:

调用成功,返回非0

调用不成功,返回为0



CreateFile()

功能:

CreateFile函数创建或打开以下对象并返回一个句柄,可以用来访问对象:文件、管道、mailslots、通信资源、磁盘设备(Windows NT只有)、consoles、目录(只开放)

原型:

HANDLE CreateFile(

LPCTSTR lpFileName, //指向文件名的指针

DWORD dwDesiredAccess, //访问模式(写/读)

DWORD dwShareMode, //共享模式

LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全属性的指针

DWORD dwCreationDisposition, //如何创建

DWORD dwFlagsAndAttributes, //文件属性

HANDLE hTemplateFile //用于复制文件句柄

);

参数:

lpFileName String要打开的文件的名或设备名。这个字符串的最大长度在ANSI版本中为MAX_PATH,在unicode版本中为32767。

dwDesiredAccess指定类型的访问对象。如果为 GENERIC_READ 表示允许对设备进行读访问;如果为 GENERIC_WRITE 表示允许对设备进行写访问(可组合使用);如果为零,表示只允许获取与一个设备有关的信息 。

另外,还可以指定下面的控制标志:

标准控制权限(16-23位掩码):

DELETE 删除对象的权限。

READ_CONTROL 从对象的安全描述符中读取信息的权限,但不包括SACL(系统访问控制列表)中的信息。

WRITE_DAC 修改对象安全描述符中的DACL(随机访问控制列表)的权限

WRITE_OWNER 修改对象安全描述符中的属主的权限

SYNCHRONIZE 同步化使用对象的权限,即可以创建一个线程等待信号量释放(但有些对象不支持这个权限)。

STANDARD_RIGHTS_REQUIRED 等价于前面四种权限的总合(通常这四种是必须具有的权限)。

STANDARD_RIGHTS_READ 一般等价于READ_CONTROL

STANDARD_RIGHTS_WRITE 一般等价于READ_CONTROL

STANDARD_RIGHTS_EXECUTE 一般等价于READ_CONTROL

STANDARD_RIGHTS_ALL 等价于前面五种权限的总合。

特殊控制权限(0-15位掩码):

SPECIFIC_RIGHTS_ALL

ACCESS_SYSTEM_SECURITY

MAXIMUM_ALLOWED

GENERIC_READ

GENERIC_WRITE

GENERIC_EXECUTE

GENERIC_ALL

注:实质上是通过ACCESS_MASK结构体的一个双字值来设置标准权限、特殊权限和一般权限的。

dwShareModeLong, 如果是零表示不共享; 如果是FILE_SHARE_DELETE表示随后打开操作对象会成功只要删除访问请求;如果是FILE_SHARE_READ随后打开操作对象会成功只有请求读访问;如果是FILE_SHARE_WRITE 随后打开操作对象会成功只有请求写访问。

lpSecurityAttributesSECURITY_ATTRIBUTES, 指向一个SECURITY_ATTRIBUTES结构的指针,定义了文件的安全特性(如果操作系统支持的话)

dwCreationDispositionLong,下述常数之一:

CREATE_NEW 创建文件;如文件存在则会出错

CREATE_ALWAYS 创建文件,会改写前一个文件

OPEN_EXISTING 文件必须已经存在。由设备提出要求

OPEN_ALWAYS 如文件不存在则创建它

TRUNCATE_EXISTING 将现有文件缩短为零长度

dwFlagsAndAttributesLong:

 一个或多个下述常数

FILE_ATTRIBUTE_ARCHIVE 标记归档属性

FILE_ATTRIBUTE_COMPRESSED 将文件标记为已压缩,或者标记为文件在目录中的默认压缩方式

FILE_ATTRIBUTE_NORMAL 默认属性

FILE_ATTRIBUTE_HIDDEN 隐藏文件或目录

FILE_ATTRIBUTE_READONLY 文件为只读

FILE_ATTRIBUTE_SYSTEM 文件为系统文件

FILE_FLAG_WRITE_THROUGH 操作系统不得推迟对文件的写操作

FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作

FILE_FLAG_NO_BUFFERING 禁止对文件进行缓冲处理。文件只能写入磁盘卷的扇区块

FILE_FLAG_RANDOM_ACCESS 针对随机访问对文件缓冲进行优化

FILE_FLAG_SEQUENTIAL_SCAN 针对连续访问对文件缓冲进行优化

FILE_FLAG_DELETE_ON_CLOSE 关闭了上一次打开的句柄后,将文件删除。特别适合临时文件

也可在Windows NT下组合使用下述常数标记:

SECURITY_ANONYMOUS, SECURITY_IDENTIFICATION, SECURITY_IMPERSONATION, SECURITY_DELEGATION, SECURITY_CONTEXT_TRACKING, SECURITY_EFFECTIVE_ONLY

返回值:

如执行成功,则返回文件句柄。

INVALID_HANDLE_VALUE表示出错,会设置GetLastError。即使函数成功,但若文件存在,且指定了CREATE_ALWAYS 或 OPEN_ALWAYS,GetLastError也会设为ERROR_ALREADY_EXISTS



CloseHandle()

功能:

关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等

原型:

BOOL CloseHandle(

HANDLE hObject

);

参数:

hObject :代表一个已打开对象handle。

返回值:

TRUE:执行成功;

FALSE:执行失败



SetFilePointer()

功能: 在一个文件中设置当前的读取位置。 原型:

DWORD SetFilePointer(

HANDLE hFile, // 文件句柄

LONG lDistanceToMove, // 偏移量(低位)

PLONG lpDistanceToMoveHigh, // 偏移量(高位)

DWORD dwMoveMethod // 基准位置FILE_BEGIN:文件开始位置 FILE_CURRENT:文件当前位置 FILE_END:文件结束位置

说明:移动一个打开文件的指针

返回值:
Long,返回一个新位置,它采用从文件起始处开始算起的一个字节偏移量。HFILE_ERROR意味着出错。会设置GetLastError


SetEndOfFile()
功能: 针对一个打开的文件,将当前文件位置设为文件末尾
原型: BOOL WINAPI SetEndOfFile(
  _In_ HANDLE hFile
);
参数: hFile Long,一个文件指定句柄。文件的当前位置设为文件尾,文件会根据需要缩短

返回值: Long(32位整数),非零表示成功,零表示失败


SetFocus() 功能: 该函数对指定的窗口设置键盘焦点。该窗口必须与调用线程的消息队列相关。
原型: HWND SetFocus(HWND hWnd)
参数: hWnd:接收键盘输入的窗口指针。若该参数为NULL,则击键被忽略
返回值: 若函数调用成功,则返回原先拥有键盘焦点的窗口句柄。若hWnd参数无效或窗口未与调用线程的消息队列相关,则返回值为NULL。


LoadLibrary() 功能: 载入指定的动态链接库,并将它映射到当前进程使用的地址空间。一旦载入,即可访问库内保存的资源
原型; HMODULE WINAPI LoadLibrary( _In_ LPCTSTR lpFileName);
参数: lpFileName:要载入文件的名称. 一旦不需要,用FreeLibrary函数释放DLL
返回值: Long,成功则返回库模块的句柄,零表示失


RegisterWindowMessage() 功能: 函数定义一个新的窗口消息,保证该消息在系统范围内是唯一的。通常调用SendMessage或者PostMessage函数时,可以使用该函数返回的消息值。
原型: UINT RegisterWindowMessage( lpString);
参数: lpString ------- String,(被注册)消息的名字
返回值: Long,& C000 到 & FFFF之间的一个消息编号。零意味着出错(注册消息失败)




消息:
EM_GETMODIFY 功能: 得到一个编辑控件的状态的修改标记。表明编辑控件的内容是否已经被修改。你可以发送这个消息到一个编辑控件或丰富的编辑控件

参数:

按钮

未使用,必须为零。

lParam

未使用,必须为零。

返回值:

如果编辑控件的内容已经修改,返回值非零;否则,它是零。


WM_ACTIVATE

参数: 
fActive  = LOWORD(wParam);   // activation flag 
fMinimized = (BOOL)HIWORD(wParam); // minimized flag 
hwndPrevious= (HWND)lParam;   // window handle
fActive 参数主要定义了该窗口发生了什么事情,即该窗口是被激活还是被取消。该
信息保存在 wParam 的低阶字中,可以取以下的值:
WA_CLICKACTIVE       通过鼠标单击激活了该窗口 
WA_ACTIVE                   通过鼠标以外的工具(如键盘)激活了该窗口 
WA_INACTIVE               取消该窗口的激活 
示例代码:
case WM_ACTIVATE: 

     // test if window is being activated 
     if(LOWORD(wParam)!=WA_INACTIVE) 
     { 
          // application is being activated 
     } 
     else 
     { 
          // application is being deactivated 
     } 

break;