a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 75|回复: 1

[PC技术] 计算机PC技术辅导:窗口子类化

[复制链接]
发表于 2012-7-31 20:55:16 | 显示全部楼层 |阅读模式
  理论:, h- m, [: Z* O" s+ _* i
  如果你曾经在 Windows 环境下编过程序,有时候就会发现:有一个现成的窗口,几乎有你所需要的全部功能,但还不完全一样(否则就没有必要讲这一节了)。你曾遇到过这样的处境吗,如果你需要一个具有过滤特殊字符功能的 Edit 控件。当然最直接的方法就是自己用代码来实现,但这的确是一个费时又很困难的任务,而窗口子类化就可以用来做这种事情。0 V  d7 q2 `7 l1 I2 b
  窗口子类化允许你接管被子类化的窗口,使你对它有绝对的控制权。举个例子了来阐明一下:例如你需要一个只接受十六进制数字输入的文本编辑框,如果使用一个简单的 Edit控件,当用户输入十六进制以外的字符时,你既不知道也无计可施。也就是说,当用户进文本框中输入字符串 "zb+q*" 时,如果除了拒绝接受整个字符串以外几乎什么也不能做,至少这显得特别不专业。重要的是,你需要具有输入检测的能力,即每当用户输入一个字符到编辑框中时要能检测这个字符。- ]" B  r+ V" A+ D9 G. ^
  现在来解释实现细节:当用户往文本框中输入字符时,Windows 会给Edit控件的窗口函数发送 WM_CHAR 消息。这个窗口函数本身寄生于   Windows 中,因此不能直接修改它。但是我们可以重定向这个消息使之发送到我们自己编写的窗口处理函数。如果自定义窗口要处理这个消息那就可以处理它,如果不处理就可以把这个消息转发到它原来窗口处理函数。通过这种方式,自定义的窗口处理函数就把它自己插入到 Windows 系统和 Edit 控件之间。( Z& T% N/ i8 \, n7 E( H6 T
  看下面的流程:
) E3 R9 f) P  A& ?, I8 Y8 x$ n  窗口子类化之前/ J' |0 o( Q( R, |$ P
  Windows ==>Edit 控件的窗口处理函数。5 i0 M: @" N6 U! P4 X& ^
  子类化之后
- m3 X" F2 ^# ]! N; @9 p1 R  Windows ==>自定义的窗口处理函数==> Edit 控件的窗口处理函数。+ t  b+ @, p! s) N- Q
  注意子类化并不局限于控件,可以子类化任何窗口,现在我们要把精力集中到怎样实现子类化一个窗口上。让我们想想Windows 怎样知道 Edit 控件的窗口处理函数放在什么地方。猜的?…肯定不是。原来 WNDCLASSEX 结构的成员 lpfnWndProc 指出了窗口函数地址。如果能用自己编写的窗口函数的地址来替换这个成员变量,那 Windows 不就把消息发到自定义的窗口函数了吗! 我们通过调用函数SetWindowLong 来实现这个任务,此函数的原型为:# `# d: L  Y5 s+ m. U2 G* U
  SetWindowLong PROTO hWnd:DWORD, nIndex:DWORD, dwNewLong:DWORD
- l! e  r& m7 i6 _  hWnd = 将要实施子类化的窗口的句柄
8 P1 d: C) b8 Z0 P+ U( l4 i9 ~* U  nIndex = 函数了功能索引
" d1 F. g* T* j/ Z* G- o  GWL_EXSTYLE 设置窗口的扩展风格./ S$ B7 k1 Q# S- K3 E- y; u
  GWL_STYLE 设置新的窗口风格3 A3 u2 c; g/ h" Z7 y$ N$ P) G& [
  GWL_WNDPROC 设置新的窗口处理函数地址
, _8 _# L/ Z. n! B  GWL_HINSTANCE 设置新的应用程序句柄8 T. [' @- m+ V  e& V6 a
  GWL_ID 设置新的窗口标识
, s. m' y. Q6 r2 x6 ^% U9 w  GWL_USERDATA 设置一个与这个窗口相关的给用户使用的32位的数据2 T+ t0 I3 I6 T! ~. d  x
  dwNewLong = 用来更新的数据  m( O# t4 a. `( g( C+ ~4 C0 L4 |
  我们的工作还是比较简单的:" S2 f! D. t/ Z# e' d) g
  写一个窗口函数用于处理发给 Edit 控件的消息。" Q& G/ c% Z% S1 D" E: q
  用参数GWL_WNDPROC调用SetWindowLong 函数,如果调用成功那么返回值就是与调用功能相联系的一个32位的整数2 ]5 T# L: W) K3 _; }% I; F. s) E" l
  在我们的程序中,返回值就是原先窗口函数的地址。我们要保存这个值以便以后使用。 记住:有一些我们不处理的消息,需要把它们派遣给原来的窗口函数来处理,这就用到另外一个函数 CallWindowProc, 函数原型为:& \1 }1 [# D, Y9 r; F- E  P
  CallWindowProc PROTO lpPrevWndFunc:DWORD, hWnd:DWORD, Msg:DWORD, wParam:DWORD, lParam:DWORD
1 l  O5 u3 I5 v, `  lpPrevWndFunc = 窗口原来函数的地址. 剩下的四个参数就是发给自定义函数的参数,直接把它们传给函数 CallWindowProc 就行了。
, j) z+ @( W; c4 z. A! s  m  D/ f& x( W& A
  代码举例:7 M$ R7 l3 L/ S/ n
  .386, E* `* Y! D" `6 P) f8 M
  .model flat,stdcall
+ \, v) i+ ?: K( D) d  option casemap:none
% F5 g3 |- e; F9 u" _# @0 Y* L  include \masm32\include\windows.inc1 \1 ?2 p$ H* U
  include \masm32\include\user32.inc
