📄 lion-tutorial20.htm
字号:
<html>
<head>
<link rel="stylesheet" href="../../asm.css">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Iczelion's win32 asm tutorial</title>
</head>
<body bgcolor="#FFFFFF" background="../../images/back01.jpg">
<p align="center">Tutorial 20: Window Subclassing</p>
<hr size="1">
<strong> </strong> In this tutorial, we will learn about window subclassing, what
it is and how to use it to your advantage. <br>
Download the example <a href="files/tut20.zip">here</a>.
<h3> Theory:</h3>
If you program in Windows for some time, you will find some cases where a window
has <i>nearly</i> the attributes you need in your program but not quite. Have
you encountered a situation where you want some special kind of edit control that
can filter out some unwanted text? The straightforward thing to do is to code
your own window. But it's really hard work and time-consuming. Window subclassing
to the rescue. <br>
In a nutshell, window subclassing allows you to "take over" the subclassed window.
You will have absolute control over it. Let's take an example to make this clearer.
Suppose you need a text box that accepts only hex numbers. If you use a simple
edit control, you have no say whatsoever when your user types something other
than hex numbers into your text box, ie. if the user types "zb+q*" into your text
box, you can't do anything with it except rejecting the whole text string. This
is <i>unprofessional</i> at least. In essence, you need the ability to examine
each character the user typed into the text box right at the moment he typed it.
<br>
We will examine how to do that now. When the user types something into a text
box, Windows sends WM_CHAR message to the edit control's window procedure. This
window procedure resides inside Windows itself so we can't modify it. <b>But we
can redirect the message flow to our own window procedure</b>. So that our window
procedure will get first shot at any message Windows sends to the edit control.
If our window procedure chooses to act on the message, it can do so. But if it
doesn't want to handle the message, it can pass it to the original window procedure.
This way, our window procedure inserts itself between Windows and the edit control.
Look at the flow below:
<ul>
<h4> Before Subclassing</h4>
Windows ==> edit control's window procedure
<h4> After Subclassing</h4>
Windows ==> our window procedure -----> edit control's window procedure
</ul>
Now we put our attention on how to subclass a window. Note that subclassing is
not limited to controls, it can be used with any window. <br>
Let's think about how Windows knows where the edit control's window procedure
resides. A guess?......lpfnWndProc member of WNDCLASSEX structure. If we can replace
this member with the address of our own window procedure, Windows will send messages
to our window proc instead. <br>
We can do that by calling SetWindowLong.
<ul>
<b>SetWindowLong PROTO hWnd:DWORD, nIndex:DWORD, dwNewLong:DWORD</b>
</ul>
hWnd = handle of the window to change the value in the WNDCLASSEX structure <br>
nIndex == value to change.
<ul>
<b>GWL_EXSTYLE</b> Sets a new extended window style. <br>
<b>GWL_STYLE</b> Sets a new window style. <br>
<b>GWL_WNDPROC</b> Sets a new address for the window procedure. <br>
<b>GWL_HINSTANCE</b> Sets a new application instance handle. <br>
<b>GWL_ID</b> Sets a new identifier of the window. <br>
<b>GWL_USERDATA</b> Sets the 32-bit value associated with the window. Each window
has a corresponding 32-bit value intended for use by the application that created
the window.
</ul>
dwNewLong = the replacement value. <br>
So our job is easy: We code a window proc that will handle the messages for the
edit control and then call SetWindowLong with GWL_WNDPROC flag, passing along
the address of our window proc as the third parameter. If the function succeeds,
the return value is the previous value of the specified 32-bit integer, in our
case, the address of the original window procedure. We need to store this value
for use within our window procedure. <br>
Remember that there will be some messages we don't want to handle, we will pass
them to the original window procedure. We can do that by calling CallWindowProc
function.
<ul>
<b>CallWindowProc PROTO lpPrevWndFunc:DWORD, \</b> <br>
<b>
hWnd:DWORD,\</b> <br>
<b>
Msg:DWORD,\</b> <br>
<b>
wParam:DWORD,\</b> <br>
<b>
lParam:DWORD</b>
</ul>
lpPrevWndFunc = the address of the original window procedure. <br>
The remaining four parameters are the ones passed to our window procedure. We
just pass them along to CallWindowProc.
<h4> Code Sample:</h4>
<b>.386</b> <br>
<b>.model flat,stdcall</b> <br>
<b>option casemap:none</b> <br>
<b>include \masm32\include\windows.inc</b> <br>
<b>include \masm32\include\user32.inc</b> <br>
<b>include \masm32\include\kernel32.inc</b> <br>
<b>include \masm32\include\comctl32.inc</b> <br>
<b>includelib \masm32\lib\comctl32.lib</b> <br>
<b>includelib \masm32\lib\user32.lib</b> <br>
<b>includelib \masm32\lib\kernel32.lib</b>
<p><b>WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD</b> <br>
<b>EditWndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD</b>
<p><b>.data</b> <br>
<b>ClassName db "SubclassWinClass",0</b> <br>
<b>AppName db "Subclassing Demo",0</b> <br>
<b>EditClass db "EDIT",0</b> <br>
<b>Message db "You pressed Enter in the text box!",0</b>
<p><b>.data?</b> <br>
<b>hInstance HINSTANCE ?</b> <br>
<b>hwndEdit dd ?</b> <br>
<b>OldWndProc dd ?</b>
<p><b>.code</b> <br>
<b>start:</b> <br>
<b> invoke GetModuleHandle, NULL</b> <br>
<b> mov hInstance,eax</b> <br>
<b> invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT</b>
<br>
<b> invoke ExitProcess,eax</b>
<p><b>WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD</b>
<br>
<b> LOCAL wc:WNDCLASSEX</b> <br>
<b> LOCAL msg:MSG</b> <br>
<b> LOCAL hwnd:HWND</b> <br>
<b> mov wc.cbSize,SIZEOF WNDCLASSEX</b> <br>
<b> mov wc.style, CS_HREDRAW or CS_VREDRAW</b>
<br>
<b> mov wc.lpfnWndProc, OFFSET WndProc</b> <br>
<b> mov wc.cbClsExtra,NULL</b> <br>
<b> mov wc.cbWndExtra,NULL</b> <br>
<b> push hInst</b> <br>
<b> pop wc.hInstance</b> <br>
<b> mov wc.hbrBackground,COLOR_APPWORKSPACE</b>
<br>
<b> mov wc.lpszMenuName,NULL</b> <br>
<b> mov wc.lpszClassName,OFFSET ClassName</b>
<br>
<b> invoke LoadIcon,NULL,IDI_APPLICATION</b> <br>
<b> mov wc.hIcon,eax</b> <br>
<b> mov wc.hIconSm,eax</b> <br>
<b> invoke LoadCursor,NULL,IDC_ARROW</b> <br>
<b> mov wc.hCursor,eax</b> <br>
<b> invoke RegisterClassEx, addr wc</b> <br>
<b> invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR
AppName,\</b> <br>
<b> WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,\</b>
<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -