电竞比分网-中国电竞赛事及体育赛事平台

分享

VB api 中級

 ddlld345 2012-07-16

這篇文章之所以這么久才和大家見面,主要由于工作或學習時間太忙,一直想寫但又一直沒時間去寫,拖來拖去,!~前些天碰見二哥跟我說VBGOOD還有很多網(wǎng)友等著我的API教程,至此我感到挺慚愧的,先前的API教程寫得并不好,但是卻得到了大家的肯定與認可,甚感欣慰!在此謝謝大家的支持和鼓勵!

    好了,廢話不多說,接前次文章,此次"中級入門"主要是以消息和子類作講解,順帶我還會介紹一些其它的知識(純粹是個人的經(jīng)歷而言),Windows 是一個很豐富的平臺,它的包函當然不止這些.在 Windows 編程中,如果你的程序窗口(Window),那么就一定會和消息打交道!

    網(wǎng)友提問時間:"那啥叫消息?"

    舉個例子,當你的程序運行,假設(shè)這時你的程序帶有一個窗口,那么此時會先創(chuàng)建窗口,這時會激發(fā) WM_CREATE 消息,我上篇文章已經(jīng)說過,在 Windows 系統(tǒng),所以的消息常量都是以 WM_ 為開頭的,大家可以打開API 瀏覽器看看就知道了.再假設(shè)如果你用鼠標左鍵點擊所創(chuàng)建的窗口,此時會激發(fā) WM_LBUTTONDOWN 消息,在此我來幫大家分析下這些常量為什么會這么寫,首先, WM_ 我們不用去管它,因為后面 LBUTTONDOWN 才是關(guān)鍵,如果你EOK的話應該可以看得出來,咱們把它進行拆分以后就是這樣的:L Button Down ,現(xiàn)在應該明白了吧? L 代表的鼠標左鍵 Left , Button 自然是按鈕的意思, Down 表示鼠標按下的意思,既然這樣,那么當鼠標松開時,自然會激發(fā) WM_LBUTTONUP (Left Button Up)消息啦.當然,如果是右鍵點擊的話,那么自然同理,WM_RBUTTONDOWN,折分出來就是: Right Button Down.(俺曰:明白否:所有網(wǎng)友沉默中..)有人可能會問到,為什么要采用這種方式去做常量:因為微軟中所有的命名風格都是采用匈牙利命名法,大家可以到網(wǎng)上搜搜"關(guān)于匈牙利命名法".

    接上面,再再假設(shè)如果你的程序要退出了,這時你程序肯定會先關(guān)閉窗口,釋放相關(guān)的資源,然后退出,這時窗口會激發(fā) WM_CLOSE 消息,至于這些個E文我都不用解釋了吧?

    從上面這些來看,VB中我們窗口,控件等事件,幾乎都是以消息驅(qū)動來完成的,所以說,如果你想編寫好 Windows 窗口程序,對消息的理解不得忽視.在上一篇API 中級入門中,我給大家講解了如何使用 SendMessage API函數(shù)給程序發(fā)送消息,如果你在前篇文章不明白為什么那么做,那么我將會在下面為你解答.

    附注:前段時間有網(wǎng)友發(fā)伊妹兒跟我說不太明白 SendMessage 后面兩個參數(shù)為什么要根據(jù) Msg 定義,可能前段時間寫的不太詳細,這里我再仔細的說明下,還是以實例的方法來解答.

    怎么分別 SendMessage 后面兩個參數(shù)應該傳什么值.

    首先我們來看看 SendMessage 這個API

    Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

    很顯然,這是一個發(fā)送消息的API,從字面上的意思我們都可以看出,: Send = 發(fā)送的意思, Message = 自然是消息的意思了.我們說過 Windows 窗口程序大部分都是以消息進行處理的,窗口創(chuàng)建時系統(tǒng)就向程序發(fā)送 WM_CRATE 創(chuàng)建消息,窗口繪畫時系統(tǒng)就給程序發(fā)送 WM_PAINT 消息,窗口點擊時系統(tǒng)就給程序發(fā)送 WM_LBUTTONDOWN 消息,窗口關(guān)閉時系統(tǒng)就給程序發(fā)送 WM_CLOSE,消毀窗口時系統(tǒng)就會給程序發(fā)送 WM_DESTROY 消息,所以說,一個窗口程序是離不開消息的.當然,微軟為了能讓我們更好的控制窗口,給我們提供了很多窗口操作接口(這里指API),而 SendMessage 就是其中的一個,通過該函數(shù)可以向任何有窗口的程序發(fā)送任何消息,只要是所接收對象的窗口能處理的消息.

    現(xiàn)在再來說說后面兩個參數(shù)傳遞的具體定義,可以說它們完全根據(jù) wMsg 參數(shù)而定,說到這里可能網(wǎng)友有些糊涂了,怎么根據(jù) wMsg 參數(shù)而定?該怎么定義?~~大家別急哈,我會幫大家慢慢搞明白的.

    首先,還是以一個例子作以說明,假設(shè)這里所有的API和常量你已聲明:

    SendMessage Form1.hWnd, WM_CLOSE, 0, ByVal 0&

    看看上面一段代碼,它所執(zhí)行的功能為關(guān)閉我們的 Form1 窗口.

    第一個參數(shù)自然是句柄了,你要給哪個窗口發(fā)送消息,你就傳遞哪個窗口的句柄,這很容易明白是吧?

    第二個參數(shù)我前面講過,自然是給某個窗口發(fā)送的消息,這里是 WM_CLOSE 關(guān)閉消息,說白了就是向一個窗口發(fā)送關(guān)閉窗口消息.

    現(xiàn)在來看看第三個參數(shù),這里有些人可能搞不明白為什么就傳0?怎么不傳一,,三或四呢?如果你有這個疑問可以嘗試著把該參數(shù)換成100, 1000, 10000 都行,你看看會不會起什么作用?我們來看看 MSDN 的說法:

    wParam : This parameter is not used.

    翻譯過來就是:這個參數(shù)不被使用那為啥不被使用呢?很簡單,你給一個窗口發(fā)送關(guān)閉消息,當接收窗口收到該消息時就會作出退出操作,而這時的窗口關(guān)閉只需要接收到 WM_CLOSE 消息即可,所以這時你傳遞任何值它都會被忽略掉不處理,所以說,你就算換在 1,2,3,4,5,6 我想都不會發(fā)生任何作用.

    那這里可能就人要問了,那既然不用的話這個參數(shù)還有存在下去的必要嗎?我的回答是:當然有必要!后面我會給大家解開這個困惑的.

    再看看最后一個參數(shù),這里也有網(wǎng)友向我詢問過,問為什么要 ByVal 0& 這樣傳遞呢?

    首先我們看看當前API的最后聲明是怎么樣的:

    lParam As Any

    可以看出 lParam 參數(shù)是以 ByRef 方法聲明的,說白的這時所傳遞的值是一個地址,如果我們在參數(shù)前面加上 ByVal 的話VB就會默認向該參數(shù)以值的方式傳遞,說白了這時所傳遞的就是一個值.如果你還不明白什么是地址什么是值,可以到網(wǎng)上查查相關(guān)資料

    再看看后面為什么要加個 & ,這個符號在VB中如果以運算方式來看的話,它是一個鏈接符,用于鏈接兩個字符.如果以數(shù)據(jù)類型來看的話,它所代表的含意相當于 Long 變量.大家可以看看下面這個API聲明方式:

    Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    看出什么區(qū)別沒有?最后一個參數(shù)是以 ByVal lParam As Long 方式聲明的,所以如果使用以后就會是這樣的:

    SendMessage Form1.hWnd, WM_CLOSE, 0, 0

    現(xiàn)在你應該明白了?那么再看看這個參數(shù)為什么也要為0,我們還是先看看 MSDN 的說法:

    lParam : This parameter is not used.

    還是那句老話:該參數(shù)不被使用.所以這里我們默認就以 作填充了,因為這個參數(shù)不管你傳遞什么值所接收窗口都不會處理這個值的.所以嘛,忽略,忽略掉!~~

    現(xiàn)在,我們再說說這兩個參數(shù)存在下去的必要性,首先,我們看看原來的 WM_SETTEXT 消息(假設(shè)API都已聲明):

    SendMessage Form1.hWnd, WM_SETTEXT, 0, ByVal "is demo"

    前面兩個參數(shù)我都不說了,來看看第三個參數(shù)為何也是零下面是MSDN的說法:

    wParam : This parameter is not used. 

    還是那種話:該參數(shù)不被使用.所以說咱們在這個參數(shù)傳遞什么值,窗口消息都不會處理的,所以填充0.

    再看看最后一個參數(shù),下面是MSDN的說法:

    lParam : Pointer to a null-terminated string that is the window text. 

    翻譯過來可能就是該參數(shù)須傳遞一個以 NULL 為結(jié)尾的字符串指針.(E文不好,大大們覺得翻譯有誤還請多多包涵撒~~~).這里所指的 NULL 我們可以理解為VB中的 Chr(0).

    那么這樣看來,這個參數(shù)不再是零了,而是一個字符串指針.那么看看我們上面是怎么傳遞的:

    ByVal "is demo"

    注意:這里參數(shù)默認是以 lParam As Any 方式聲明的,不是以 ByVal lParam As Long.

    看看上面的,如果你聲明為 ByVal lParam As Long 整形那么應該怎么傳遞這個字符串呢(ps: 如果你會指針你當然也有辦法?可以用 StrPtr,超出本文范圍,這里不作詳解)?所以呢,咱們還是要保留該參數(shù)的默認聲明方式為 Any,那么我們可以傳遞任何值給這個參數(shù).

    現(xiàn)在來看看為什么前面還要加個 ByVal, ByVal 的意思已經(jīng)說過,是以值方式傳遞.這里之所有在傳遞字符串時需要用到 ByVal,那是因為VB中的字符串默認就是一個指針.注意了, VB中的字符串默認就是一個指針!!!而 Windows 操作系統(tǒng)中所有關(guān)于字符串的傳遞都是以指針方式進行的,不可能直接把幾個字符串按值傳遞.所以這里傳遞的其實是

     ByVal 字符串地址

     現(xiàn)在,應該很清楚明白了?如果你把 ByVal 去掉的話,那么傳遞就是:

     字符串地址的地址

     這又是指向內(nèi)存哪個地方的東西??明白了吧??不信你可以試試執(zhí)行后的結(jié)果是不是預想的那樣.

     現(xiàn)在又有人要向我發(fā)飆了,看了這么多示例?為什么 wParam 參數(shù)老為零?  :哎呀呀呀~~~,你小子,了不起啊~~

     再來看看另一個示例(假設(shè)你已聲明API):