6 T9 s) r) n+ _' \' }  include \masm32\include\kernel32.inc7 H+ _0 Q4 C7 K. ?  s$ |3 s
  include \masm32\include\comctl32.inc
4 \: G* s7 C' u3 g! a4 C: K  includelib \masm32\lib\comctl32.lib( _5 T3 I  r. {' `/ A6 D4 B. d
  includelib \masm32\lib\user32.lib) H! I- ~5 ~. r9 [
  includelib \masm32\lib\kernel32.lib! |2 u/ [! F, B. f
  WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
) Q" @: o& X8 m  K% A  EditWndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD& s7 E; P/ t, ~
  .data
' O; q% W4 p$ y& _+ ]' U4 O# u  ClassName db "SubclassWinClass",0
$ z3 I0 E! j( Q2 A& @/ V) I  AppName db "Subclassing Demo",0
/ x/ M/ ]! N2 \4 A4 B& a  EditClass db "EDIT",0
( Y5 W4 y( C" z8 k. n  Message db "You pressed Enter in the text box!",0
+ S  _  @5 ?( d4 x5 q* k- r  .data?
' N7 b2 s6 V; b% s6 Y$ O. f$ E" H  hInstance HINSTANCE ?
$ V* J; x9 H' T9 M0 Q  hwndEdit dd ?
  g9 T% x  P5 q# k# E# O  OldWndProc dd ?7 ^( b  o/ w$ U& [" R
  .code8 C5 ?/ l7 l6 Y; s; R" K
  start:
4 U8 q2 z3 A4 q  invoke GetModuleHandle, NULL0 {3 b4 g6 y+ a! ?. X3 g' i- {
  mov hInstance,eax3 W; v% ?' c. V1 b. b8 s0 E! p& F
  invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
, v$ v/ l, w: I, p; J6 w5 a" }  invoke ExitProcess,eax+ c2 \* V% o% Y, y5 @
  WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
3 X. j  C2 C+ v, H% U, |. r  LOCAL wc:WNDCLASSEX
3 v8 v. e/ X, j* W) U$ C  d  LOCAL msg:MSG$ I* Z! t  B2 r  R
  LOCAL hwnd:HWND
& R; M* [2 _  w! E0 j& m( t7 K0 A  mov wc.cbSize,SIZEOF WNDCLASSEX
* a/ y+ V5 U; z, z3 O1 H  mov wc.style, CS_HREDRAW or CS_VREDRAW4 R$ W- f  o3 s- H- d& B
  mov wc.lpfnWndProc, OFFSET WndProc" [9 u# D1 d* i- {+ j
  mov wc.cbClsExtra,NULL7 p  r1 I  M% {+ P6 H0 ~- R, h% V, m
  mov wc.cbWndExtra,NULL
. X0 D0 x, H5 J  push hInst
/ ?7 j4 d; E6 [+ ^) g  pop wc.hInstance
$ w; X: _& P& b! a: y/ U  mov wc.hbrBackground,COLOR_APPWORKSPACE
& g% H! w! M5 L4 N7 I, W3 J- H  mov wc.lpszMenuName,NULL
+ _% \" J2 t0 h' d# y5 D  mov wc.lpszClassName,OFFSET ClassName
% P( I2 m; m8 u# u/ t) w! A/ |2 f  invoke LoadIcon,NULL,IDI_APPLICATION
回复

使用道具 举报

 楼主| 发表于 2012-7-31 20:55:17 | 显示全部楼层

计算机PC技术辅导:窗口子类化

  mov wc.hIcon,eax
: j" W* ?: @3 O" T" z  mov wc.hIconSm,eax
5 b" k: ?- A; ^; \7 \* r! @# M! u  invoke LoadCursor,NULL,IDC_ARROW
* V. ?! U0 Z% k8 ]+ y; j  mov wc.hCursor,eax
- ?$ W$ q6 C2 @5 k! p  invoke RegisterClassEx, addr wc, s. ]0 ^, y8 m8 p& T2 f
  invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\  WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,\
: U$ J5 L& h7 n- A+ _  CW_USEDEFAULT,350,200,NULL,NULL,\
( g3 |5 J- Z" g  h6 t  hInst,NULL' a' M5 s& ^5 V- [
  mov hwnd,eax
- q+ \. d. B8 _8 L+ w! y) I! o  .while TRUE
3 g5 n5 y5 k% h3 z$ f2 H  invoke GetMessage, ADDR msg,NULL,0,0, ^( P! B- r, [& a$ \3 _
  .BREAK .IF (!eax)
  R1 r# l) \+ t% d  invoke TranslateMessage, ADDR msg
: o3 ^8 ^! l" c$ |% q7 K  invoke DispatchMessage, ADDR msg
2 z. o7 F3 P4 }  .endw# a* t- F% Y# D' P
  mov eax,msg.wParam+ q- }5 v+ J' F4 N: B, _3 O9 N  E
  ret
7 P% h6 F% p$ Q9 s  WinMain endp </p>
! M' l9 R6 a- D- ]/ Y! b  WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM1 v! ]- \6 V  _" W2 v4 K/ m
  .if uMsg==WM_CREATE
: H) F# |6 |  Z, P) h6 Q+ b  invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR EditClass,NULL,\
/ B2 k7 w, g) \$ t) y) m' a; f4 q; V  WS_CHILD+WS_VISIBLE+WS_BORDER,20,\, |. x# Z* Q3 t/ d& L
  20,300,25,hWnd,NULL,\
3 a& S  w0 ?$ h) U: Q$ N: t  hInstance,NULL, v& C$ s. r# Q8 a( m
  mov hwndEdit,eax/ i0 l3 y, M$ p
  invoke SetFocus,eax
+ X6 E/ s) W4 i/ Q1 P  ;-----------------------------------------
9 ^, M: }' @! m  ; Subclass it!
# ~: ^' k, b% E; ?  ;-----------------------------------------
( l* B/ f& L, q" `  invoke SetWindowLong,hwndEdit,GWL_WNDPROC,addr EditWndProc* d3 v7 l2 E$ y! [, \6 Q' p# T
  mov OldWndProc,eax8 X8 s% t3 v8 X: V$ O/ j
  .elseif uMsg==WM_DESTROY/ F0 h/ o' P3 R( Z: M1 I5 a7 P
  invoke PostQuitMessage,NULL2 l5 @2 Y! t9 [! a4 U
  .else
" m: p, P+ G. t" H; C$ v# _  invoke DefWindowProc,hWnd,uMsg,wParam,lParam
6 h( j5 o4 o0 a  ret; g- L* z& N# ]* G( z0 ?) _
  .endif
/ }  S. P. b" m- m8 Q  xor eax,eax
# c0 f/ ~1 x+ C5 N( h  ret: O& K& S7 H5 D, [
  WndProc endp8 ?' p. d  \! R+ J8 J5 f9 u+ B/ g
  EditWndProc PROC hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD+ s4 \) F+ Q6 O
  .if uMsg==WM_CHAR6 n; Y% V6 d; V  a* f: _5 m' N
  mov eax,wParam% G# g9 `4 _9 _1 g9 F6 D$ A
  .if (al>="0" && al="A" && al="a" && al="a" && al="0" && al="A" && al="a" && al="a" && al
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-18 12:12 , Processed in 0.848470 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表