Win32汇编---控件的超类化感想
对于窗口的子类化相信大家并不陌生:基于某一个控件功能,用窗口子类化来实现我们想要的功能!由于控件的封装,我们无法对它进行直接操作修改,但是我们可以截获windows给控件过程发送的消息,从而达到控制控件窗口的目的!对于单个控件的子类化,并不费事,但是我们如果要注册多个这样的控件就麻烦了,于是产生了超类化的思想。
可以用GetClassInfoEx()来获取现存类的属性,然后修改结构的内容,就可以派生出一个功能不同的类!如下面一段代码:
.const szClass db "NewEdit",0 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ………… _SuperClass proc local @stWndClass:WNDCLASSEX ;////////////////////////////////// ; 基于 Edit 类建立一个新类:NewEdit ;////////////////////////////////// mov @stWndClass.cbSize,sizeof WNDCLASSEX invoke GetClassInfoEx,NULL,CTXT("edit"),addr @stWndClass push @stWndClass.lpfnWndProc pop lpOldProcEdit mov @stWndClass.lpfnWndProc,offset _ProcEdit push hInstance pop @stWndClass.hInstance mov @stWndClass.lpszClassName,offset szClass invoke RegisterClassEx,addr @stWndClass ret _SuperClass endp
基于Edit类的NewEdit类就产生了,其中_ProcEdit子程序是NewEdit类的过程函数。这不禁让我想到当初创建windows窗口的时候,每次都要注册一次WNDCLASSEX结构体函数,下面使我们非常熟悉的代码:
_WinMain proc local @stWndClass:WNDCLASSEX local @stMsg:MSG invoke GetModuleHandle,NULL mov hInstance,eax invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass ;******************************************************************** ; 注册窗口类 ;******************************************************************** 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_WINDOW + 1 mov @stWndClass.lpszClassName,offset szClassName invoke RegisterClassEx,addr @stWndClass …………
这岂不也是对于窗口的“子类化”吗?我们可以自定义窗口的背景颜色,光标位图以及主窗口图标!然后调用CreateWindowEx来创建,我想窗口超类化的思想和这里肯定也有些未知的联系(不知道我的思考对不对)!当然也可以在RC文件中用我们超类化好的“NewEdit”,下面是一段演示代码,是针对进制转化超类化出来的,控件中只能输入0~9以及A~F,并自动把小写字母大写,资源文件的定义如下:
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< #include <resource.h> //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< #define ICO_MAIN 1000 #define DLG_MAIN 1000 //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ICO_MAIN ICON "Main.ico" //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< DLG_MAIN DIALOG 190, 180, 126, 20 STYLE DS_MODALFRAME | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_POPUP CAPTION "SuperClass" FONT 9,"YaHei Consolas Hybrid" { CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,5,115,12 } //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
汇编源代码如下:
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< .386 .model flat, stdcall option casemap: none ;--------------------------------------------------------------------------------- include windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib include macro.asm ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ICO_MAIN equ 1000 DLG_MAIN equ 1000 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< .data? hInstance dd ? hWinMain dd ? lpOldProcEdit dd ? .const szAllowedChar db "0123456789ABCDEFabcdef",08h szClass db "HexEdit",0 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< .code ;--------------------------------------------------------------------------------- _ProcEdit proc uses ebx edi esi hWnd, uMsg, wParam, lParam .if uMsg == WM_CHAR mov eax,wParam lea edi,szAllowedChar mov ecx,sizeof szAllowedChar cld 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 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< _SuperClass proc local @stWndClass:WNDCLASSEX ;////////////////////////////////// ; 基于 Edit 类建立一个新类:HexEdit ;////////////////////////////////// mov @stWndClass.cbSize,sizeof WNDCLASSEX invoke GetClassInfoEx,NULL,CTXT("edit"),addr @stWndClass push @stWndClass.lpfnWndProc pop lpOldProcEdit mov @stWndClass.lpfnWndProc,offset _ProcEdit push hInstance pop @stWndClass.hInstance mov @stWndClass.lpszClassName,offset szClass invoke RegisterClassEx,addr @stWndClass ret _SuperClass endp ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< _ProcDlgMain proc uses ebx edi esi hWnd, uMsg, wParam, lParam mov eax,uMsg .if eax == WM_CLOSE invoke EndDialog,hWnd,NULL .else mov eax,FALSE ret .endif mov eax,TRUE ret _ProcDlgMain endp ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< start: invoke GetModuleHandle,NULL mov hInstance,eax call _SuperClass invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL invoke ExitProcess,NULL ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< end start
这中间我也学到了很多,老早就从Zoologist的文章中了解到如何去用Spy++去查看窗口属性,以及怎么去截获窗口消息。今天用了下,明白了窗口一些基本的属性,以及看到别的程序一些不知道的风格可以去“截取”,而不必打开MSDN,啃着枯燥的英文!突然想到的一点就是有些程序当光标放在BUTTON上面就变成一个手型,很好奇。通过Spy++研究到可以截获WM_MOUSEMOVE消息来了解光标的活动范围,然后用API函数SetCursor来改变光标形状!这个我没有实验过,感觉中不能实现光标的持续性停留变化。还有一招就是调用API函数SetClassLong,利用GCL_HCURSOR参数来“永久改变”,但后再改回来!麻烦了些,具体还没有实验,调研中……
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------