| ||
Q. Is it possible to control information input into the edit field?
Yes, and in Chapter 10, you saw how to do this correctly using hotkeys. However, hotkeys can easily block the arrival of certain characters into the edit field. In some cases, it might be required to convert the information being entered on the fly. In this case, the subclasses mechanism can be used. To demonstrate this mechanism, consider the program provided in Listing 3.2. Now, I will modify this program to ensure that it is possible to control the information input.
; The EDIT.INC file ; Constants WM_CHAR equ 102h WM_SETFOCUS equ 7h ; This message arrives when the window is closed WM_DESTROY equ 2 ; This message arrives when the window is created WM__CREATE equ 1 ; This message arrives when something happens to the window elements WM_COMMAND equ 111h ; This message allows you to get a string WM_GETTEXT equ 0Dh ; The constant for the SetWindowLong function GWL_WNDPROC equ -4 ; Window properties CS_VREDRAW equ 1h CS_HREDRAW equ 2h CS_GLOBALCLASS equ 4000h WS_TABSTOP equ 10000h WS_SYSMENU equ 80000h WS_OVERLAPPEDWINDOW equ 0+WS_TABSTOP+WS_SYSMENU STYLE equ CS_HREDRAW+CS_VREDRAW+CS_GLOBALCLASS CS_HREDRAW equ 2h BS_DEFPUSHBUTTON equ 1h WS_VISIBLE equ 10000000h WS_CHILD equ 40000000h WS_BORDER equ 800000h STYLBTN equ WS_CHILD+BS_DEFPUSHBUTTON+WS_VISIBLE+WS_TABSTOP STYLEDT equ WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP ; Standard icon identifier IDI_APPLICATION equ 32512 ; Cursor identifier IDC_ARROW equ 32512 ; Window display mode - Normal SW_SHOWNORMAL equ 1 ; Prototypes of external procedures IFDEF MASM EXTERN CallWindowProcA@ 2 0:NEAR EXTERN SetWindowLongA@12:NEAR EXTERN SetFocus@4:NEAR EXTERN SendMessageA@16:NEAR EXTERN MessageBoxA@16:NEAR EXTERN CreateWindowExAg 48:NEAR EXTERN DefWindowProcA@16:NEAR EXTERN DispatchMessageA@4:NEAR EXTERN ExitProcess@4:NEAR EXTERN GetMessageA@16:NEAR EXTERN GetModuleHandleA@ 4:NEAR EXTERN LoadCursorA@ 8:NEAR EXTERN LoadIconAg 8:NEAR EXTERN PostQuitMessage@4:NEAR EXTERN RegisterClassA@4:NEAR EXTERN ShowWindow@ 8:NEAR EXTERN TranslateMessage@4:NEAR EXTERN UpdateWindow@4:NEAR ELSE EXTERN CallWindowProcA:NEAR EXTERN SetWindowLongA:NEAR EXTERN SetFocus:NEAR EXTERN SendMessageA:NEAR EXTERN MessageBoxA:NEAR EXTERN CreateWindowExA:NEAR EXTERN DefWindowProcA:NEAR EXTERN DispatchMessageA:NEAR EXTERN ExitProcess:NEAR EXTERN GetMessageA:NEAR EXTERN GetModuleHandleA:NEAR EXTERN LoadCursorA:NEAR EXTERN LoadIconA:NEAR EXTERN PostQuitMessage:NEAR EXTERN RegisterClassA:NEAR EXTERN ShowWindow:NEAR EXTERN TranslateMessage:NEAR EXTERN UpdateWindow:NEAR CallWindowProcA@20 = CallWindowProcA SetWindowLongA@12 = SetWindowLongA SetFocus@4 = SetFocus SendMessageA@16 = SendMessageA MessageBoxA@16 = MessageBoxA CreateWindowExA@48 = CreateWindowExA DefWindowProcA@16 = DefWindowProcA DispatchMessageA@4 = DispatchMessageA ExitProcess@4 = ExitProcess GetMessageA@16 = GetMessageA GetModuleHandleA@4 = GetModuleHandleA LoadCursorA@8 = LoadCursorA LoadIconA@8 = LoadlconA PostQuitMessage@4 = PostQuitMessage RegisterClassA@4 = RegisterClassA ShowWindow@8 = ShowWindow TranslateMessage@4 = TranslateMessage UpdateWindow@4 = UpdateWindow ENDIF ; Structures ; Message structure MSGSTRUCT STRUC MSHWND DD ? MSMESSAGE DD ? MSWPARAM DD ? MSLPARAM DD ? MSTIME DD ? MSPT DD ? MSGSTRUCT ENDS ;---- Window class structure WNDCLASS STRUC CLSSTYLE DD ? CLWNDPROC DD ? CLSCBCLSEX DD ? CLSCBWNDEX DD ? CLSHINST DD ? CLSHICON DD ? CLSHCURSOR DD ? CLBKGROUND DD ? CLMENNAME DD ? CLNAME DD ? WNDCLASS ENDS ; The EDIT.'ASM file .586P ; Flat memory model .MODEL FLAT, stdcall include editn.inc ; INCLUDELIB directives for the linker IFDEF MASM includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE includelib c:\tasm32\lib\import32.lib ENDIF ;---------------------------------------------- ; Data segment _DATA SEGMENT NEWHWND DD 0 MSG MSGSTRUCT <?> WC WNDCLASS <?> HINST DD 0 ; Application descriptor TITLENAME DB 'Controlling the edit field', 0 CLASSNAME DB 'CLASS32', 0 CPBUT DB 'Exit', 0 ; Exit CPEDT DB ' ', 0 CLSBUTN DB 'BUTTON1, 0 CLSEDIT DB 'EDIT', 0 HWNDBTN DWORD 0 HWNDEDT DWORD 0 CAP BYTE 'Message', 0 MES BYTE 'Exiting the program', 0 TEXT DB 100 DUP(0) OLDWND DD 0 CHAR DD ? _DATA ENDS ; Code segment _TEXT SEGMENT START: ; Get the application handle PUSH 0 CALL GetModuleHandleA@4 MOV [HINST], EAX REG_CLASS: ; Fill the window structure ; Style MOV [WC.CLSSTYLE], STYLE ; Message-handling procedure MOV [WC.CLWNDPROC], OFFSET WNDPROC MOV [WC.CLSCBCLSEX], 0 MOV [WC.CLSCBWNDEX], 0 MOV EAX, [HINST] MOV [WC.CLSHINST], EAX ;---------- Window icon PUSH IDI_APPLICATION PUSH 0 CALL LoadIconA@8 MOV [WC.CLSHICON], EAX ;---------- Window cursor PUSH IDC_ARROW PUSH 0 CALL LoadCursorA@8 MOV [WC.CLSHCURSOR], EAX MOV [WC.CLBKGROUND], 17 ; Window color MOV DWORD PTR [WC.CLMENNAME], 0 MOV DWORD PTR [WC.CLNAME], OFFSET CLASSNAME PUSH OFFSET WC CALL RegisterClassA@4 ; Create a window of the registered class PUSH 0 PUSH [HINST] PUSH 0 PUSH 0 PUSH 150 ; DY - Window height PUSH 400 ; DX - Window width PUSH 100 ; Y - Coordinate of the top left corner PUSH 100 ; X - Coordinate of the top left corner PUSH WS_OVERLAPPEDWINDOW PUSH OFFSET TITLENAME ; Window name PUSH OFFSET CLASSNAME ; Class name PUSH 0 CALL CreateWindowExA@48 ; Check for an error CMP EAX, 0 JZ _ERR MOV [NEWHWND], EAX ; Window descriptor ;------------------------------ PUSH SW_SHOWNORMAL PUSH [NEWHWND] CALL ShowWindow@8 ; Show the newly-created window ;------------------------------ PUSH [NEWHWND] CALL UpdateWindow@4 ; Redraw the visible part ; of the window, the WM_PAINT message ; Message-processing loop MSG_LOOP: PUSH 0 PUSH 0 PUSH 0 PUSH OFFSET MSG CALL GetMessageA@16 CMP AX, 0 JE END_LOOP PUSH OFFSET MSG CALL TranslateMessage@4 PUSH OFFSET MSG CALL DispatchMessageA@4 JMP MSG_LOOP END_LOOP: ; Exit the program (close the process) PUSH [MSG.MSWPARAM] CALL ExitProcess@4 _ERR: JMP END_LOOP ;---------------------------------------- ; Window procedure ; Position of parameters in the stack ; [EBP+014H] ; LPARAM ; [EBP+10H] ; WAPARAM ; [EBP+0CH] ; MES ; [EBP+8] ; HWND WNDPROC PROC PUSH EBP MOV EBP, ESP PUSH EBX PUSH ESI PUSH EDI CMP DWORD PTR [EBP+0CH], WM_DESTROY JE WMDESTROY CMP DWORD PTR [EBP+0CH], WM_CREATE JE WMCREATE CMP DWORD PTR [EBP+0CH], WM_COMMAND JE WMCOMMND JMP DEFWNDPROC WMCOMMND: MOV EAX, HWNDBTN CMP DWORD PTR [EBP+14H], EAX JNE NODESTROY JMP WMDESTROY NODESTROY: MOV EAX, 0 JMP FINISH WMCREATE: ; Create the button window PUSH 0 PUSH [HINST] PUSH 0 PUSH DWORD PTR [EBP+08H] PUSH 20 ; DY PUSH 60 ; DX PUSH 10 ; Y PUSH 10 ; X PUSH STYLBTN PUSH OFFSET CPBUT ; Window name PUSH OFFSET CLSBUTN ; Class name PUSH 0 CALL CreateWindowExA@48 MOV HWNDBTN, EAX ; Save the button descriptor ; Create the edit field PUSH 0 PUSH [HINST] PUSH 0 PUSH DWORD PTR [EBP+08H] PUSH 20 ; DY PUSH 350 ; DX PUSH 50 ; Y PUSH 10 ; X PUSH STYLEDT PUSH OFFSET CPEDT ; Window name PUSH OFFSET CLSEDIT ; Class name PUSH 0 CALL CreateWindowExA@48 MOV HWNDEDT, EAX ; Set the focus to the edit field PUSH HWNDEDT CALL SetFocus@4 ; Set the custom handler procedure PUSH OFFSET WNDEDIT PUSH GWL_WNDPROC PUSH [HWNDEDT] CALL SetWindowLongA@12 MOV OLDWND, EAX MOV EAX, 0 JMP FINISH DEFWNDPROC: PUSH DWORD PTR [EBP+14H] PUSH DWORD PTR [EBP+10H] PUSH DWORD PTR [EBP+0CH] PUSH DWORD PTR [EBP+08H] CALL DefWindowProcA@16 JMP FINISH WMDESTROY: ; Get the edited string PUSH OFFSET TEXT PUSH 150 PUSH WM_GETTEXT PUSH HWNDEDT CALL SendMessageA@16 ; Show the edited string PUSH 0 PUSH OFFSET CAP PUSH OFFSET TEXT PUSH DWORD PTR [EBP+08H] ; Window descriptor CALL MessageBoxA@16 ; Go to exit PUSH 0 CALL PostQuitMessage@4 ; Message WM_QUIT MOV EAX, 0 FINISH: POP EDI POP ESI POP EBX POP EBP RET 16 WNDPROC ENDP ;-------------------------------------------- ; New message-handling procedure for the edit field WNDEDIT PROC PUSH EBP MOV EBP, ESP MOV EAX, DWORD PTR [EBP+10H] MOV CHAR, EAX CMP DWORD PTR [EBP+0CH], WM_CHAR JNE _OLD ; Check the input character CMP AL, 13 JNE _OLD ; Send the message about closing the main window PUSH 0 PUSH 0 PUSH WM_DESTROY PUSH [NEWHWND] CALL SendMessageA@16 _OLD: ; Call the old procedure PUSH DWORD PTR [EBP+014H] PUSH DWORD PTR [EBP+10H] PUSH DWORD PTR [EBP+0CH] PUSH DWORD PTR [EBP+8H] PUSH [OLDWND] CALL CallWindowProcA@20 FIN: POP EBP RET 16 WNDEDIT ENDP _TEXT ENDS END START
There isn't anything new in this mechanism. Even in the MS-DOS operating system, it was possible to trap interrupts and build custom procedures into their handling. As a result, the custom procedure was called prior to the previously installed one if a call was made to this interrupt. It also was possible to proceed in a different way: first, to call the existing procedure, and then, to call the custom one. Because it was possible to catch interrupts multiple times, a chain of sequentially executing procedures might appear as a result. I have already compared the calls with the window procedure and the interrupt calls. They are similar, aren't they? For object-oriented programming, this is nothing else but the creation of the parent class.
The foundation of this mechanism is formed by the SetWindowLong function, which can change the attributes of the existing window. The parameters of this function are as follows :
First parameterThe descriptor of the window created by the current process.
Second parameterThe value that defines what has to be changed. Generally, this is only an offset in a certain memory area. You will be interested only in the value that defines the address of the window procedure. This value is defined by the DWL_DLGPROC = 4 constant (for the dialog) or by GWL_WNDPROC = ˆ 4 (for a normal window). Hence, this operation can be carried out not only over normal windows but also over dialog boxes.
Third parameterThe new value of the window attribute.
It is also necessary to mention that this function returns the old attribute value.
I must note that all window elements that you create on a window are also windows with their own window functions. In everyday practice, you usually will be dealing only with messages arriving at the main window procedure.
The next question you might ask is as follows: How do I call the old window procedure? The standard CALL command is not suitable in this case. You'll have to use a special function for this purpose CallWindowProc . Parameters of this function are as follows:
First parameterThe address of the called procedure
Second parameterThe window descriptor
Third parameterThe message code
Fourth parameterThe WPARAM parameter
Fifth parameterThe LPARAM parameter
To translate the program presented in Listing 18.2, issue the following commands for, MASM32:
ml /c /coff /DMASM editn.asm link /subsystem:windows editn.obj
Issue the following commands for TASM32:
tasm32 /ml editn.asm tlink32 -aa editn.obj
When studying the program presented in Listing 18.2, notice that the method provided in this listing allows you to do practically any trick to the edit field. For example, you can block any character by sending the zero code instead of it, or you can replace the sent character with any other one.
| ||