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