按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 计算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
invoke EndDialog;hWnd;NULL
;********************************************************************
。elseif eax WM_INITDIALOG
mov eax;hWnd
mov hWinMain;eax
invoke SendDlgItemMessage;hWnd;
IDC_HEX;EM_LIMITTEXT;8;0
invoke SendDlgItemMessage;hWnd;
IDC_DEC;EM_LIMITTEXT;10;0
invoke GetDlgItem;hWnd;IDC_HEX
invoke SetWindowLong;eax;GWL_WNDPROC;addr _ProcEdit
mov lpOldProcEdit;eax
;********************************************************************
。elseif eax WM_MAND
mov eax;wParam
。if ! dwOption
mov dwOption;TRUE
。if ax IDC_HEX
invoke _HexToDec
。elseif ax IDC_DEC
invoke _DecToHex
。endif
mov dwOption;FALSE
。endif
。else
mov eax;FALSE
ret
。endif
mov eax;TRUE
ret
_ProcDlgMain endp
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
start:
invoke GetModuleHandle;NULL
mov hInstance;eax
invoke DialogBoxParam;hInstance;DLG_MAIN;
NULL;offset _ProcDlgMain;NULL
invoke ExitProcess;NULL
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第9章 通用控件
9。5 窗口的子类化(3)
end start
程序运行后将显示如图9。9所示的对话框,上面的编辑控件是经过子类化的,只能输入16进制字符,当输入字母a~f的时候,不管输入的是大写还是小写字母,都会被控件转换成大写字母。下面的编辑框是ES_NUMBER风格的,可以输入数字。不管在哪个编辑框中输入数值,程序会马上进行转换并将结果在另一个编辑框中显示出来。
图9。9 窗口子类化例子的运行界面
程序在对话框的初始化消息WM_INITDIALOG中对这两个编辑控件发送EM_LIMITTEXT消息,以此限制能够输入的最大字符长度,接下来程序通过GetDlgItem获取IDC_HEX编辑框的窗口句柄,并使用SetWindowLong函数将编辑框的新窗口过程设置到_ProcEdit子程序中,返回的原窗口过程地址被保存到lpOldProcEdit变量中:
invoke GetDlgItem;hWnd;IDC_HEX
invoke SetWindowLong;eax;GWL_WNDPROC;addr _ProcEdit
mov lpOldProcEdit;eax
这样,当Windows向IDC_HEX编辑框发送消息时,_ProcEdit子程序就会收到消息,在_ProcEdit中我们仅处理感兴趣的WM_CHAR消息,程序在数据段中定义了一个允许输入的字符表,表中包括0~9、大小写的A~F以及退格键(如果不允许输入退格键的话将无法修正输入错误)。然后在处理WM_CHAR消息时使用scasb指令进行查表,如果字符在表中,则将WM_CHAR消息通过CallWindowProc函数转发给原来的窗口过程,如果不在表中则直接返回,相当于丢弃了这个按键动作。代码如下:
nst
szAllowedChar db '0123456789ABCDEFabcdef';08h
de
。。。
mov eax;wParam ;WM_CHAR消息中的一段代码
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
在转发之前,程序还对字符进行判断,如果字符是小写的a~f的话(表中的字符中大于“9”的肯定是字母),则通过and al;not 20h语句将字母转换成大写,因为大写字母的ASCII码从41h开始,小写字母从61h开始,这样的计算方法对大写字母没有影响,对小写的则刚好能够转换成大写的。程序将其他所有的消息原封不动地转发给原来的窗口过程,这样才能让编辑控件的窗口过程为我们完成控件的其他功能。
转发消息使用了CallWindowProc函数,这个函数仅起到将参数入栈和调用指定地址的作用,对于下面的语句我们完全可以用自己调用lpOldProcEdit的方法来代替它:
invoke CallWindowProc;lpOldProcEdit;hWnd;uMsg;eax;lParam
下面的代码就可以完成同样的功能:
push lParam
push eax
push uMsg
push hWnd
call lpO ldProcEdit
程序中的其他代码应该算是相当简单的,_DecToHex子程序是10进制到16进制的转换子程序,子程序中用GetDlgItemInt函数读入编辑框中的10进制数值,并用wsprintf转换成16进制数值的字符串并显示到IDC_HEX编辑框中;_HexToDec是16进制到10进制的转换子程序,由于并没有现成的转换函数,所以在子程序中顺序读入字符并每次通过乘以16来进行计算。
程序中还有一个技巧。由于使用SetDlgItemText设置编辑框文本的时候,编辑框会发送WM_MAND消息,由于一收到某个WM_MAND消息就进行转换计算,并再次使用SetDlgItemText函数将计算结果显示在另一个编辑框中,这样就会进入发送WM_MAND消息的死循环中。为此程序中定义了一个dwOption变量,当正在处理某个WM_MAND消息的时候,将这个变量设置为1来防止重入,这样就能够防止死循环的发生,代码如下:
。elseif eax WM_MAND
mov eax;wParam
。if ! dwOption
mov dwOption;TRUE
。if ax IDC_HEX
invoke _HexToDec
。elseif ax IDC_DEC
invoke _DecToHex
。endif
mov dwOption;FALSE
。endif
对控件窗口进行子类化,影响的仅是被操作的窗口,并不会影响基于这种控件的其他窗口,因为SetWindowLong函数操作的对象仅是单个窗口而不是窗口类。所以要对多个控件窗口进行同样的子类化就必须对每个窗口都进行子类化操作。
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第9章 通用控件
9。6 控件的超类化(1)
9。6。1 什么是控件的超类化
子类化是对窗口功能的调整和扩展,那么超类化是什么呢?超类化是对类的调整和扩展,在C++中,可以通过继承和扩展某个基类来形成一个派生的类,超类化可以完成的功能就和这相似。
超类化主要用在什么地方呢?举例来说,如果需要一个只能输入16进制字符的编辑框,那么可以通过对编辑框窗口子类化来实现,9。5节的例子就是如此,但是当应用程序需要大量使用这种16进制编辑框时,该如何处理呢?方法有3种:
● 创建自己的类,自己书写所有的功能代码。
● 创建多个Edit控件,并把它们全部子类化。
● 超类化Edit控件,用Edit控件当做基类派生出一个新的类,并用这个类来建立多个“新Edit”控件窗口。
第一种方法在9。5节中就被“枪毙”了,几乎没有人去干这种吃力不讨好的事情;第二种方法要好一点,但子类化一大堆的控件也是一件令人头痛的事情;这时就应该使用超类化Edit类方法,当从Edit类派生出一个新的“16进制编辑类”后,接下来直接使用这个类就能够创建出一大堆的16进制编辑框。
9。6。2 控件超类化的实现
各种自定义的窗口和不同的控件窗口之所以看上去千姿百态,功能也各不相同是因为两个原因:首先用来表示类属性的WNDCLASSEX结构定义不同,造成窗口的风格与形状等各不相同;其次,不同窗口类使用的窗口过程不同,这些不同的窗口过程对各种消息的处理方法各不相同,造成窗口的功能不同。
设想这样一种情况:如果自定义一个类,这个类的WNDCLASSEX结构中定义的风格、形状、光标与图标等所有属性都和Edit类相同,然后在自己的类中将窗口过程地址指向Edit类的窗口过程(或者原样拷贝Edit类的窗口过程代码),这个类会实现什么样的功能呢?答案是:除了类的名称不同之外,用这个类创建的窗口的形状和所有功能将和Edit框一模一样!这时候,就相当于从Edit类派生出了一个相同的类来。
这样一来就不难设想从基类派生出新类的方法,我们可以获取基类的WNDCLASSEX结构,然后保持结构中的大部分字段不变,仅修改个别需要自定义的属性,那么新类的窗口风格就和基类类似,如果还需要扩充某些功能的话,可以将结构中的窗口过程地址指到自己的子程序中,这样就可以扩展基类的功能。最后,使用这个修改后的结构以自定义的名称注册一个类,一个新的类就派生出来了。
对基类进行超类化的时候,如果修改的仅是窗口风格,那么使用派生类建立的窗口和基类窗口会实现同样的功能,但外观上会有所不同;如果仿照子类化窗口的方法修改窗口过程,那么使用派生类建立的窗口和基类窗口的外形是相同的,但是功能上会有所不同。
使用GetClassInfoEx函数可以获取现存的类的属性,对基类进行超类化的第一步就是使用这个函数获取基类的WNDCLASSEX 结构。GetClassInfoEx函数的使用方法是:
invoke GetClassInfoEx;hinst;lpszClass;lpwcx
hinst参数是创建这个类的应用程序的实例句柄,如果要获取某个Windows预定义类的属性,那么这个参数使用NULL。
lpszClass参数指向一个字符串,用来定义类的名称。lpwcx参数指向一个WNDCLASSEX结构,用来返回指定类的属性。在调用函数之前,结构中的cbSize必须正确地设置为WNDCLASSEX结构的长度,否则函数的执行可能失败。
获取WNDCLASSEX结构以后,可以根据需要修改结构的内容。如果需要派生出一个功能不同的新类,可以将窗口过程地址设置到自己的程序中,当然原来的地址应该被保存下来,以便收到不感兴趣的消息时转发到原来的窗口过程中。除了修改需要自定义的属性外,还有两个字段是必须修改的:hInstance字段必须设置为应用程序的实例句柄;lpszClassName必须指向新的派生类的类名。完成了这些修改后,使用经过修改的WNDCLASSEX注册一个新的类就大功告成了。
让我们通过一个简单的例子来演示超类化的过程,例子中建立了一个对话框,并在对话框中定义了多个从Edit类派生出来的16进制编辑类,这些类实现的功能和9。5节中的例子是一样的,全部的源代码在所附光盘的Chapter09SuperClass目录中,SuperClass。rc文件的定义如下:
//》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
#include
//》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
#define ICO_MAIN 1000
#define DLG_MAIN 1000
//》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
ICO_MAIN ICON 〃Main。ico〃
//》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
DLG_MAIN DIALOG 107; 102; 126; 82
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION 〃SuperClass〃
FONT 9; 〃宋体〃
{
CONTROL 〃〃;…1;〃HexEdit〃;ES_LEFT | WS_BORDER | WS_TABSTOP;5;5;115;12
CONTROL 〃〃;…1;〃HexEdit〃;ES_LEFT | WS_BORDER | WS_TABSTOP;5;20;115;12
CONTROL 〃〃;…1;〃HexEdit〃;ES_LEFT | WS_BORDER | WS_TABSTOP;5;35;115;12
CONTROL 〃〃;…1;〃Hex