网页设计师培训需要多少钱,北京优化seo排名优化,资讯门户 wordpress,怎样清理网站后门在这一讲我们将学习什么是超类化以及它有什么作用#xff1b;同时你还会学到怎样在自己的窗口中用Tab键在控件中切换这一技巧。理论#xff1a;在你的程序生涯中你肯定遇到过这样的情况#xff0c;你需要一系列的控件#xff0c;但它们之间却只有一点点的不同。例如#x…在这一讲我们将学习什么是超类化以及它有什么作用同时你还会学到怎样在自己的窗口中用Tab键在控件中切换这一技巧。理论在你的程序生涯中你肯定遇到过这样的情况你需要一系列的控件但它们之间却只有一点点的不同。例如你可能需要10个只接受数字的 Edit 控件当然你可以通过多种方法来达到这个目的。创建自己的类并用它实例化为那些控件创建那些 Edit 控件并把它们全部子类化超类化Edit 控件第一种方法太乏味了因为你必须自己实现Edit 控件的每个功能但这项工作不是轻松就能完成的。第二种方法好于第一种但仍然要做许多工作子类化几个Edit 控件还可以接受但若要子类化十几二十个这项工作简直就是一场恶梦。在这种情况下就应该使用超类化这个技巧它是用于控制某一个特定窗口类的特殊方法。通过这种控制就可以修改窗口类的特性使之符合你的要求然后再创建那一堆控件就可以了。超类化有如下几个步骤通过调用 GetClassInfoEx 来获得想要进行超类化操作的窗口类的信息。函数GetClassInfoEx 需要一个指向 WNDCLASSEX 结构的指针用于当成功返回时填入窗口类的信息。按需要修改 WNDCLASSEX 结构的成员其中有两个成员必须修改hInstance 存放程序的实例句柄lpszClassName 指向一个新类名的指针不必修改成员 lpfnWndProc但大多数情况下还是需要的。但要记住如果要使用函数 CallWindowProc 调用老窗口的过程那就必须保存成员 lpfnWndProc 的原值。注册修改完的 WNDCLASSEX 结构得到一个具有旧窗口类某些特性的新窗口类。用新窗口类创建窗口如果要创建具有相同特性的多个控件超类化就比子类化要好。举例.386.model flat,stdcalloption casemap:noneinclude \masm32\include\windows.incinclude \masm32\include\user32.incinclude \masm32\include\kernel32.incincludelib \masm32\lib\user32.libincludelib \masm32\lib\kernel32.libWM_SUPERCLASS equ WM_USER5WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORDEditWndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD.dataClassName db SuperclassWinClass,0AppName db Superclassing Demo,0EditClass db EDIT,0OurClass db SUPEREDITCLASS,0Message db You pressed the Enter key in the text box!,0.data?hInstance dd ?hwndEdit dd 6 dup(?) 存放6个窗口句柄的数组OldWndProc dd ? 原来的窗口过程.codestart:invoke GetModuleHandle, NULLmov hInstance,eaxinvoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULTinvoke ExitProcess,eaxWinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORDLOCAL wc:WNDCLASSEXLOCAL msg:MSGLOCAL hwnd:HWNDmov wc.cbSize,SIZEOF WNDCLASSEXmov wc.style, CS_HREDRAW or CS_VREDRAWmov wc.lpfnWndProc, OFFSET WndProcmov wc.cbClsExtra,NULLmov wc.cbWndExtra,NULLpush hInstpop wc.hInstancemov wc.hbrBackground,COLOR_APPWORKSPACEmov wc.lpszMenuName,NULLmov wc.lpszClassName,OFFSET ClassNameinvoke LoadIcon,NULL,IDI_APPLICATIONmov wc.hIcon,eaxmov wc.hIconSm,eaxinvoke LoadCursor,NULL,IDC_ARROWmov wc.hCursor,eaxinvoke RegisterClassEx, addr wcinvoke CreateWindowEx,WS_EX_CLIENTEDGEWS_EX_CONTROLPARENT,ADDR ClassName,ADDR AppName,\WS_OVERLAPPEDWS_CAPTIONWS_SYSMENUWS_MINIMIZEBOXWS_MAXIMIZEBOXWS_VISIBLE,CW_USEDEFAULT,\CW_USEDEFAULT,350,220,NULL,NULL,\hInst,NULLmov hwnd,eax.while TRUEinvoke GetMessage, ADDR msg,NULL,0,0.BREAK .IF (!eax)invoke TranslateMessage, ADDR msginvoke DispatchMessage, ADDR msg.endwmov eax,msg.wParamretWinMain endpWndProc proc uses ebx edi hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAMLOCAL wc:WNDCLASSEX.if uMsgWM_CREATEmov wc.cbSize,sizeof WNDCLASSEXinvoke GetClassInfoEx,NULL,addr EditClass,addr wcpush wc.lpfnWndProcpop OldWndProcmov wc.lpfnWndProc, OFFSET EditWndProcpush hInstancepop wc.hInstancemov wc.lpszClassName,OFFSET OurClassinvoke RegisterClassEx, addr wcxor ebx,ebxmov edi,20.while ebx6invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR OurClass,NULL,\WS_CHILDWS_VISIBLEWS_BORDER,20,\edi,300,25,hWnd,ebx,\hInstance,NULLmov dword ptr [hwndEdit4*ebx],eaxadd edi,25inc ebx.endwinvoke SetFocus,hwndEdit.elseif uMsgWM_DESTROYinvoke PostQuitMessage,NULL.elseinvoke DefWindowProc,hWnd,uMsg,wParam,lParamret.endifxor eax,eaxretWndProc endpEditWndProc PROC hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD.if uMsgWM_CHARmov eax,wParam.if (al0 al9) || (alA alF) || (ala alf) || alVK_BACK处理字符0~9A~Fa~f这几个十六进制数.if ala alfsub al,20h如果是字符a~f则把它们变为大写.endifinvoke CallWindowProc,OldWndProc,hEdit,uMsg,eax,lParamret.endif.elseif uMsgWM_KEYDOWNmov eax,wParam.if alVK_RETURNinvoke MessageBox,hEdit,addr Message,addr AppName,MB_OKMB_ICONINFORMATIONinvoke SetFocus,hEdit.elseif alVK_TABinvoke GetKeyState,VK_SHIFTtest eax,80000000.if ZERO?invoke GetWindow,hEdit,GW_HWNDNEXT.if eaxNULLinvoke GetWindow,hEdit,GW_HWNDFIRST.endif.elseinvoke GetWindow,hEdit,GW_HWNDPREV.if eaxNULLinvoke GetWindow,hEdit,GW_HWNDLAST.endif.endifinvoke SetFocus,eaxxor eax,eaxret.elseinvoke CallWindowProc,OldWndProc,hEdit,uMsg,wParam,lParamret.endif.elseinvoke CallWindowProc,OldWndProc,hEdit,uMsg,wParam,lParamret.endifxor eax,eaxretEditWndProc endpend start分析这个程序创建了一个在其客户区有六个被修改的 Edit 控件的简单窗口这些 Edit控件只接受十六进制的数字。实际上这个例子是通过修改窗口了类化的例子得来的。这个程序开始和其它程序一样有趣的部分出现在主窗口被创建的时候.if uMsgWM_CREATEmov wc.cbSize,sizeof WNDCLASSEXinvoke GetClassInfoEx,NULL,addr EditClass,addr wc必须用想进行超类化操作的类数据填充 WNDCLASSEX 结构在我们的例子中就是类 Edit 记住在调用函数 GetClassInfoEx 之前必须填写成员 cbSize否则函数调用 GetClassInfoEx不会在 WNDCLASSEX 结构中填入正确的返回值。成功返回后变量 wc中保存的就是想要创建一个新类所需要的所有信息。push wc.lpfnWndProcpop OldWndProcmov wc.lpfnWndProc, OFFSET EditWndProcpush hInstancepop wc.hInstancemov wc.lpszClassName,OFFSET OurClass现在必须修改变量 wc 的一些属性第一个要修改的就是指向窗口过程的指针。因为在新窗口过程中函数 CallWindowProx 要用到老窗口过程因此得把它保存到一个变量中以便使用。这个技巧和在子类化中用到的一样只不过不是调用 SetWindowLong 而是直接修改 WNDCLASSEX 结构罢了。接下来必须得为这个新类取个名字。invoke RegisterClassEx, addr wc当所有这些都完成时注册这个新类就会得到一个具有旧类某些特征的新类了。xor ebx,ebxmov edi,20.while ebx6invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR OurClass,NULL,\WS_CHILDWS_VISIBLEWS_BORDER,20,\edi,300,25,hWnd,ebx,\hInstance,NULLmov dword ptr [hwndEdit4*ebx],eaxadd edi,25inc ebx.endwinvoke SetFocus,hwndEdit注册完新类就可以创建基于它的窗口了在上面的程序片断中用寄存器 ebx 来保存已创建的窗口数目用寄存器 edi 来保存窗口左上角的 y 坐标。创建一个新窗口时把它的句柄保存在一个双字的数组中当创建完所有的窗口后设定输入焦点为所创建的第一个窗口。这时已经有6个只能接受十六进制数字的 edit 窗口控件了替换的窗口过程处理了字符过滤这实际上和在子类化中的例子是一样的。但不必做子类化那些窗口的额外工作了。在此程序中通过使用 Tabs 键来在各个 Edit 控件中切换来使得这个程序更加有趣。一般来说如果使用对话框对话框管理器会处理好所有这些问题即按下 Tabs 输入焦点切换到下一个控件窗口中按下 Shift-Tabs 输入焦点切换到上一个控件窗口中但一个简单的窗口不具有这个功能必须子类化它们以处理 Tabs 键。在这个例子中不必一个一个去子类化已经进行过超类化操作的这些控件可以使用一种集中控制切换策略。.elseif alVK_TABinvoke GetKeyState,VK_SHIFTtest eax,80000000.if ZERO?invoke GetWindow,hEdit,GW_HWNDNEXT.if eaxNULLinvoke GetWindow,hEdit,GW_HWNDFIRST.endif.elseinvoke GetWindow,hEdit,GW_HWNDPREV.if eaxNULLinvoke GetWindow,hEdit,GW_HWNDLAST.endif.endifinvoke SetFocus,eaxxor eax,eaxret上面是摘自于 EditWndClass 过程的程序片断它检查用户是否按下了 Tabs 键若是就调用函数 GetKeyState 来检查 SHIFT 键是否也被同时按下了。函数 GetKeyState 在寄存器 eax 中设立一个返回值用于判断某个特定的键是否被按下了若按下了则把 eax 的的最高位置1否则把最高位清0。所以只要用 80000000h 来测试返回值就行了若最高位是1则说明用户按下了 SHIFT-Tabs这需要单独处理否则说明只按下 Tabs 键调用函数 GetWindow 来获得 hEdit 所指向窗口的下一个窗口句柄若该函数返回 NULL 说明这是当前窗口是窗口链中最后一个窗口了应该通过以参数 GW_HWNDFIRST 调用函数 GetWindow 来卷回到窗口链中的第一个窗口控件。SHIFT-Tabs 的处理过程和这正好相反。