The second ten lesson window subclass
In this reason, we will learn what is window subclass and how to use it in the way you want.
theory:
If you have edited the program in the Windows environment, sometimes you will find: There is a ready-made window, almost all the features you need, but it is not exactly the same (otherwise there is no need to speak this section). Have you encountered such a situation, if you need an edit control with a special character function. Of course, the most direct way is to implement yourself, but this is indeed a time-friendly task, and window subcategory can be used to do this.
Window Subclass allows you to take over the subclass of windows, so that you have absolute control. For example, you need to accept a text edit box that only accepts hexadecimal numbers. If you use a simple Edit control, you don't know if you enter characters other than hexadecimal. There is no way. That is, when the user enters the text box, enter the string "ZB Q *", if almost anything else to accept the entire string, at least this is particularly unprofessional. It is important that you need to have the ability to input detection, that is, whenever the user enters a character into the edit box, you can detect this character.
Now explain the implementation details: When the user enters the character into the text box, Windows will send a WM_CHAR message to the Edit control window function. This window function itself is parasitized in Windows, so it cannot be modified directly. But we can redirect this message to the window handling function we have written in our own. If the custom window is to handle this message, you can process it. If you do not process, you can forward this message to its original window handling function. In this way, the custom window processing function is inserted into the Windows system and the EDIT control.
Look at the following process: Windows ==> Edit control window processing function before the window subcatenification.
After subclass, Windows ==> Custom Window Processing Function ==> The window handling function of the Edit control.
Attention is not limited to the control, you can submit any windows, now we have to concentrate on how to implement the subclass of one window. Let us think about how Windows knows where the edit control window handling function is placed. Guess? …Certainly not. The original WNDCLASSEX structure, LPFNWndProc, pointed out the window function address. If you can replace this member variable with the address of the window function you have written, the Windows does not send the message to a custom window function! We implemented this task by calling the function setWindowlong, this function is:
Setwindowlong Proto Hwnd: DWORD, NINDEX: DWORD, DWNEWLONG: DWORD
HWnd = The handle of the window to implement the subclass of the window NINDEX = function has the function index GWL_EXSTYLE setup window extension style. GWL_Style Sets the new window style GWL_WNDPROC Set the new window processing function address GWL_HINSTANCE Set the new application handle GWL_ID Set the new window Identify GWL_USERDATA Sets a 32-bit data dwnewlong used to users with this window = data used to update
Our work is still relatively simple:
Write a window function to process messages sent to the EDIT control. Use the parameter GWL_WNDPROC to call the setWindowlong function, if the call is successful, the return value is a 32-bit integer associated with the call function.
In our program, the return value is the address of the original window function. We want to save this value for later use. Remember: There are some news we don't deal with, you need to send them to the original window function, which uses another function CallWindowProc, the origin: CallWindowProc Proto LPPREvWndFunc: DWORD, HWND: DWORD, MSG: DWORD, WPARAM: DWORD, LPARAM: DWORD
LPPREVWNDFUNC = The address of the window is the original function. The remaining four parameters are the parameters sent to the custom function, directly pass them to the function CallWindowProc.
Code example:
.386
.Model flat, stdcall
Option CaseMAP: NONE
INCLUDE /MASM32/INCLUDE/Windows.inc
INCLUDE /MASM32/INCLUDE/USER32.INC
INCLUDE /MASM32/INCLUDE / WANEL32.INC
INCLUDE /MASM32/INCLUDE/ComctL32.inc
INCLUDELIB /MASM32/LIB/ComctL32.lib
INCLUDELIB /MASM32/LIB/USER32.LIB
INCLUDELIB /MASM32/LIB/kernel32.lib
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?
HWndIt 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, HWndIt, GWL_WndProc, Addr EditWndProc
Mov OldWndProc, EAX
.ELSEIF uMSG == WM_DESTROY
Invoke PostquitMessage, NULL
.lse
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_ICONITIONFORMATION
Invoke setfocus, Hedit
.lse
Invoke CallWindowProc, OldWndproc, Hedit, UMSG, WPARAM, LPARAMRET
.endif
.lse
Invoke CallWindowProc, OldwndProc, Hedit, UMSG, WPARAM, LPARAM
RET
.endif
XOR EAX, EAX
RET
EditWndProc ENDP
End Start
analysis:
Invoke SetWindowlong, Hwndit, GWL_WndProc, Addr EditWndProcmov OldWndProc, Eax
After creating the Edit control, the original window function address is replaced with the address of the custom function by calling setWindowl, so that it is noted that in order to call the function CallWindowProc, we store the original window function address, self-written EditWndProc is just a Popular window function. Of course, you can also call a setWindowlong function to store this 32-bit value.
Invoke setWindowlong, HWndIt, GWL_USERDATA, EAX.
Of course, you will call getWindowlong to retrieve this value.
.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
In the function editwndproc, we handle the WM_CHAR message: if the input character is '0' - '9', 'a' - 'f' or 'a' - 'f' accepts, and put this message Forward to the original window function, if you entered the lowercase 'a' - 'f', it becomes uppercase. If you enter is not a hexadecimal character, you will lose it and do not forward this message. Therefore, when the input is a non-hexadecimal character, this character will not be displayed in the Edit control.
.ELSEIF uMSG == WM_KEYDOWN
Mov Eax, WPARAM
.IF AL == VK_RETURN
Invoke Messagebox, Hedit, Addr Message, Addr Appname, MB_OK MB_ICONITIONFORMATION
Invoke setfocus, Hedit
.lse
Invoke CallWindowProc, OldwndProc, Hedit, UMSG, WPARAM, LPARAM
RET
.end .end
Here we further demonstrate the ability of subclass by handling the Enter key. EditWndProc determines if it is a Enter key by checking the WM_KeyDonw message, if the prompt message box is displayed, otherwise it is forwarded this message. You can use window subclass to control additional windows, which is one of the very useful technologies that must be mastered.