窗口子类化演示
   作者:msfm 于2008-1-17上传 

编辑前言:msfm给我们提供了一个窗口子类化的例子,程序实现了检测输入
    
是否在给定范围的功能。程序很简单,但是对于学习者来说有很大的参考意义。

另外我们还可以根据这个程序的框架扩展出自己需要的程序。通过积累框架的代码

在日后会很方便我们编写简单的程序。


;MASMPlus 代码模板 - 普通的 Windows 程序代码
;********************************************************************
;             窗口子类化演示
; 起源于一个DELPHI项目,需要控制一些字符输入,要求速度优先,于是想到用嵌入汇编
; 解决循环查找字符,带来的时间浪费问题。
; 于是简单的 使用了窗口自类化方法,其中需要注意的是,使用模态与非模态对话框,VK_RETURN
; 消息将不被拦截,希望高手赐教原因。
;  程序还有相当大的优化改进,空间,同时存在很大的不足,目前只是提供了一个框架,希望大
;  家修改,并提出宝贵的意见。谢谢
;********************************************************************
.386
.model flat,stdcall
option casemap:none
include  windows.inc
include  user32.inc
includelib user32.lib
include  kernel32.inc
includelib kernel32.lib
.data?
hInstance  dd ?
hWinMain   dd ?
dwOption   dd ?
lpOldProcEdit dd ?
hedt      dd ?
buf      db 256 dup(?)
.const
szClassName  db 'MyClass',0
Cedt         db "Edit",0           ;标准控件
Cstc         db "static",0          ;标准控件
szCaptionMain db '字符检测',0           ;Cation
szCaption  db '范围定义 *、0..9、:、A..Z、a..z',0   ;合法字符  
lpText     db '提示',0
lpCaption     db '包含非法字符',0
tbTable   db '*','*','0','9',':',':',    
      'A','Z',
      'a','z'           ;定义合法字符Table
tbTableLen  db $-tbTable          ;length(Table)
.code
_isLetter proc
pushad
;下面的程序是一个双层循环,看起来不是很精巧,但是
;算法足够简单,容易理解
   invoke  lstrlen,addr buf
   mov ecx,eax
   lea esi,buf          
  iloop:                     ;外层循环
   mov  bl,[esi]             ;从输入中取出一个字符
   xor  edx,edx              ;我们使用edx作为标记
   push ecx
   lea  edi,tbTable
   movzx ecx,tbTableLen  
   jloop:                    ;内层循环
      mov  ax,[edi]
      .if  (al>bl)
        inc edx      
        jmp nexti      
      .elseif (ah>=bl)
        jmp nexti
      .else
        add edi,2
      .endif
   loop jloop
  nexti:
  pop  ecx
  .if (edx!=0)              ;如果没有标记,说明不符合范围
   mov eax,1
   popad
   ret
  .endif
  inc  esi
  loop iloop
  popad
  xor eax,eax    
   ret
_isLetter endp

_ProcEdit proc  hWnd,uMsg,wParam,lParam
         pushad
     mov eax,uMsg
   .if eax==WM_KEYDOWN
     .if wParam == VK_RETURN
      invoke GetWindowText,hedt,addr buf,sizeof buf
      invoke _isLetter
       .if eax !=0
         invoke MessageBox,hWnd,addr lpCaption,addr lpText ,MB_ICONWARNING
         invoke SetFocus,hedt
         ret
         .endif
         ret
     .endif
     .else
    invoke CallWindowProc,lpOldProcEdit,hWnd,uMsg,wParam,lParam
    ret
   .endif
     xor eax,eax
         popad
     ret
_ProcEdit endp

_ProcWinMain proc uses ebx edi esi hWnd,uMsg,wParam,lParam
  mov eax,uMsg
  .if eax == WM_CLOSE
   invoke DestroyWindow,hWinMain
   invoke PostQuitMessage,NULL
  .else
   invoke DefWindowProc,hWnd,uMsg,wParam,lParam
   ret
  .endif
  xor eax,eax
  ret
_ProcWinMain endp
_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
  invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,offset szCaptionMain,\
   WS_OVERLAPPEDWINDOW,\
   100,100,400,200,\
   NULL,NULL,hInstance,NULL
  mov hWinMain,eax
  
  invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset Cstc,offset szCaption,\
   WS_VISIBLE or WS_CHILD,\
   25,10,350,20,\
   hWinMain,NULL,hInstance,NULL
  invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset Cedt,NULL,\
   WS_VISIBLE or WS_CHILD,\
   25,50,350,40,\
   hWinMain,NULL,hInstance,NULL    
  mov hedt,eax
  invoke SetFocus,hedt
  invoke SetWindowLong,hedt,GWL_WNDPROC,addr _ProcEdit
  mov lpOldProcEdit,eax
  invoke ShowWindow,hWinMain,SW_SHOWNORMAL
  invoke UpdateWindow,hWinMain
;********************************************************************
; 消息循环
;********************************************************************
  .while TRUE
   invoke GetMessage,addr @stMsg,NULL,0,0
   .break .if eax == 0
   invoke TranslateMessage,addr @stMsg
   invoke DispatchMessage,addr @stMsg
  .endw
  ret
_WinMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
  call _WinMain
  invoke ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start

欢迎访问AoGo汇编小站:http://www.aogosoft.com
下一篇>>>