友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
windows环境下32位汇编语言程序设计-第59部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
● ENM_PROTECTED——允许发送EN_PROTECTED通知码。
● ENM_SCROLL——允许发送EN_HSCROLL和EN_VSCROLL通知码。
● ENM_SCROLLEVENTS——允许为鼠标滑轮发送EN_MSGFILTER通知码。
● ENM_SELCHANGE——允许发送EN_SELCHANGE通知码,本消息在选择区域改变以后发送(包括光标位置改变)。
● ENM_UPDATE——允许发送EN_UPDATE通知码,本消息在控件将要显示被改变的文本之前发送。
当这些通知消息被激活的时候,父窗口就可以收到包含相应通知码的WM_NOTIFY消息。一般来说,将控件设置为仅发送程序感兴趣的通知消息,如当在Richedit控件中按下右键需要弹出一个菜单的时候,需要检测鼠标消息,那么就需要指定ENM_MOUSEEVENTS标志;另外,如果需要随时检测选择区域的状态,以便随时设置工具栏中“拷贝”与“剪切”等按钮的状态,那么就要使用ENM_SELCHANGE标志,这样光标一移动或者选择区域一改变,父窗口就可以收到EN_SELCHANGE通知码,于是程序就可以在WM_NOTIFY消息中随时改变工具栏上各按钮的状态。
由于Richedit。asm例子中没有使用工具栏,所以没有对通知消息进行示例,有兴趣的读者可以查看所附光盘的Chapter09Wordpad目录中的例子文件,这个例子中使用工具栏和状态栏等控件,需要随时显示光标位置等信息,程序中就包含了处理通知消息的代码。
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第9章 通用控件
9。5 窗口的子类化(1)
9。5。1 什么是窗口的子类化
在使用控件的过程中,常常会遇到这样一种情况:我们需要一种窗口,它和某种现成的控件提供的功能很相似,如果使用现成控件的话,那么控件几乎能提供所有需要的功能,仅我们要求的某个细节无法实现。举例来说,要编写一个16进制与10进制的转换程序,程序中需要两个编辑控件来输入数值,输入10进制数值可以使用现成的Edit控件,只要指定ES_NUMBER风格就能让编辑框只能输入数字0~9,但输入16进制数值的时候就不行了,因为指定ES_NUMBER风格的话就无法输入A~F,不指定的话用户就可能输入0~9和A~F之外的东西,那么该如何处理呢?
解决的办法有两种,第一种当然是自己创建一个窗口类,然后在自己的窗口过程中完成所有的功能,这显然是一项费时又费力的工作,因为我们几乎要自己重新写一遍Edit控件的全部功能;第二种方法就是使用本节要介绍的窗口子类化,窗口子类化最适合做的就是这一类工作。
窗口子类化的含义是接管被子类化的控件窗口,以达到对它进行控制的目的。虽然控件的窗口过程被封装在Windows内部,无法对它进行直接修改,但只要能截获Windows给控件的窗口过程发送的消息,就能够控制控件窗口。以上面的要求为例,只要截获Windows向编辑控件发送的WM_CHAR消息,就能够根据需要丢弃包含非16进制字符的WM_CHAR消息,只把包含16进制字符的WM_CHAR转发给控件的窗口过程,这样编辑控件将根本收不到16进制字符之外的字符,我们的要求也就达到了。
控件窗口子类化的流程如图9。8所示。
子类化的操作并不局限于控件窗口,实际上任何窗口都可以子类化。但是对于应用程序自身使用的窗口类来说,它的控制权本来就是100%属于应用程序自身的,要实现某种功能就直接修改源代码好了,没有必要再进行一个子类化的过程,所以子类化的操作往往是对“黑匣子”类型的控件窗口进行的。
图9。8 窗口子类化的工作原理
9。5。2 窗口子类化的实现
窗口子类化的要点是截获窗口的窗口过程,如何实现这一点呢?每个窗口的内部都保存有它所属的窗口类的WNDCLASSEX 结构,结构中的lpfnWndProc字段指出了窗口过程的地址,如果能用自己的窗口过程地址来替换这个地址,那么Windows就会把消息发送到自定义的窗口过程中来了。通过调用函数SetWindowLong可以实现这个功能,SetWindowLong函数的用法是这样的:
invoke SetWindowLong;hWnd;nIndex;dwNewLong
mov dwOldLong
hWnd参数指定要子类化窗口的窗口句柄,nIndex参数指定需要修改窗口的哪个属性,它可以是以下的取值:
● GWL_EXSTYLE——窗口的扩展风格。
● GWL_STYLE——窗口风格。
● GWL_WNDPROC——窗口过程地址(这就是我们需要的)。
● GWL_HINSTANCE——窗口所属的模块实例句柄。
● GWL_ID——窗口ID。
● GWL_USERDATA——窗口附带的32位自定义数值。
dwNewLong参数指定新的属性值。如果nIndex为GWL_WNDPROC,dwNewLong表示新的窗口过程地址;如果nIndex为GWL_STYLE,dwNewLong则表示新的窗口风格,依此类推。函数的返回值是指定属性的原先数值。当函数用于窗口子类化的时候,在nIndex参数中使用GWL_WNDPROC,以便将窗口过程地址设置到自定义的子程序中,这时函数返回的是控件窗口原来的窗口过程地址,由于窗口子类化的出发点就是为了尽量使用控件窗口原有的功能,程序为了“偷懒”而不去处理的大部分消息还要靠原来的窗口过程来处理,所以这个地址必须被保存下来。
让我们通过一个简单的例子来演示窗口子类化的实现过程,程序实现的就是前面介绍的16进制与10进制转换的程序,源代码位于所附光盘的Chapter09SubClass目录中。程序首先在资源脚本文件SubClass。rc中定义了一个对话框,对话框中包括两个编辑控件,IDC_DEC用来输入10进制数值,它包含ES_NUMBER风格,只能输入0~9的数值;而IDC_HEX用来输入16进制数值,代码如下:
//》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
#include
//》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
#define ICO_MAIN 1000
#define DLG_MAIN 1000
#define IDC_HEX 1001
#define IDC_DEC 1002
//》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
ICO_MAIN ICON 〃Main。ico〃
//》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
DLG_MAIN DIALOG 107; 102; 129; 42
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION 〃Hex Dec〃
FONT 9; 〃宋体〃
{
LTEXT 〃Hex〃; …1; 7; 9; 15; 8
EDITTEXT IDC_HEX; 27; 7; 94; 12
LTEXT 〃Dec〃; …1; 7; 26; 15; 8
EDITTEXT IDC_DEC; 27; 24; 94; 12; ES_NUMBER
}
汇编源程序SubClass。asm的内容如下:
。386
。model flat; stdcall
option casemap :none
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; Include 文件定义
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
include windows。inc
include user32。inc
includelib user32。lib
include kernel32。inc
includelib kernel32。lib
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; Equ 等值定义
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
ICO_MAIN equ 1000
DLG_MAIN equ 1000
IDC_HEX equ 1001
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第9章 通用控件
9。5 窗口的子类化(2)
IDC_DEC equ 1002
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 数据段
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
。data?
hInstance dd ?
hWinMain dd ?
dwOption dd ?
lpOldProcEdit dd ?
nst
szFmtDecToHex db '%08X';0
szFmtHexToDec db '%u';0
szAllowedChar db '0123456789ABCDEFabcdef';08h
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 代码段
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
de
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; IDC_HEX编辑框的新窗口过程
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
_ProcEdit proc uses ebx edi esi hWnd;uMsg;wParam;lParam
mov eax;uMsg
。if uMsg WM_CHAR
mov eax;wParam
mov edi;offset szAllowedChar
mov ecx;sizeof szAllowedChar
repnz scasb
。if ZERO?
。if al 》 '9'
and al;not 20h
。endif
invoke CallWindowProc;lpOldProcEdit;
hWnd;uMsg;eax;lParam
ret
。endif
。else
invoke CallWindowProc;lpOldProcEdit;
hWnd;uMsg;wParam;lParam
ret
。endif
xor eax;eax
ret
_ProcEdit endp
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 计算16进制到10进制
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
_HexToDec proc
local @szBuffer'512':byte
invoke GetDlgItemText;hWinMain;IDC_HEX;
addr @szBuffer;sizeof @szBuffer
lea esi;@szBuffer
cld
xor eax;eax
mov ebx;16
。while TRUE
movzx ecx;byte ptr 'esi'
inc esi
。break 。if ! ecx
。if cl 》 '9'
sub cl;'A' … 0ah
。else
sub cl;'0'
。endif
mul ebx
add eax;ecx
。endw
invoke wsprintf;addr @szBuffer;addr szFmtHexToDec;eax
invoke SetDlgItemText;hWinMain;IDC_DEC;addr @szBuffer
ret
_HexToDec endp
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 计算10进制到16进制
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
_DecToHex proc
local @szBuffer'512':byte
invoke GetDlgItemInt;hWinMain;IDC_DEC;NULL;FALSE
invoke wsprintf;addr @szBuffer;addr szFmtDecToHex;eax
invoke SetDlgItemText;hWinMain;IDC_HEX;addr @szBuffer
ret
_DecToHex endp
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
_ProcDlgMain proc uses ebx edi esi hWnd;wMsg;wParam;lParam
mov eax;wMsg
;********************************************************************
。if eax WM_CLOSE
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!