Si programas por un tiempo en Windows encontrarás casos donde tu ventana tiene CASI todos los atributos que deseas pero no todos. ¿Haz encontrado una situación donde deseas una clase especial de control de edición que filtre algunos caracteres indeseables? Lo más directo que se puede hacer es codificar tu propia ventana. Pero relamente es un trabajo duro y consume tiempo. La subclasificación de Windows al rescate.
En pocas palabras, la subclasificación de ventanas te permite hacerte cargo de la ventana subclasificada. Tienes el control absoluto sobre ella. Tomemos un ejemplo para clarificar más. Supongamos que necesitas una caja de texto que acepte sólo cadenas en hexadecimal. Si usas un control de edición simple, tienes que decir algo cuando el usuario transcribe algo diferente a números hexadecimales dentro de la caja de texto, es decir. si el usuario escribe "zb+q" dentro de la caja de texto, no puedes hacer nada con ello, excepto rechazar toda la cadena de texto. Esto al menos carece de profesionalidad. En esencia, necesitas la habilidad de examinar cada caracter que el usuario escribió dentro de la caja de texto en el momento que él lo transcribió.
Ahora examinaremos cómo hacerlo. Cuando el usuario tipea algo dentro de la caja de texto, Windows envía el mensaje WM_CHAR al procedimiento de ventana del control de edición. Este procedimiento de ventana reside dentro de Windows así que no podemos modificarlo. Pero podemos redirigir el flujo de mensajes a nuestro propio procedimiento de ventana. Así que nuestro procedimiento de ventana obtendrá primero un impacto [shot] de cualquier mensaje de Windows antes de que sea enviado al control de edición. Si nuestro procedimeinto de ventana resuelve actuar sobre el mensaje, puede aprovechar ahora para hacerlo. Pero si no desea manejar el mensaje, lo pasa al procedimiento de ventana principal. De esta manera, nuestro procedimiento de ventana se inserta dentro de Windows y del control de edición. Veamos el siguiente flujo:
Ahora ponemos nuestra atención en cómo subclasificar una ventana. Nota que la subclasificación no está limitada a los controles, puede ser usada con cualquier ventana. Pensemos cómo Windows llega a tener conocimiento sobre dónde residen los procedimientos de ventana de los controles de edición. Una pista?......el miembro lpfnWndProc de la estructura WNDCLASSEX. Si podemos reemplazar este miembro con la dirección de nuestro procedimiento de ventana, Windows enviará más bien mensajes a nuestro procedimiento de ventana.
Podemos hacer esto llamando a SetWindowLong.
dwNewLong = el valor de reemplazo.
Así que la tarea es fácil. Programamos un procedimiento de ventana que maneje los mensajes para el control de edición y luego llamamos a SetWindowLong con la bandera GWL_WNDPROC, pasando junto a ella la dirección de nuestro procedimento de ventana como tercer parámetro. Si la función tiene éxito, el valor de regreso es el valor previo del número entero especificado de 32-bit, en nuestro caso, la dirección del procedimiento de ventana original. Necesitamos almacenar este valor para usarlo dentro de nuestro procedimiento de ventana.
Recuerda que habrá algunos mensajes que no querrás manejar, los pasaremos al procedimiento de ventana original. Podemos hacerlo llamando a la función CallWindowProc.
lpPrevWndFunc = la dirección del procedimiento de ventana original.
Los restantes cuatro parámetros son pasados a nuestro procedimiento de ventana. Los pasamos justo con CallWindowProc.
WinMain
PROTO :DWORD,:DWORD,:DWORD,:DWORD
EditWndProc
PROTO :DWORD,:DWORD,:DWORD,:DWORD
.data
ClassName
db "SubclassWinClass",0
AppName
db "Subclassing Demo",0
EditClass
db "EDIT",0
Message
db "You pressed Enter in the text box!",0
.data?
hInstance
HINSTANCE ?
hwndEdit
dd ?
OldWndProc
dd ?
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain
proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_APPWORKSPACE
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,\
CW_USEDEFAULT,350,200,NULL,NULL,\
hInst,NULL
mov hwnd,eax
.while TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.endw
mov eax,msg.wParam
ret
WinMain
endp
WndProc
proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.if uMsg==WM_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR EditClass,NULL,\
WS_CHILD+WS_VISIBLE+WS_BORDER,20,\
20,300,25,hWnd,NULL,\
hInstance,NULL
mov hwndEdit,eax
invoke SetFocus,eax
;-----------------------------------------
; Subclass it!
;-----------------------------------------
invoke SetWindowLong,hwndEdit,GWL_WNDPROC,addr EditWndProc
mov OldWndProc,eax
.elseif uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
WndProc
endp
EditWndProc
PROC hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
.if uMsg==WM_CHAR
mov eax,wParam
.if (al>="0" && al<="9") || (al>="A" && al<="F")
|| (al>="a" && al<="f") || al==VK_BACK
.if al>="a" && al<="f"
sub al,20h
.endif
invoke CallWindowProc,OldWndProc,hEdit,uMsg,eax,lParam
ret
.endif
.elseif uMsg==WM_KEYDOWN
mov eax,wParam
.if al==VK_RETURN
invoke MessageBox,hEdit,addr Message,addr AppName,MB_OK+MB_ICONINFORMATION
invoke SetFocus,hEdit
.else
invoke CallWindowProc,OldWndProc,hEdit,uMsg,wParam,lParam
ret
.endif
.else
invoke CallWindowProc,OldWndProc,hEdit,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
EditWndProc
endp
end
start
Ahora quiero demostrar el poder de la subclasificación atrapando la tecla ENTER. EditWndProc chequea el mensaje WM_KEYDOWN para verificar si es VK_RETURN (la tecla Enter). Si lo es, despliega una caja de mensaje que dice "You pressed the Enter key in the text box!". Si no es una tecla Enter, pasa el mensaje al procedimiento de ventana original.
Puedes usar
la subclasificación de ventanas para tomar el control sobre otras ventanas.
Es una de las técnicas más poderosas que deberías tener
en tu arsenal.
[Iczelion's Win32 Assembly HomePage]
n u M I T_o r's Programming Page
Este tutorial, original de Iczelion, ha sido traducido por: n u M I T_o r