Visual Basic/子類化
外觀
當您想要新增 Visual Basic 不直接支援的功能時,子類化可能很有用。為了解釋它是如何工作的,我們必須先了解一些背景理論。
Windows 中的所有視窗(例如窗體、按鈕、列表框等)都具有一個函式,作業系統或其他程式可以呼叫該函式來與程式通訊。例如,Windows 可以傳送有關事件的訊息,例如滑鼠指標移過視窗、視窗處於焦點時按下某個鍵,以及更多情況。程式也可以傳送請求視窗資訊的訊息;例如,EM_GETLINECOUNT 訊息要求文字框傳送回它儲存的文字行數。您也可以定義自己的函式。
要呼叫這些特殊函式,您可以使用PostMessage、SendMessage 或CallWindowProc(如果您知道函式的地址,則僅使用最後一個)。
通常,這樣的過程看起來像這樣
Public Function WindowProc(ByVal hwnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
' Your code here
Select Case uMsg
Case 0
' React to message 0
Case 1
' React to message 1
End Select
WindowProc = 0 ' Return a value to the caller
End Function
在此函式中,hwnd 是呼叫方嘗試聯絡的視窗的控制代碼;uMsg 是訊息識別符號,它說明呼叫是關於什麼的;wParam 和lParam 用於呼叫方和視窗之間商定的任何用途。控制代碼 hwnd 不是地址,而是由 Windows 用於查詢地址。
例如,如果我們要設定窗體標題欄中顯示的文字,可以使用以下程式碼
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Integer, _
ByVal lParam As Any) As Long
Private Const WM_SETTEXT = &HC
Private Sub Form_Load()
SendMessage Me.hwnd, WM_SETTEXT, 0&, "This is a test"
End Sub
The receiver will get this message via its window function, which will look something like this:
Public Function WindowProc(ByVal hwnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
' hwnd is now equal to Me.hwnd,
' uMsg is WM_SETTEXT,
' wParam is 0
' lParam is the address of the text: "This is a test"
' It doesn't actually look like this of course, but this gives
' a good enough impression of what happens under the surface
Select Case uMsg
Case WM_SETTEXT
Me.Caption = lParam
'Case ...
'... many more here
End Select
End Function
'one thing i have to say is if you press alt+f11 in vbe subclass not remove when you use unsubclassform and convey to vbe so this function have to be updated
子類化的意義何在?
使用此技術,我們可以完全用自己的視窗函式替換程式的視窗函式。然後,我們可以以 Visual Basic 不允許的方式響應訊息,我們可以選擇將訊息進一步傳送到原始視窗函式,也可以不傳送,我們可以根據自己的喜好以任何方式修改它們。
要指定要使用我們的視窗函式,我們使用API 呼叫SetWindowLong。研究以下示例,並將其放在一個基本模組中
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hwnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
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
Declare Function SetClipboardViewer Lib "user32" _
(ByVal hwnd As Long) As Long
Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Integer, _
ByVal lParam As Any) As Long
Public Const WM_SETTEXT = &HC
Public Const GWL_WNDPROC = (-4)
Private PrevProc As Long ' The address of the original window function
Public Sub SubclassForm(F As Form)
' AddressOf WindowProc = finds the address of a function
PrevProc = SetWindowLong(F.hwnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub
Public Sub UnSubclassForm(F As Form)
' It is _very_ important that we restore the original window function,
' because VB will crash if we don't.
SetWindowLong F.hwnd, GWL_WNDPROC, PrevProc
End Sub
Public Function WindowProc(ByVal hwnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Dim sTemp As String
If uMsg = WM_SETTEXT Then
' Don't let the text get through, replace it with our own. Also, because all
' strings in VB are of the format UTF-16 (Unicode) and the receiving method
' expects a zero-terminated ASCII-string, it is necessary to convert it before
' passing it further down the chain.
sTemp = StrConv("Subclassing" & Chr(0), vbFromUnicode)
lParam = StrPtr(sTemp) ' get the address of our text
End If
' Call the original function
WindowProc = CallWindowProc(PrevProc, hwnd, uMsg, wParam, lParam)
End Function
新增一個帶有一個按鈕cmdTest 的窗體,並新增以下程式碼
Private Sub cmdTest_Click()
SendMessage Me.hwnd, WM_SETTEXT, 0&, "This is a test"
End Sub
Private Sub Form_Load()
' Start subclassing
SubclassForm Me
End Sub
Private Sub Form_Unload(Cancel As Integer)
' WARNING: If you stop the project (for example with the stop button) without calling this,
' your program, as well as the VB IDE, will most likely crash.
UnSubclassForm Me
End Sub
當您單擊cmdTest 按鈕時,您會看到顯示的文字不是“這是一個測試”,而是“子類化”。
| 上一個: Windows_API | 目錄 | 下一個: External_Processes |