• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            旅途

            如果想飛得高,就該把地平線忘掉

            超類化

             在這一講我們將學習什么是超類化以及它有什么作用;同時你還會學到怎樣在自己的窗口中用Tab鍵在控件中切換這一技巧。

            理論:

            在你的程序生涯中你肯定遇到過這樣的情況,你需要一系列的控件,但它們之間卻只有一點點的不同。例如,你可能需要10個只接受數(shù)字的 Edit 控件,當然你可以通過多種方法來達到這個目的。

            創(chuàng)建自己的類并用它實例化為那些控件
            創(chuàng)建那些 Edit 控件并把它們?nèi)孔宇惢?
            超類化Edit 控件
            第一種方法太 乏味了,因為你必須自己實現(xiàn)Edit 控件的每個功能,但這項工作不是輕松就能完成的。第二種方法好于第一種,但仍然要做許多工作,子類化幾個Edit 控件還可以接受,但若要子類化十幾二十個,這項工作簡直就是一場惡夢。在這種情況下就應該使用超類化這個技巧,它是用于控制某一個特定窗口類的特殊方法。 通過這種控制就可以修改窗口類的特性使之符合你的要求,然后再創(chuàng)建那一堆控件就可以了。

            超類化有如下幾個步驟:

            通過調(diào)用 GetClassInfoEx 來獲得想要進行超類化操作的窗口類的信息。函數(shù)GetClassInfoEx 需要一個指向 WNDCLASSEX 結(jié)構(gòu)的指針,用于當成功返回時填入窗口類的信息。
            按需要修改 WNDCLASSEX 結(jié)構(gòu)的成員,其中有兩個成員必須修改:
            hInstance 存放程序的實例句柄
            lpszClassName 指向一個新類名的指針
            不必修改成員 lpfnWndProc,但大多數(shù)情況下還是需要的。但要記住如果要使用函數(shù) CallWindowProc 調(diào)用老窗口的過程,那就必須保存成員 lpfnWndProc 的原值。
            注冊修改完的 WNDCLASSEX 結(jié)構(gòu),得到一個具有舊窗口類某些特性的新窗口類。
            用新窗口類創(chuàng)建窗口
            如果要創(chuàng)建具有相同特性的多個控件,超類化就比子類化要好。

            舉例:

            .386
            .model flat,stdcall
            option casemap:none
            include \masm32\include\windows.inc
            include \masm32\include\user32.inc
            include \masm32\include\kernel32.inc
            includelib \masm32\lib\user32.lib
            includelib \masm32\lib\kernel32.lib
            WM_SUPERCLASS equ WM_USER+5
            WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
            EditWndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD

            .data
            ClassName db "SuperclassWinClass",0
            AppName db "Superclassing Demo",0
            EditClass db "EDIT",0
            OurClass db "SUPEREDITCLASS",0
            Message db "You pressed the Enter key in the text box!",0

            .data?
            hInstance dd ?
            hwndEdit dd 6 dup(?) ;存放6個窗口句柄的數(shù)組
            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+WS_EX_CONTROLPARENT,ADDR ClassName,ADDR AppName,\
            WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,\
            CW_USEDEFAULT,350,220,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 uses ebx edi hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
            LOCAL wc:WNDCLASSEX
            .if uMsg==WM_CREATE
            mov wc.cbSize,sizeof WNDCLASSEX
            invoke GetClassInfoEx,NULL,addr EditClass,addr wc
            push wc.lpfnWndProc
            pop OldWndProc
            mov wc.lpfnWndProc, OFFSET EditWndProc
            push hInstance
            pop wc.hInstance
            mov wc.lpszClassName,OFFSET OurClass
            invoke RegisterClassEx, addr wc
            xor ebx,ebx
            mov edi,20
            .while ebx<6
            invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR OurClass,NULL,\
            WS_CHILD+WS_VISIBLE+WS_BORDER,20,\
            edi,300,25,hWnd,ebx,\
            hInstance,NULL
            mov dword ptr [hwndEdit+4*ebx],eax
            add edi,25
            inc ebx
            .endw
            invoke SetFocus,hwndEdit
            .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
            ;處理字符0~9,A~F,a~f,這幾個十六進制數(shù)
            .if al>="a" && al<="f"
            sub al,20h
            如果是字符a~f,則把它們變?yōu)榇髮?br>.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
            .elseif al==VK_TAB
            invoke GetKeyState,VK_SHIFT
            test eax,80000000
            .if ZERO?
            invoke GetWindow,hEdit,GW_HWNDNEXT
            .if eax==NULL
            invoke GetWindow,hEdit,GW_HWNDFIRST
            .endif
            .else
            invoke GetWindow,hEdit,GW_HWNDPREV
            .if eax==NULL
            invoke GetWindow,hEdit,GW_HWNDLAST
            .endif
            .endif
            invoke SetFocus,eax
            xor eax,eax
            ret
            .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


            分析

            這個程序創(chuàng)建了一個在其客戶區(qū)有六個被修改的 Edit 控件的簡單窗口,這些 Edit控件只接受十六進制的數(shù)字。實際上,這個例子是通過修改窗口了類化的例子得來的。這個程序開始和其它程序一樣,有趣的部分出現(xiàn)在主窗口被創(chuàng)建的時候:

            .if uMsg==WM_CREATE
            mov wc.cbSize,sizeof WNDCLASSEX
            invoke GetClassInfoEx,NULL,addr EditClass,addr wc

            必須用想進行超類化操作的類數(shù)據(jù)填充 WNDCLASSEX 結(jié)構(gòu),在我們的例子中就是類 Edit ,記住在調(diào)用函數(shù) GetClassInfoEx 之前必須填寫成員 cbSize,否則函數(shù)調(diào)用 GetClassInfoEx不會在 WNDCLASSEX 結(jié)構(gòu)中填入正確的返回值。成功返回后,變量 wc中保存的就是想要創(chuàng)建一個新類所需要的所有信息。

            push wc.lpfnWndProc
            pop OldWndProc
            mov wc.lpfnWndProc, OFFSET EditWndProc
            push hInstance
            pop wc.hInstance
            mov wc.lpszClassName,OFFSET OurClass

            現(xiàn)在必須修改變量 wc 的一些屬性:第一個要修改的就是指向窗口過程的指針。因為在新窗口過程中函數(shù) CallWindowProx 要用到老窗口過程,因此得把它保存到一個變量中以便使用。這個技巧和在子類化中用到的一樣,只不過不是調(diào)用 SetWindowLong 而是直接修改 WNDCLASSEX 結(jié)構(gòu)罷了。接下來必須得為這個新類取個名字。

            invoke RegisterClassEx, addr wc

            當所有這些都完成時,注冊這個新類就會得到一個具有舊類某些特征的新類了。

            xor ebx,ebx
            mov edi,20
            .while ebx<6
            invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR OurClass,NULL,\
            WS_CHILD+WS_VISIBLE+WS_BORDER,20,\
            edi,300,25,hWnd,ebx,\
            hInstance,NULL
            mov dword ptr [hwndEdit+4*ebx],eax
            add edi,25
            inc ebx
            .endw
            invoke SetFocus,hwndEdit

            注冊完新類就可以創(chuàng)建基于它的窗口了:
            在上面的程序片斷中,用寄存器 ebx 來保存已創(chuàng)建的窗口數(shù)目,用寄存器 edi 來保存窗口左上角的 y 坐標。創(chuàng)建一個新窗口時,把它的句柄保存在一個雙字的數(shù)組中,當創(chuàng)建完所有的窗口后,設定輸入焦點為所創(chuàng)建的第一個窗口。

            這時已經(jīng)有6個只能接受十六進制數(shù)字的 edit 窗口控件了,替換的窗口過程處理了字符過濾,這實際上和在子類化中的例子是一樣的。但不必做子類化那些窗口的額外工作了。

            在此程序中,通過使用 Tabs 鍵來在各個 Edit 控件中切換來使得這個程序更加有趣。一般來說,如果使用對話框,對話框管理器會處理好所有這些問題,即:
            按 下 Tabs 輸入焦點切換到下一個控件窗口中,按下 Shift-Tabs 輸入焦點切換到上一個控件窗口中;但一個簡單的窗口不具有這個功能,必須子類化它們以處理 Tabs 鍵。在這個例子中,不必一個一個去子類化已經(jīng)進行過超類化操作的這些控件,可以使用一種集中控制切換策略。

            .elseif al==VK_TAB
            invoke GetKeyState,VK_SHIFT
            test eax,80000000
            .if ZERO?
            invoke GetWindow,hEdit,GW_HWNDNEXT
            .if eax==NULL
            invoke GetWindow,hEdit,GW_HWNDFIRST
            .endif
            .else
            invoke GetWindow,hEdit,GW_HWNDPREV
            .if eax==NULL
            invoke GetWindow,hEdit,GW_HWNDLAST
            .endif
            .endif
            invoke SetFocus,eax
            xor eax,eax
            ret

            上面是摘自于 EditWndClass 過程的程序片斷,它檢查用戶是否按下了 Tabs 鍵,若是就調(diào)用函數(shù) GetKeyState 來檢查 SHIFT 鍵是否也被同時按下了。函數(shù) GetKeyState 在寄存器 eax 中設立一個返回值,用于判斷某個特定的鍵是否被按下了,若按下了,則把 eax 的的最高位置1,否則把最高位清0。所以只要用 80000000h 來測試返回值就行了,若最高位是1則說明用戶按下了 SHIFT-Tabs,這需要單獨處理;否則說明只按下 Tabs 鍵,調(diào)用函數(shù) GetWindow 來獲得 hEdit 所指向窗口的下一個窗口句柄,若該函數(shù)返回 NULL ,說明這是當前窗口是窗口鏈中最后一個窗口了,應該通過以參數(shù) GW_HWNDFIRST 調(diào)用函數(shù) GetWindow 來卷回到窗口鏈中的第一個窗口控件。SHIFT-Tabs 的處理過程和這正好相反。

            posted on 2007-07-18 00:08 旅途 閱讀(277) 評論(0)  編輯 收藏 引用 所屬分類: 深入windows

            久久精品国产国产精品四凭 | 欧美一级久久久久久久大| 99999久久久久久亚洲| 成人a毛片久久免费播放| 久久午夜福利电影| 日韩人妻无码一区二区三区久久99| 色欲综合久久躁天天躁| 色婷婷综合久久久中文字幕| 久久久精品一区二区三区| 欧美久久亚洲精品| 99久久婷婷国产综合亚洲| 欧美激情精品久久久久久久九九九| AV无码久久久久不卡蜜桃| 国産精品久久久久久久| 亚洲AV日韩精品久久久久久久| 亚洲国产精品一区二区久久| 久久精品国产日本波多野结衣| 精品久久久无码中文字幕天天| 亚洲av日韩精品久久久久久a| 天天做夜夜做久久做狠狠| 久久综合九色综合久99| 香蕉久久av一区二区三区| 模特私拍国产精品久久| 国内精品免费久久影院| 久久精品这里热有精品| 国产一级做a爰片久久毛片| 久久精品一本到99热免费| 久久天天日天天操综合伊人av| 91久久精一区二区三区大全| 色8久久人人97超碰香蕉987| 久久亚洲日韩看片无码| 久久久无码精品亚洲日韩蜜臀浪潮| 久久精品成人欧美大片| 久久精品国产WWW456C0M| Xx性欧美肥妇精品久久久久久| 久久99精品国产一区二区三区| 精品少妇人妻av无码久久| 91精品国产91久久久久福利| 久久精品蜜芽亚洲国产AV| 久久水蜜桃亚洲av无码精品麻豆 | 久久精品无码午夜福利理论片|