Private Sub Command1_Click()

    SendMessage Me.hwnd, WM_KEYDOWN, 65, ByVal 0&

End Sub

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

    MsgBox Chr(KeyCode)

End Sub

    至于 Form_KeyDown 這里面的東西我就不說了,基本的東西了.只看 Command1_Click 中的代碼,首先 WM_KEYDOWN 是按鍵消息,你可以拆分看看 Key Down,是不是?該消息說白了就是按鍵按下時所激發(fā)的消息.

    最后一個參數(shù)我們不去看它,這里只作一個示例,有興趣的朋友自己查MSDN,先來看看MSDN對了WM_KEYDOWN 消息的第三個參數(shù)的說明:

    wParam : Specifies the virtual-key code of the nonsystem key. 

    翻譯過來就是:指定一個虛擬鍵碼,非系統(tǒng)鍵.這里所指的當然是那些 A, B, C,D等等按鍵編碼了.OK,這里不在為0,得傳遞點東西上面去了,這里我默認是傳遞的一個 65,大家可以用 Chr(65) 看看是什么鍵.然后把這個按鍵消息發(fā)送給我自己,當我收到以后,就會調(diào)用 MsgBox 得到傳遞過來的鍵值了.

Now,大家應該明白了吧? ^_^

,初識子類

    當你還不碰過子類的時候,你看到這個標題,定會問:"啥叫子類?".因為你知道我定會為你解答.(陰險哪~~~),因為鄙人文才不好,不知如何以最詳細最能理解的方式為你解答,所以到網(wǎng)上偷了一段,還請各位笑納:

    子類處理,是一種功能強大的技術(shù),它的作用是對發(fā)送到窗口的消息進行處理,我們完全可以用自己定制的一個窗口函數(shù)替代它,并保留指向默認窗口函數(shù)的指針,當一個消息到達窗口時,自制的窗口函數(shù)會攔截它并進行識別處理,對不能識別或不需進行特別處理的消息,就通過指向默認窗口函數(shù)的指針傳遞給默認的窗口函數(shù)進行處理,這樣便擴充了默認窗口函數(shù)的功能。這種用定制的窗口函數(shù)代替默認的窗口函數(shù),攔截并處理到達窗口的消息的技術(shù),我們就稱之為子類處理,定制的函數(shù)我們稱之為回調(diào)函數(shù)。

    上面解釋可能較復雜,但是我們現(xiàn)在也沒必要完全搞懂它,因為有了實例這一切就自然明白了.

    首先,在使用子類的時候,我們需要用到三個API函數(shù),它們分別是 GetWindowLong, SetWindowLong, CallWindowProc(沒嚇到你吧?),這三個函數(shù)不難,可以說是很簡單,有了它們,我們實現(xiàn)子類化成為可能,先來看看 GetWindowLong API函數(shù)的原型:

    Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long

    前面的我都不說了,只看參數(shù):

    ByVal hwnd As Long ,不用我說了吧?傳句柄的(:誰的句柄:當然是你要子類的那個窗口的句柄啦)

    ByVal nIndex As Long ,咳咳,這個嘛,需要傳遞一個常量,至于傳遞什么樣的常量,咱們用前段時間學習的API分析大法分析下不就OK了么?(~~聰明)

    第二個參數(shù)具體傳遞什么樣的參數(shù),根據(jù)這個API的名稱進行分析(:為什么啊:,API的常量一般都和API名字有很大關(guān)聯(lián)的,難道還分析你的名字不成么?),首先是  Get = G, Window = W, Long = L,合成以后就是 GWL_ ,OK ,打開API 瀏覽器,轉(zhuǎn)到常量,輸入 GWL_ 四個字符看看?有沒?沒有我馬上玩游戲去~~~~~~~~~~

    Public Const GWL_EXSTYLE = (-20)

    Public Const GWL_HINSTANCE = (-6)

    Public Const GWL_HWNDPARENT = (-8)

    Public Const GWL_ID = (-12)

    Public Const GWL_STYLE = (-16)

    Public Const GWL_USERDATA = (-21)

    Public Const GWL_WNDPROC = (-4)

    很多哈,但是實現(xiàn)子類的時候我們只需要一個,那就是 GWL_WNDPROC,至于其它的常量我建議大家看看MSDN,如果你看不懂的話可以參考下我以前發(fā)的關(guān)于一篇大量使用 GetWindowLong 和 SetWindowLong 兩個API函數(shù)的文章,地址是: http://www./viewthread.php?tid=46956&highlight= (建議學完該段API介紹再看)

    然后,我們再看看 SetWindowLong 原型:

    Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

    參數(shù):

    ByVal hwnd As Long ,句柄,還是句柄

    ByVal nIndex As Long ,好奇的你可能已經(jīng)發(fā)現(xiàn)了這個參數(shù)和 GetWindowLong 的第二個參數(shù)一樣的耶?那么恭喜你,是一樣的,包括傳遞的參數(shù)都是一樣的,如果你不服氣你去試下有沒有 SWL_ 開頭的常量.^_^

    ByVal dwNewLong As Long ,這個嘛~~, 參數(shù)的名稱已經(jīng)說明這是一個 New(新的)Long(長整形),當然這里的長整形是指一個地址 Address , you know ?

    前段時間我們知道了 Get 與 Set 的區(qū)別,那就是一個獲取,一個設(shè)置,當然這個也不例外.再來看看 CallWindowProc 這個API的原型:

    Public 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

    參數(shù):

    ByVal lpPrevWndFunc As Long ,這個,我先試著拆分看看意思, Prev 的意思可能是 Previous(原始的), Wnd 自然是 Window(窗口意思咯,最后一個 Func 應該是 Function(函數(shù)),看看前面的 lp ,如果你會匈牙利命名法的話可以很明顯看出來,該參數(shù)應該傳一個指針,當然VB默認不支持指針,所有的指針類型都是以Long代替(:貌似在32位系統(tǒng)中指針本來就是一個四字節(jié)的整形變量).那么這個參數(shù)的意思就是需要傳遞一個原始窗口指針,至于為什么,在這會可能說不清楚,咱們接著往下看.

    ByVal hWnd As Long , 啥也不說了,句柄唄.

    ByVal Msg As Long, 消息撒.至于傳什么,那就接著往下看

    ByVal wParam As Long , 還是那句老話,根據(jù) Msg 消息來定,前篇API教程中我們說過 SendMessage 后面二個參數(shù)的具體定義,本次這些也一樣

    ByVal lParam As Long , 同 wParam 解釋一樣

    這個API的用途就是把已處理的消息按 lpPrevWndFunc(原窗口消息地址返回給該地址

    好了,這段算是介紹完了,可能你還處于云山霧里,不過別擔心,我能讓你吃虧嗎?哈哈哈~~~~~

    ,回調(diào)函數(shù)

    在調(diào)用過程時指定的自定義函數(shù)被稱為回調(diào)函數(shù)?;卣{(diào)函數(shù)(通常簡稱為回調(diào))能夠?qū)^程提供的數(shù)據(jù)執(zhí)行指定的操作。回調(diào)函數(shù)的參數(shù)集必須具有規(guī)定的形式,這是由使用回調(diào)函數(shù)的 API 決定的。關(guān)于需要什么參數(shù),如何調(diào)用它們,請參閱 API 文檔。

    從上面一段文字描述中我們可以看出,回調(diào)函數(shù)說白了就是一段自定義的過程函數(shù),至于是什么樣的自定義函數(shù),那都是由API來決定的.那么有人會問:咱們這個實現(xiàn)子類化的回調(diào)函數(shù)是怎么定義的呢?問的好,當然,我還是那句老話,如果你有MSDN的話,建議看看.這里我們實現(xiàn)的子類的回調(diào)函數(shù)是下面這種樣子:

    Function WindowProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    怎么樣?(網(wǎng)友好復雜啊 答:不會吧?這都復雜?那我介紹一個容易記住的方法,把 SendMessage API中的幾個參數(shù)拿過來用就行了,是不是發(fā)現(xiàn)它們都是一樣的?然后把最后一個參數(shù)改成 Byval ???? Long 就行了),可見這個回調(diào)函數(shù)和 SendMessage 好像啊,幾乎差不多,不過要注意的是: SendMessage 最后一個參數(shù)是 lParam As Any,當然 SendMessage 的最后一個參數(shù)也可以改成 Byval lParam As Long,當然這里是根據(jù)你的需要去定的.

    OK,該了解了我們都了解的差不多了?現(xiàn)在該是我們實際操作的時候了,打開VB6,新建標準EXE,然后新建一個標準模塊.

    注意哦:VB進行子類是危險的,你要時刻記得保存你的VB文檔,否則你寫了半天的代碼會因為突然崩潰而沒保存,到那時就別怪我沒提醒你哦.哈哈~~~~~~

    提示:VB中進行子類時,默認只能在標準模塊中進行.

,實際操作的機會來了

    在 Form1 中的代碼:

Private Sub Form_Load()

    pWndProc = GetWindowLong(Me.hwnd, GWL_WNDPROC)

    SetWindowLong Me.hwnd, GWL_WNDPROC, AddressOf WindowProc

End Sub

Private Sub Form_Unload(Cancel As Integer)

    SetWindowLong Me.hwnd, GWL_WNDPROC, pWndProc

End Sub

    在 Module1 中的代碼:

Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public 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

Public Const GWL_WNDPROC = (-4)

Public pWndProc As Long

Public Function WindowProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    Debug.Print Hex$(Msg)

    WindowProc = CallWindowProc(pWndProc, hwnd, Msg, wParam, lParam)

End Function

    就這么一點代碼就能實現(xiàn)VB中的子類,可以說是比較簡單的,先來看看 Module1 中的代碼,至于API函數(shù)和常量的聲明我就不說了.

    首先我們聲明了一個 Public pWndProc As Long 變量,這里主要是把它當然指針來使用,這里我們再看看 Form1 中的代碼:

    pWndProc = GetWindowLong(Me.hwnd, GWL_WNDPROC)  ,可見窗口初始時先獲取當前窗口的消息地址,然后再使用 SetWindowLong Me.hwnd, GWL_WNDPROC, AddressOf WindowProc 把地址指向模塊中的 WindowProc 回調(diào)函數(shù),我們在分析 SetWindowLong, 前面兩個參數(shù)我就不說了,后面一個用到了 Addressof 函數(shù),這個函數(shù)的功能就是返回一個函數(shù)的地址.再看看 SetWindowLong 最后一個參數(shù), dwNewLong 肯定與一個新的參數(shù)有關(guān),而這里正是指向我們參數(shù)自定義的函數(shù)地址.

    我們不可能 SetWindowLong Me.hwnd, GWL_WNDPROC, WindowProc 這樣傳遞是吧?這樣直接把函數(shù)當做一個參數(shù)是不對的,而第三個參數(shù)正好是一新地址,所以我們通過 AddressOf WindowProc 該回調(diào)函數(shù)地址設(shè)置成當前窗口的消息地址,這樣我們就能通過 WindowProc 回調(diào)函數(shù)處理我們的消息了.

    接著看 WindowProc 回調(diào)函數(shù)里的代碼:

    Debug.Print Hex$(Msg) 這句意思是以十六進制的方式查看當前的消息情況.當然你可以運行該代碼,然后你將鼠標移動到Form1窗體上,這時在立即窗口就會顯示相應的消息數(shù)據(jù).

    WindowProc = CallWindowProc(pWndProc, hwnd, Msg, wParam, lParam) 這句的意思是把不需要處理的消息返回給系統(tǒng),前面我們分析過 CallWindowProc 函數(shù),后面四個參數(shù)我就不多說了,它們都是按照回調(diào)函數(shù)中的參數(shù)原樣返回就行了,主要看第一個參數(shù). CallWindowProc 的第一個參數(shù)上面分析時說明為一個地址,這個地址必須是原有的.通過 Form_Load 中的代碼我們就可以看出,先是通過 GetWindowLong 獲取Form1窗口的默認消息地址,然后再通過 SetWindowLong 把消息的流通地址轉(zhuǎn)到我們的回調(diào)函數(shù)中,然后通過回調(diào)函數(shù)處理,當不需要時需要再通過 CallWindowProc 返回給窗體默認的消息地址就行了.

    再看 Form_Unload 中的代碼,這是一個還原,主要是當我們退出時不在處理窗體默認的消息時應該返回給系統(tǒng),這里是需要注意的,否則程序可能會出現(xiàn)異常.

    說了這么多,可能有些人還不太怎么明白,不過不要緊,以后多多接觸這方面的例子就自然會明白了.好了,我來擬個運行順序,希望大家能夠明白它們的運行機制.

    首先,窗體加載時,我們使用

    pWndProc = GetWindowLong(Me.hwnd, GWL_WNDPROC) 

    保存當前窗體的默認消息地址然后再通過

    SetWindowLong Me.hwnd, GWL_WNDPROC, AddressOf WindowProc

    把當前窗體的默認消息地址設(shè)置到我們的回調(diào)函數(shù)地址處,然后我們就可以通過回調(diào)消息來控制當前窗體的消息了

    WindowProc = CallWindowProc(pWndProc, hwnd, Msg, wParam, lParam)

    當消息不用時,我們就要把這個消息返還給系統(tǒng).該參數(shù)只按原路照寫就行了.這里切記,如果少了這個函數(shù),程序接不到相應的消息會死掉的

    SetWindowLong Me.hwnd, GWL_WNDPROC, pWndProc

    最后不用時咱們就把地址返還給系統(tǒng).當然有時缺少這一句不會出現(xiàn)什么問題,但是以良好的SDK編程規(guī)則來說,最好把這句寫上.

    OK,這段似乎較復雜,不過不要緊,先苦后甜嘛,等你熟練使用子類的時候,你的Windows 編程功力就更上一層樓.

    休閑時間廣告您曾經(jīng)是否為無法處理窗口的消息而煩惱?您曾經(jīng)是否看到別人漂亮的自繪菜單而羨慕?您曾經(jīng)是否因為自己的窗口功能太單一而憂郁?現(xiàn)在好了,趕快學習VB子類吧,有了它,一切都會好起來的.趕快拿起電話定購吧電話:110

    上面廣告純屬虛構(gòu),如有雷同,算我倒霉.其實子類的好處不止這些,當然也有很多很多,下面我會舉一些例子來說明子類的好處.

    ,理論,實操一起抓

    1,讓你發(fā)消息關(guān)不掉我

    首先新建標準EXE,然后新建一個標準模塊:

    在 Form1 中加入以下代碼

Private Sub Form_Load()

    pWndProc = GetWindowLong(Me.hwnd, GWL_WNDPROC)

    SetWindowLong Me.hwnd, GWL_WNDPROC, AddressOf WindowProc

End Sub

Private Sub Form_Unload(Cancel As Integer)

    SetWindowLong Me.hwnd, GWL_WNDPROC, pWndProc

End Sub

    然后再在 Module1 中加入以下代碼:

Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public 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

Public Const GWL_WNDPROC = (-4)

Public Const WM_CLOSE = &H10

Public pWndProc As Long

Public Function WindowProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    If Msg = WM_CLOSE Then '處理 WM_CLOSE 窗口關(guān)閉消息

        WindowProc = 1

        Exit Function

    End If

    WindowProc = CallWindowProc(pWndProc, hwnd, Msg, wParam, lParam)

End Function

    其它代碼我就不說了,主要是看回調(diào)函數(shù)中的那幾段處理代碼首先通過 Msg 參數(shù)判斷當前激發(fā)的消息,先前說過,Windows 的所以消息都是以 WM_ 開頭的,大家可以找找看.如果是我們要攔截的消息時,那么用下面代碼

    WindowProc = 1

    Exit Function

    兩句搞定, WindowProc = 1 返回為 True,意思是該消息處理完成,然后 Exit Function 自然是退出該函數(shù),這句代碼的意思說白了就是不讓執(zhí)行下面的 CallWindowProc,如果你給CallWindowProc執(zhí)行了,消息也就自然返回給程序了,當程序接到WM_CLOSE,自然就會退出了.所以說白了,子類攔截消息就是不讓執(zhí)行 CallWindowProc.應該很簡單吧??

    好了,運行起來試試(別忘了保存)?如果你的VB崩潰了,說明你的代碼有誤,請仔細檢查下.找一個利用 SendMessage 發(fā)送WM_CLOSE消息關(guān)閉窗口程序試試,發(fā)現(xiàn)無法正常關(guān)閉你的窗口吧?(:別拿 Windows 任務(wù)管理器試,因為它不單單只是 SendMessage. 如果你實在拿不出什么工具來試,可以自己寫個 SendMessage me.hWnd, WM_CLOSE, 0, 0 試試)

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多