需要子类处理大家一起学习 用户控件 Option ExplicitPrivate m_hWnd As Long Private m_Messages() As Long Private m_NumMessages As IntegerEvent WndProc(Msg As Long, wParam As Long, lParam As Long, Result As Long)'Hooks or unhooks the specified message Public Property Let Messages(nMessage As Long, bSubclass As Boolean) Dim i As Integer, j As Integer 'Look up existing entry for this message For i = 1 To m_NumMessages If m_Messages(i) = nMessage Then If bSubclass Then 'Message already subclassed Exit Property Else 'Remove this message m_NumMessages = m_NumMessages - 1 For j = i To m_NumMessages m_Messages(j) = m_Messages(j + 1) Next j ReDim Preserve m_Messages(m_NumMessages) Exit Property End If End If Next i 'Add message if not found If bSubclass Then 'Add new hook for this window m_NumMessages = m_NumMessages + 1 ReDim Preserve m_Messages(m_NumMessages) m_Messages(m_NumMessages) = nMessage End If End Property'Returns True if the specified message is currently hooked Public Property Get Messages(nMessage As Long) As Boolean Dim i As Integer 'Look up entry for this message For i = 1 To m_NumMessages If m_Messages(i) = nMessage Then Messages = True Exit Property End If Next i 'No entry for this message Messages = False End Property'Hook specified window Public Property Let hWnd(hWndNew As Long) 'Only if hWnd has changed If hWndNew <> m_hWnd Then 'Clear existing hook (if any) If m_hWnd <> 0 Then UnhookWindow m_hWnd End If m_hWnd = hWndNew 'Hook new window (if any) If m_hWnd <> 0 Then HookWindow m_hWnd, Me End If 'Note: No need to call PropertyChanged 'because this property is not saved End If End Property'Return currently-hooked window Public Property Get hWnd() As Long hWnd = m_hWnd End Property'Call default window procedure Public Function CallWndProc(Msg As Long, wParam As Long, lParam As Long) As Long If m_hWnd <> 0 Then CallWndProc = WinProc.CallWndProc(m_hWnd, Msg, wParam, lParam) End If End Function'Invoke WndProc event (called from BAS-module WndProc) Friend Function RaiseWndProc(Msg As Long, wParam As Long, lParam As Long) As Long Dim Result As Long RaiseEvent WndProc(Msg, wParam, lParam, Result) RaiseWndProc = Result End Function'Force design-time control to size of icon Private Sub UserControl_Resize() Size imgIcon.Width, imgIcon.Height End Sub'Unhook window if still hooked Private Sub UserControl_Terminate() If m_hWnd <> 0 Then UnhookWindow m_hWnd End If End Sub'Display about box Public Sub AboutBox() frmAbout.Show vbModal Set frmAbout = Nothing End Sub
用户控件中的模块 Option ExplicitPrivate Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long Private 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 Private Const GWL_WNDPROC = (-4) Public Const WM_NCDESTROY = &H82Private Type HOOKINFO hWnd As Long 'Subclassed window Ctrl As Subclass 'Control OldWndProc As Long 'Old window procedure End Type'Note: These variables will be common to all 'control instances within an application Private HookArray() As HOOKINFO Private NumHooks As Integer'Hooks the specified window/control Public Sub HookWindow(hWnd As Long, Ctrl As Subclass) Dim i As Integer If hWnd <> 0 Then 'Note: Since we use the window handle to identify 'the subclassing control, we cannot allow more than 'one control to subclass the same window. So before 'hooking a window, we remove any existing hooks to 'that same window. UnhookWindow hWnd 'Add new hook for this window NumHooks = NumHooks + 1 ReDim Preserve HookArray(NumHooks) HookArray(NumHooks).hWnd = hWnd Set HookArray(NumHooks).Ctrl = Ctrl HookArray(NumHooks).OldWndProc = GetWindowLong(hWnd, GWL_WNDPROC) 'Install custom window procedure for this window SetWindowLong hWnd, GWL_WNDPROC, AddressOf WndProc End If End Sub'Unhook the specified window 'Set nStartIndex to index of window (if known) Public Sub UnhookWindow(hWnd As Long) Dim i As Integer, j As Integer 'Reset window hook for this window For i = 1 To NumHooks If HookArray(i).hWnd = hWnd Then 'Sanity check Debug.Assert HookArray(i).OldWndProc <> 0 'Reset previous window procedure SetWindowLong hWnd, GWL_WNDPROC, HookArray(i).OldWndProc 'Remove hook information from array NumHooks = NumHooks - 1 For j = i To NumHooks HookArray(j) = HookArray(j + 1) Next j ReDim Preserve HookArray(NumHooks) Exit For End If Next i End Sub'Call the original window procedure Public Function CallWndProc(hWnd As Long, Msg As Long, wParam As Long, lParam As Long) As Long Dim i As Integer 'Find hook information for this window For i = 1 To NumHooks If HookArray(i).hWnd = hWnd Then CallWndProc = CallWindowProc(HookArray(i).OldWndProc, hWnd, Msg, wParam, lParam) Exit For End If Next i End Function'Replacement window procedure--Invokes control handler Private Function WndProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Dim i As Integer 'Find hook information for this window For i = 1 To NumHooks If HookArray(i).hWnd = hWnd Then 'Sanity check Debug.Assert HookArray(i).Ctrl.hWnd = hWnd 'Does control want this message? If HookArray(i).Ctrl.Messages(Msg) Then 'Suppress unhandled run-time errors On Error Resume Next 'Send message to control WndProc = HookArray(i).Ctrl.RaiseWndProc(Msg, wParam, lParam) Else 'Otherwise, just call default window handler WndProc = CallWindowProc(HookArray(i).OldWndProc, hWnd, Msg, wParam, lParam) End If 'Unhook this window if it is being destroyed If Msg = WM_NCDESTROY Then HookArray(i).Ctrl.hWnd = 0 End If Exit For End If Next i End Function还有一个frmabout.frm窗口
编译成Subclass控件调用,部件箱中添加即可 Option Explicit'This message is sent by windows when a menu command is highlighted Private Const WM_MENUSELECT = &H11F'System menu constants Private Const SC_RESTORE = &HF120& Private Const SC_MOVE = &HF010& Private Const SC_SIZE = &HF000& Private Const SC_MINIMIZE = &HF020& Private Const SC_MAXIMIZE = &HF030& Private Const SC_CLOSE = &HF060&'Program Subclass object on form load Private Sub Form_Load() Subclass1.hWnd = Form1.hWnd Subclass1.Messages(WM_MENUSELECT) = True End Sub'Terminate program Private Sub mnuFileExit_Click() Unload Me End Sub'Subclass callback Private Sub Subclass1_WndProc(Msg As Long, wParam As Long, lParam As Long, Result As Long) Dim Status As String If Msg = WM_MENUSELECT Then 'Only message for this demo Select Case wParam And &HFFFF& '0 = No menu 'The following values are defined by Visual Basic 'They always start from 1 and increment through each menu item '1 = File menu Case 2 Status = "Exit this program" '3 = Edit menu Case 4 Status = "Cut the selected items to the clipboard and delete them" Case 5 Status = "Copy the selected items to the clipboard" Case 6 Status = "Paste the contents of the clipboard to the current location" Case 7 Status = "Delete the selected items" 'The following prompts correspond to system menu commands Case SC_RESTORE Status = "Restore window to normal position and size" Case SC_MOVE Status = "Move the window using the keyboard" Case SC_SIZE Status = "Size the window using the keyboard" Case SC_MINIMIZE Status = "Minimize the window" Case SC_MAXIMIZE Status = "Maximize the window" Case SC_CLOSE Status = "Close this window and terminate this program" Case Else Status = "" End Select StatusBar1.Panels(1) = Status End If 'Unless you are overriding the default behavior, it's 'good practice to call the original window procedure Result = Subclass1.CallWndProc(Msg, wParam, lParam) End Sub
bar.Panels.Add 1, "MenuInfo", "当前菜单:" & " " & 菜单提示信息
如果有了,add 后依次增加
删除原有的用remove
用户控件
Option ExplicitPrivate m_hWnd As Long
Private m_Messages() As Long
Private m_NumMessages As IntegerEvent WndProc(Msg As Long, wParam As Long, lParam As Long, Result As Long)'Hooks or unhooks the specified message
Public Property Let Messages(nMessage As Long, bSubclass As Boolean)
Dim i As Integer, j As Integer
'Look up existing entry for this message
For i = 1 To m_NumMessages
If m_Messages(i) = nMessage Then
If bSubclass Then
'Message already subclassed
Exit Property
Else
'Remove this message
m_NumMessages = m_NumMessages - 1
For j = i To m_NumMessages
m_Messages(j) = m_Messages(j + 1)
Next j
ReDim Preserve m_Messages(m_NumMessages)
Exit Property
End If
End If
Next i
'Add message if not found
If bSubclass Then
'Add new hook for this window
m_NumMessages = m_NumMessages + 1
ReDim Preserve m_Messages(m_NumMessages)
m_Messages(m_NumMessages) = nMessage
End If
End Property'Returns True if the specified message is currently hooked
Public Property Get Messages(nMessage As Long) As Boolean
Dim i As Integer
'Look up entry for this message
For i = 1 To m_NumMessages
If m_Messages(i) = nMessage Then
Messages = True
Exit Property
End If
Next i
'No entry for this message
Messages = False
End Property'Hook specified window
Public Property Let hWnd(hWndNew As Long)
'Only if hWnd has changed
If hWndNew <> m_hWnd Then
'Clear existing hook (if any)
If m_hWnd <> 0 Then
UnhookWindow m_hWnd
End If
m_hWnd = hWndNew
'Hook new window (if any)
If m_hWnd <> 0 Then
HookWindow m_hWnd, Me
End If
'Note: No need to call PropertyChanged
'because this property is not saved
End If
End Property'Return currently-hooked window
Public Property Get hWnd() As Long
hWnd = m_hWnd
End Property'Call default window procedure
Public Function CallWndProc(Msg As Long, wParam As Long, lParam As Long) As Long
If m_hWnd <> 0 Then
CallWndProc = WinProc.CallWndProc(m_hWnd, Msg, wParam, lParam)
End If
End Function'Invoke WndProc event (called from BAS-module WndProc)
Friend Function RaiseWndProc(Msg As Long, wParam As Long, lParam As Long) As Long
Dim Result As Long
RaiseEvent WndProc(Msg, wParam, lParam, Result)
RaiseWndProc = Result
End Function'Force design-time control to size of icon
Private Sub UserControl_Resize()
Size imgIcon.Width, imgIcon.Height
End Sub'Unhook window if still hooked
Private Sub UserControl_Terminate()
If m_hWnd <> 0 Then
UnhookWindow m_hWnd
End If
End Sub'Display about box
Public Sub AboutBox()
frmAbout.Show vbModal
Set frmAbout = Nothing
End Sub
Option ExplicitPrivate Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private 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
Private Const GWL_WNDPROC = (-4)
Public Const WM_NCDESTROY = &H82Private Type HOOKINFO
hWnd As Long 'Subclassed window
Ctrl As Subclass 'Control
OldWndProc As Long 'Old window procedure
End Type'Note: These variables will be common to all
'control instances within an application
Private HookArray() As HOOKINFO
Private NumHooks As Integer'Hooks the specified window/control
Public Sub HookWindow(hWnd As Long, Ctrl As Subclass)
Dim i As Integer
If hWnd <> 0 Then
'Note: Since we use the window handle to identify
'the subclassing control, we cannot allow more than
'one control to subclass the same window. So before
'hooking a window, we remove any existing hooks to
'that same window.
UnhookWindow hWnd
'Add new hook for this window
NumHooks = NumHooks + 1
ReDim Preserve HookArray(NumHooks)
HookArray(NumHooks).hWnd = hWnd
Set HookArray(NumHooks).Ctrl = Ctrl
HookArray(NumHooks).OldWndProc = GetWindowLong(hWnd, GWL_WNDPROC)
'Install custom window procedure for this window
SetWindowLong hWnd, GWL_WNDPROC, AddressOf WndProc
End If
End Sub'Unhook the specified window
'Set nStartIndex to index of window (if known)
Public Sub UnhookWindow(hWnd As Long)
Dim i As Integer, j As Integer
'Reset window hook for this window
For i = 1 To NumHooks
If HookArray(i).hWnd = hWnd Then
'Sanity check
Debug.Assert HookArray(i).OldWndProc <> 0
'Reset previous window procedure
SetWindowLong hWnd, GWL_WNDPROC, HookArray(i).OldWndProc
'Remove hook information from array
NumHooks = NumHooks - 1
For j = i To NumHooks
HookArray(j) = HookArray(j + 1)
Next j
ReDim Preserve HookArray(NumHooks)
Exit For
End If
Next i
End Sub'Call the original window procedure
Public Function CallWndProc(hWnd As Long, Msg As Long, wParam As Long, lParam As Long) As Long
Dim i As Integer
'Find hook information for this window
For i = 1 To NumHooks
If HookArray(i).hWnd = hWnd Then
CallWndProc = CallWindowProc(HookArray(i).OldWndProc, hWnd, Msg, wParam, lParam)
Exit For
End If
Next i
End Function'Replacement window procedure--Invokes control handler
Private Function WndProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim i As Integer
'Find hook information for this window
For i = 1 To NumHooks
If HookArray(i).hWnd = hWnd Then
'Sanity check
Debug.Assert HookArray(i).Ctrl.hWnd = hWnd
'Does control want this message?
If HookArray(i).Ctrl.Messages(Msg) Then
'Suppress unhandled run-time errors
On Error Resume Next
'Send message to control
WndProc = HookArray(i).Ctrl.RaiseWndProc(Msg, wParam, lParam)
Else
'Otherwise, just call default window handler
WndProc = CallWindowProc(HookArray(i).OldWndProc, hWnd, Msg, wParam, lParam)
End If
'Unhook this window if it is being destroyed
If Msg = WM_NCDESTROY Then
HookArray(i).Ctrl.hWnd = 0
End If
Exit For
End If
Next i
End Function还有一个frmabout.frm窗口
Option Explicit'This message is sent by windows when a menu command is highlighted
Private Const WM_MENUSELECT = &H11F'System menu constants
Private Const SC_RESTORE = &HF120&
Private Const SC_MOVE = &HF010&
Private Const SC_SIZE = &HF000&
Private Const SC_MINIMIZE = &HF020&
Private Const SC_MAXIMIZE = &HF030&
Private Const SC_CLOSE = &HF060&'Program Subclass object on form load
Private Sub Form_Load()
Subclass1.hWnd = Form1.hWnd
Subclass1.Messages(WM_MENUSELECT) = True
End Sub'Terminate program
Private Sub mnuFileExit_Click()
Unload Me
End Sub'Subclass callback
Private Sub Subclass1_WndProc(Msg As Long, wParam As Long, lParam As Long, Result As Long)
Dim Status As String If Msg = WM_MENUSELECT Then 'Only message for this demo
Select Case wParam And &HFFFF&
'0 = No menu
'The following values are defined by Visual Basic
'They always start from 1 and increment through each menu item
'1 = File menu
Case 2
Status = "Exit this program"
'3 = Edit menu
Case 4
Status = "Cut the selected items to the clipboard and delete them"
Case 5
Status = "Copy the selected items to the clipboard"
Case 6
Status = "Paste the contents of the clipboard to the current location"
Case 7
Status = "Delete the selected items"
'The following prompts correspond to system menu commands
Case SC_RESTORE
Status = "Restore window to normal position and size"
Case SC_MOVE
Status = "Move the window using the keyboard"
Case SC_SIZE
Status = "Size the window using the keyboard"
Case SC_MINIMIZE
Status = "Minimize the window"
Case SC_MAXIMIZE
Status = "Maximize the window"
Case SC_CLOSE
Status = "Close this window and terminate this program"
Case Else
Status = ""
End Select
StatusBar1.Panels(1) = Status
End If
'Unless you are overriding the default behavior, it's
'good practice to call the original window procedure
Result = Subclass1.CallWndProc(Msg, wParam, lParam)
End Sub