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

-------------------------------------------------------

原文地址:https://www.cnblogs.com/kedebug/p/2791756.html