子類處理 當(dāng)你一最大限度利用了VB所給你的并且還想知道更多的東西,或只是想更多地了解你自己的窗口,你將會(huì)發(fā)現(xiàn)子類處理的優(yōu)勢(shì).
子類處理是指用一個(gè)新的窗口函數(shù)來(lái)取代當(dāng)前活動(dòng)窗口函數(shù).這個(gè)用戶自定義函數(shù)能處理任何需要的消息,并能調(diào)用原來(lái)的窗口函數(shù),它將在原來(lái)的窗口函數(shù)之前收到各種消息.但原來(lái)的那個(gè)窗口處理函數(shù)依然存在,并沒(méi)有消失.如果你不想處理某條消息,你應(yīng)該讓原來(lái)的窗口函數(shù)去處理它.
子類處理是通過(guò)調(diào)用SetWindowLong函數(shù)實(shí)現(xiàn)的,該函數(shù)將改變指定窗口的特殊屬性.下面是它的聲明:
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"(ByVal hwnd As Long, ByVal nIndex As Long,ByVal dwNewLong As Long) As Long
第一個(gè)參數(shù)代表要進(jìn)行子類處理的窗口,第二個(gè)參數(shù)應(yīng)該是GWL_WNDPROC(-4),第三個(gè)參數(shù)是新的窗口函數(shù)的地址.參見回調(diào)和窗口函數(shù)一節(jié).
此函數(shù)將在窗口取得焦點(diǎn),發(fā)生事件,或其他情況下(如其他進(jìn)程改變了系統(tǒng)的某些參數(shù))被隨時(shí)調(diào)用.
如果發(fā)生錯(cuò)誤SetWindowLong函數(shù)將返回0,否則將返回原來(lái)的窗口函數(shù)的地址.這個(gè)地址特別重要,你應(yīng)該把它保存在一個(gè)變量中或其他地方.當(dāng)你不處理某些消息時(shí)(實(shí)際上,你可能只處理不到1%的消息,其他的都將由原窗口函數(shù)處理),調(diào)用原來(lái)的窗口函數(shù)就需要該地址.
調(diào)用原窗口函數(shù)將由CallWindowProc來(lái)完成.這里是它的聲明:
Declare Function CallWindowProc Lib "user32" Alias"CallWindowProcA"(ByVal lpPrevWndFunc As Long,ByVal hWnd As Long,ByVal Msg As Long,ByVal wParam As Long, ByVal lParam As Long) As Long
第一個(gè)參數(shù)是原窗口函數(shù)的地址,其他的同你接收到的四個(gè)參數(shù)一樣.你可以改變其中的值來(lái)控制對(duì)消息的處理.例如,當(dāng)你收到了一條WM_MOUSEMOVE消息時(shí),你從lParam中得到鼠標(biāo)所在位置的坐標(biāo)并將其改成了其他的坐標(biāo).那么原窗口函數(shù)就會(huì)認(rèn)為鼠標(biāo)位于其他的位置從而做出一些有趣的事如顯示其他控件的Tooltip.
你指定的返回值也是有意義的,它依賴于發(fā)送的消息.
在結(jié)束你的程序時(shí)將控制權(quán)交回給原窗口函數(shù)是很重要的,通常在Form_Unload中完成如下:
Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProcAddress)
如果你在VB中啟動(dòng)程序時(shí)忘掉了這一行,結(jié)果將是VB崩潰并會(huì)丟失尚未保存的數(shù)據(jù).千萬(wàn)要小心.
這里是子類處理的一個(gè)簡(jiǎn)單示例:
Dim oldWndProc As Long
Private Sub Form_Load()
oldWndProc = SetWindowLong(Me.Hwnd, GWL_WNDPROC, AddressOf MyWndProc)
End Sub
Private Sub Form_Unload()
Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProc)
End Sub
Function MyWndProc(ByVal Hwnd As Long,ByVal wMsg as Long,ByVal wParam As Long,ByVal lParam As Long)
Debug.Print wMsg & " " & wParam & " " & lParam
Ret& = CallWindowProc(oldWndProc, Hwnd, wMsg, wParam, lParam)
End Function
處理參數(shù) 有時(shí)函數(shù)并不以你所需的方式返回信息.一個(gè)典型的例子是將兩個(gè)代表鼠標(biāo)位置的整形(2 byte)數(shù)合并為一個(gè)4 Byte的數(shù).還有一個(gè)例子是判斷一個(gè)數(shù)的某位是否為1.你還可能得到一個(gè)代表一個(gè)結(jié)構(gòu)地址的Long型數(shù).
合并和分離一個(gè)數(shù)并不需要過(guò)多的描述.你能在下面的網(wǎng)站(www.geocities.com/SiliconValley/Lab/1632/)上找到APIMacro.bas,它包含了你需要的多種函數(shù).
可以用一下方法檢查一個(gè)數(shù)的第N位是否為1:
If Value and (2^N) then ...
置1
Value = Value Or 2^N
置0
Value = Value And Not 2^N
如果你想設(shè)定或取得預(yù)先知道的某位的信息,用1024代替2^10要快的多.因?yàn)檫@樣VB無(wú)需自己進(jìn)行計(jì)算(VB憎恨 "^" ?).
如果你接收到一個(gè)類型的指針,你要做的工作將稍多一點(diǎn).你可以使用CopyMem函數(shù)來(lái)取得信息.下面是它的聲明:
Declare Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal ByteLen As Long)
如果你接收到了一個(gè)指向RECT 類型的指針并存在Long型變量Addr 中,可以這樣處理:
Dim Info As Rect
Call CopyMem(Info, ByVal Addr, len(Info))
注意ByVal關(guān)鍵字.現(xiàn)在,如果你想把信息寫回,使用:
Call CopyMem(ByVal Addr, Info, Len(Info))
結(jié)束語(yǔ) 我希望這份教程能幫助你理解如何控制API函數(shù)的威力和如何正確使用它們.但是要小心!就像火,如果你讓它失去控制,你就會(huì)玩蛋.當(dāng)然,不要忘了VB是進(jìn)行簡(jiǎn)單.安全程序設(shè)計(jì)的語(yǔ)言,而API函數(shù)則正好相反.如果你想得到更多的控制功能,最好轉(zhuǎn)移到VC++ 或者Delphi.(這一點(diǎn),洞主不敢茍同).
祝你在API探險(xiǎn)中好運(yùn)!
(
http://www.cncfan.com提示:作者未知,感謝作者寫出這么好的文檔,特發(fā)布與大家共享,一起學(xué)習(xí)交流,有知道作者的朋友請(qǐng)給出作者地址,發(fā)布到評(píng)論中,核實(shí)后我們后把來(lái)源和作者姓名重新編排到文章中。)