📄 csubclass.cls
字号:
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "cSubclass"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
'****************************************************************************
'安全警戒线整理
'网 站:http://www.hackeroo.com/
'e-mail :hackeroo@hotmail.com
'OICQ :266370
'****************************************************************************
Option Explicit
'-Selfsub declarations----------------------------------------------------------------------------
Private Const MSG_ENTRIES As Long = 32 'Number of msg table entries
Private Const WNDPROC_OFF As Long = &H38 'Thunk offset to the WndProc execution address
Private Const GWL_WNDPROC As Long = -4 'SetWindowsLong WndProc index
Private Const IDX_SHUTDOWN As Long = 1 'Thunk data index of the shutdown flag
Private Const IDX_HWND As Long = 2 'Thunk data index of the subclassed hWnd
Private Const IDX_WNDPROC As Long = 9 'Thunk data index of the original WndProc
Private Const IDX_BTABLE As Long = 11 'Thunk data index of the Before table
Private Const IDX_ATABLE As Long = 12 'Thunk data index of the After table
Private Const IDX_PARM_USER As Long = 13 'Thunk data index of the User-defined callback parameter data index
Private z_ScMem As Long 'Thunk base address
Private z_Sc(64) As Long 'Thunk machine-code initialised here
Private z_Funk As Collection 'hWnd/thunk-address collection
Private Declare Function CallWindowProcA Lib "user32" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Private Declare Function GetModuleHandleA Lib "kernel32" (ByVal lpModuleName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function IsBadCodePtr Lib "kernel32" (ByVal lpfn As Long) As Long
Private Declare Function IsWindow Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function SetWindowLongA Lib "user32" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function VirtualAlloc Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFree Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Private Declare Sub RtlMoveMemory Lib "kernel32" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)
'-------------------------------------------------------------------------------------------------
Private Sub Class_Terminate()
Terminate 'Terminate all subclassing
End Sub
'-cSubclass code----------------------------------------------------------------------------------
Public Function Subclass(ByVal lng_hWnd As Long, _
ByVal oCallback As iSubclass, _
Optional ByVal lParamUser As Long = 0, _
Optional ByVal bIdeSafety As Boolean = True) As Boolean 'Subclass the specified window handle
'*************************************************************************************************
'* lng_hWnd - Handle of the window to subclass
'* oCallback - The owner object that'll receive the iSubclass implemented interface callbacks
'* lParamUser - Optional, user-defined callback parameter
'* bIdeSafety - Optional, enable/disable IDE safety measures. NB: you should really only disable IDE safety in a UserControl for design-time subclassing
'*************************************************************************************************
Const CODE_LEN As Long = 260 'Thunk length in bytes
Const MEM_LEN As Long = CODE_LEN + (8 * (MSG_ENTRIES + 1)) 'Bytes to allocate per thunk, data + code + msg tables
Const PAGE_RWX As Long = &H40& 'Allocate executable memory
Const MEM_COMMIT As Long = &H1000& 'Commit allocated memory
Const MEM_RELEASE As Long = &H8000& 'Release allocated memory flag
Const IDX_EBMODE As Long = 3 'Thunk data index of the EbMode function address
Const IDX_CWP As Long = 4 'Thunk data index of the CallWindowProc function address
Const IDX_SWL As Long = 5 'Thunk data index of the SetWindowsLong function address
Const IDX_FREE As Long = 6 'Thunk data index of the VirtualFree function address
Const IDX_BADPTR As Long = 7 'Thunk data index of the IsBadCodePtr function address
Const IDX_OWNER As Long = 8 'Thunk data index of the Owner object's vTable address
Const IDX_CALLBACK As Long = 10 'Thunk data index of the callback method address
Const IDX_EBX As Long = 16 'Thunk code patch index of the thunk data
Const SUB_NAME As String = "sc_Subclass" 'This routine's name
Dim nAddr As Long
Dim nID As Long
Dim nMyID As Long
If IsWindow(lng_hWnd) = 0 Then 'Ensure the window handle is valid
zError SUB_NAME, "Invalid window handle"
Exit Function
End If
nMyID = GetCurrentProcessId 'Get this process's ID
GetWindowThreadProcessId lng_hWnd, nID 'Get the process ID associated with the window handle
If nID <> nMyID Then 'Ensure that the window handle doesn't belong to another process
zError SUB_NAME, "Window handle belongs to another process"
Exit Function
End If
If z_Funk Is Nothing Then 'If this is the first time through, do the one-time initialization
Set z_Funk = New Collection 'Create the hWnd/thunk-address collection
z_Sc(14) = &HD231C031: z_Sc(15) = &HBBE58960: z_Sc(17) = &H4339F631: z_Sc(18) = &H4A21750C: z_Sc(19) = &HE82C7B8B: z_Sc(20) = &H74&: z_Sc(21) = &H75147539: z_Sc(22) = &H21E80F: z_Sc(23) = &HD2310000: z_Sc(24) = &HE8307B8B: z_Sc(25) = &H60&: z_Sc(26) = &H10C261: z_Sc(27) = &H830C53FF: z_Sc(28) = &HD77401F8: z_Sc(29) = &H2874C085: z_Sc(30) = &H2E8&: z_Sc(31) = &HFFE9EB00: z_Sc(32) = &H75FF3075: z_Sc(33) = &H2875FF2C: z_Sc(34) = &HFF2475FF: z_Sc(35) = &H3FF2473: z_Sc(36) = &H891053FF: z_Sc(37) = &HBFF1C45: z_Sc(38) = &H73396775: z_Sc(39) = &H58627404
z_Sc(40) = &H6A2473FF: z_Sc(41) = &H873FFFC: z_Sc(42) = &H891453FF: z_Sc(43) = &H7589285D: z_Sc(44) = &H3045C72C: z_Sc(45) = &H8000&: z_Sc(46) = &H8920458B: z_Sc(47) = &H4589145D: z_Sc(48) = &HC4836124: z_Sc(49) = &H1862FF04: z_Sc(50) = &H35E30F8B: z_Sc(51) = &HA78C985: z_Sc(52) = &H8B04C783: z_Sc(53) = &HAFF22845: z_Sc(54) = &H73FF2775: z_Sc(55) = &H1C53FF28: z_Sc(56) = &H438D1F75: z_Sc(57) = &H144D8D34: z_Sc(58) = &H1C458D50: z_Sc(59) = &HFF3075FF: z_Sc(60) = &H75FF2C75: z_Sc(61) = &H873FF28: z_Sc(62) = &HFF525150: z_Sc(63) = &H53FF2073: z_Sc(64) = &HC328&
z_Sc(IDX_CWP) = zFnAddr("user32", "CallWindowProcA") 'Store CallWindowProc function address in the thunk data
z_Sc(IDX_SWL) = zFnAddr("user32", "SetWindowLongA") 'Store the SetWindowLong function address in the thunk data
z_Sc(IDX_FREE) = zFnAddr("kernel32", "VirtualFree") 'Store the VirtualFree function address in the thunk data
z_Sc(IDX_BADPTR) = zFnAddr("kernel32", "IsBadCodePtr") 'Store the IsBadCodePtr function address in the thunk data
End If
RtlMoveMemory VarPtr(nAddr), ObjPtr(oCallback), 4 'Get the address of the owner's vTable
RtlMoveMemory VarPtr(nAddr), nAddr + &H1C, 4 'Get the address of the implemented interface
z_ScMem = VirtualAlloc(0, MEM_LEN, MEM_COMMIT, PAGE_RWX) 'Allocate executable memory
If z_ScMem <> 0 Then 'Ensure the allocation succeeded
On Error GoTo CatchDoubleSub 'Catch double subclassing
z_Funk.Add z_ScMem, "h" & lng_hWnd 'Add the hWnd/thunk-address to the collection
On Error GoTo 0
If bIdeSafety Then 'If the user wants IDE protection
z_Sc(IDX_EBMODE) = zFnAddr("vba6", "EbMode") 'Store the EbMode function address in the thunk data
End If
z_Sc(IDX_EBX) = z_ScMem 'Patch the thunk data address
z_Sc(IDX_HWND) = lng_hWnd 'Store the window handle in the thunk data
z_Sc(IDX_BTABLE) = z_ScMem + CODE_LEN 'Store the address of the before table in the thunk data
z_Sc(IDX_ATABLE) = z_ScMem + CODE_LEN + ((MSG_ENTRIES + 1) * 4) 'Store the address of the after table in the thunk data
z_Sc(IDX_OWNER) = ObjPtr(oCallback) 'Store owner's object address in the thunk data
z_Sc(IDX_CALLBACK) = nAddr 'Store the callback address in the thunk data
z_Sc(IDX_PARM_USER) = lParamUser 'Store the lParamUser callback parameter in the thunk data
nAddr = SetWindowLongA(lng_hWnd, GWL_WNDPROC, z_ScMem + WNDPROC_OFF) 'Set the new WndProc, return the address of the original WndProc
If nAddr = 0 Then 'Ensure the new WndProc was set correctly
zError SUB_NAME, "SetWindowLong failed, error #" & Err.LastDllError
GoTo ReleaseMemory
End If
z_Sc(IDX_WNDPROC) = nAddr 'Store the original WndProc address in the thunk data
RtlMoveMemory z_ScMem, VarPtr(z_Sc(0)), CODE_LEN 'Copy the thunk code/data to the allocated memory
Subclass = True 'Indicate success
Else
zError SUB_NAME, "VirtualAlloc failed, error: " & Err.LastDllError
End If
Exit Function 'Exit Subclass
CatchDoubleSub:
zError SUB_NAME, "Window handle is already subclassed"
ReleaseMemory:
VirtualFree z_ScMem, 0, MEM_RELEASE 'Subclass has failed after memory allocation, so release the memory
End Function
'Terminate all subclassing
Public Sub Terminate()
Dim i As Long
If Not (z_Funk Is Nothing) Then 'Ensure that subclassing has been started
With z_Funk
For i = .Count To 1 Step -1 'Loop through the collection of window handles in reverse order
z_ScMem = .Item(i) 'Get the thunk address
If IsBadCodePtr(z_ScMem) = 0 Then 'Ensure that the thunk hasn't already released its memory
UnSubclass zData(IDX_HWND) 'UnSubclass
End If
Next i 'Next member of the collection
End With
Set z_Funk = Nothing 'Destroy the hWnd/thunk-address collection
End If
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -