home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 5_2007-2008.ISO / data / Zips / Transparen2044891262007.psc / MGSubclass.cls < prev    next >
Text File  |  2007-01-26  |  14KB  |  388 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "MGSubclass"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = False
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15.  
  16.  
  17. Private Const GWL_WNDPROC    As Long = (-4)
  18. Private Const WM_DESTROY     As Long = &H2
  19.  
  20. Public Enum EErrorWindowProc
  21.     eeBaseWindowProc = 13080
  22.     eeCantSubclass
  23.     eeAlreadyAttached
  24.     eeInvalidWindow
  25.     eeNoExternalWindow
  26. End Enum
  27.  
  28. Private Declare Function EbMode_vb5 Lib "vba5" Alias "EbMode" () As Long
  29. Private Declare Function EbMode_vb6 Lib "vba6" Alias "EbMode" () As Long
  30. Private Declare Function IsWindow Lib "user32" (ByVal hWnd As Long) As Long
  31. Private Declare Function GetProp Lib "user32" Alias "GetPropA" (ByVal hWnd As Long, ByVal lpString As String) As Long
  32. Private Declare Function SetProp Lib "user32" Alias "SetPropA" (ByVal hWnd As Long, ByVal lpString As String, ByVal hData As Long) As Long
  33. Private Declare Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hWnd As Long, ByVal lpString As String) As Long
  34. Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
  35. Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
  36. 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
  37. Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
  38. Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
  39. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
  40. Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
  41. Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
  42. Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
  43. Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
  44.  
  45. Private m_lAdd&, m_lClassAddr&, m_lCurrMsg&
  46.  
  47. Private Property Get p_MessageClass&(ByVal lHwnd&, ByVal lMsg&, ByVal lIndex&)
  48.  
  49.     Dim sName$
  50.  
  51.     sName = CStr(lHwnd) + Chr$(35) + CStr(lMsg) + Chr$(35) + CStr(lIndex)
  52.     p_MessageClass = GetProp(lHwnd, sName)
  53.  
  54. End Property
  55.  
  56. Private Property Let p_MessageClass(ByVal lHwnd&, ByVal lMsg&, ByVal lIndex&, ByVal lClass&)
  57.  
  58.     Dim sName$
  59.  
  60.     sName = CStr(lHwnd) + Chr$(35) + CStr(lMsg) + Chr$(35) + CStr(lIndex)
  61.     m_lAdd = SetProp(lHwnd, sName, lClass)
  62.     If lClass = 0 Then Call RemoveProp(lHwnd, sName)
  63.  
  64. End Property
  65.  
  66. Private Property Get p_MessageCount&(ByVal lHwnd&)
  67.  
  68.     Dim sName$
  69.  
  70.     sName = Chr$(67) + CStr(lHwnd)
  71.     p_MessageCount = GetProp(lHwnd, sName)
  72.  
  73. End Property
  74.  
  75. Private Property Let p_MessageCount(ByVal lHwnd&, ByVal lCount&)
  76.  
  77.     Dim sName$
  78.  
  79.     m_lAdd = 1
  80.     sName = Chr$(67) + CStr(lHwnd)
  81.     m_lAdd = SetProp(lHwnd, sName, lCount)
  82.     If lCount = 0 Then Call RemoveProp(lHwnd, sName)
  83.  
  84. End Property
  85.  
  86. Private Property Get p_OldWindowProc&(ByVal lHwnd&)
  87.  
  88.     Dim sName$
  89.  
  90.     sName = lHwnd
  91.     p_OldWindowProc = GetProp(lHwnd, sName)
  92.  
  93. End Property
  94.  
  95. Private Property Let p_OldWindowProc(ByVal lHwnd&, ByVal lPtr&)
  96.  
  97.     Dim sName$
  98.  
  99.     m_lAdd = 1
  100.     sName = lHwnd
  101.     m_lAdd = SetProp(lHwnd, sName, lPtr)
  102.     If lPtr = 0 Then Call RemoveProp(lHwnd, sName)
  103.  
  104. End Property
  105.  
  106. Private Property Get p_MessageClassCount&(ByVal lHwnd&, ByVal lMsg&)
  107.  
  108.     Dim sName$
  109.  
  110.     sName = CStr(lHwnd) + Chr$(35) + CStr(lMsg) + Chr$(67)
  111.     p_MessageClassCount = GetProp(lHwnd, sName)
  112.  
  113. End Property
  114.  
  115. Private Property Let p_MessageClassCount(ByVal lHwnd&, ByVal lMsg&, ByVal lCount&)
  116.  
  117.     Dim sName$
  118.  
  119.     sName = CStr(lHwnd) + Chr$(35) + CStr(lMsg) + Chr$(67)
  120.     m_lAdd = SetProp(lHwnd, sName, lCount)
  121.     If lCount = 0 Then Call RemoveProp(lHwnd, sName)
  122.  
  123. End Property
  124.  
  125. Public Property Get p_CurrentMessage&()
  126.  
  127.     Call CopyMemory(p_CurrentMessage, ByVal m_lCurrMsg, 4)
  128.  
  129. End Property
  130.  
  131. Private Sub Class_Initialize()
  132.  
  133.     Dim i&, nLen&, sHex$, sCode$, lIDEMode&, nOffset&
  134.  
  135.     Const CODE_STR$ = "5589E581C4E0FFFFFF5752515331C08945F88945" & _
  136.     "E068240000006800000000E8xxxxx08x89C78945EC8B4508E8DE010000897DE8FF7" & _
  137.     "5ECFF7508E8xxxxx02x8945FC09C00F8417010000EB1EE8xxxxx01x3D020000000F" & _
  138.     "842501000085C0750AE826010000E9F70000008B7DE8B2238817478B450CE895010" & _
  139.     "000B243881747B2008817897DE8FF75ECFF7508E8xxxxx03x8945F03D000000000F" & _
  140.     "8E570100008B7DE84FB223881747BB0100000089D8E85B010000FF75ECFF7508E8x" & _
  141.     "xxxx04x8945F409C07439B8xxxxx0Dx8B4D0C890868040000006800000000E8xxxx" & _
  142.     "x0Fx8945E0508B45F4508B00FF501C8B45E08B00A8027405E8DC000000E84101000" & _
  143.     "0433B5DF07F308B7DE889D8E800010000FF75ECFF7508E8xxxxx05x8945F409C074" & _
  144.     "DEB8xxxxx0Ex8B4D0C8908E810010000E9CAFFFFFF8B45F8A9FFFFFFFF75228B45F" & _
  145.     "409C0741B8B45E0508B45F4508B00FF501C8B45E08B00A8017405E875000000FF75" & _
  146.     "ECE8xxxxx09x8B45E009C0740650E8xxxxx10x5B595A5F8B45E4C9C21000E850000" & _
  147.     "000E9D6FFFFFFFF75FC68FCFFFFFFFF7508E8xxxxx07x8B7DECB2438817478B4508" & _
  148.     "E864000000FF75ECFF7508E8xxxxx06x3D000000007CA48B55EC4252FF7508E8xxx" & _
  149.     "xx0AxFF75ECFF7508E8xxxxx0BxC3FF7514FF7510FF750CFF7508FF75FCE8xxxxx0" & _
  150.     "Cx8945E4B8FFFFFFFF8945F8C38B450C3D020000007505E886FFFFFFE8CCFFFFFFE" & _
  151.     "952FFFFFF5331C931D23D000000007D07B22D881747F7D8BB0A00000031D2F7F352" & _
  152.     "4109C075F15A80C230881747E2F7B20088175BC38B45E050FF7514FF7510FF750CF" & _
  153.     "F75088B45F4508B00FF50248B45E08B008945E4C3"
  154.     sHex = CODE_STR
  155.     nLen = LenB(sHex)
  156.     For i = 1 To nLen Step 2
  157.         sCode = sCode & ChrB$(Val("&H" & Mid$(sHex, i, 2)))
  158.     Next i
  159.     nLen = LenB(sCode)
  160.     m_lClassAddr = GlobalAlloc(0, nLen)
  161.     m_lCurrMsg = GlobalAlloc(0, 4)
  162.     Call CopyMemory(ByVal m_lClassAddr, ByVal StrPtr(sCode), nLen)
  163.     i = Function_Address("vba6", "EbMode")
  164.     If i = 0 Then
  165.         i = Function_Address("vba5", "EbMode")
  166.         If Not i = 0 Then lIDEMode = EbMode_vb5()
  167.     Else
  168.         lIDEMode = EbMode_vb6()
  169.     End If
  170.     Debug.Assert i
  171.     If Not lIDEMode = 0 Then
  172.         nOffset = InStr(1, CODE_STR, "EB1E") - 1
  173.         nOffset = nOffset \ 2
  174.         Call CopyMemory(ByVal m_lClassAddr + nOffset, &H9090, 2)
  175.         Call Patch_Address(77, i)
  176.     End If
  177.     Call Patch_Address(59, Function_Address("user32", "GetPropA"))
  178.     Call Patch_Address(141, Function_Address("user32", "GetPropA"))
  179.     Call Patch_Address(187, Function_Address("user32", "GetPropA"))
  180.     Call Patch_Address(278, Function_Address("user32", "GetPropA"))
  181.     Call Patch_Address(434, Function_Address("user32", "GetPropA"))
  182.     Call Patch_Address(407, Function_Address("user32", "SetWindowLongA"))
  183.     Call Patch_Address(32, Function_Address("oleaut32", "SysAllocStringByteLen"))
  184.     Call Patch_Address(357, Function_Address("oleaut32", "SysFreeString"))
  185.     Call Patch_Address(454, Function_Address("user32", "RemovePropA"))
  186.     Call Patch_Address(465, Function_Address("user32", "RemovePropA"))
  187.     Call Patch_Address(486, Function_Address("user32", "CallWindowProcA"))
  188.     Call Patch_Address(219, Function_Address("kernel32", "GlobalAlloc"))
  189.     Call Patch_Address(370, Function_Address("kernel32", "GlobalFree"))
  190.     Call Patch_Value(199, m_lCurrMsg)
  191.     Call Patch_Value(290, m_lCurrMsg)
  192.  
  193. End Sub
  194.  
  195. Public Sub Attach_Message(ByRef ISC As MISubclass, ByVal lHwnd&, ByVal lMsg&)
  196.  
  197.     Dim lProcOld&, lMsgCount&, lMsgClassCount&, lMsgClass&
  198.  
  199.     If IsWindow(lHwnd) = False Then
  200.         Call Error_Raise(eeInvalidWindow)
  201.     Else
  202.         If Not Window_Local(lHwnd) Then
  203.             Call Error_Raise(eeNoExternalWindow)
  204.             Exit Sub
  205.         End If
  206.         lMsgClassCount = p_MessageClassCount(lHwnd, lMsg)
  207.         If lMsgClassCount > 0 Then
  208.             For lMsgClass = 1 To lMsgClassCount
  209.                 If (p_MessageClass(lHwnd, lMsg, lMsgClass) = ObjPtr(ISC)) Then
  210.                     Call Error_Raise(eeAlreadyAttached)
  211.                     Exit Sub
  212.                 End If
  213.             Next lMsgClass
  214.         End If
  215.         p_MessageClassCount(lHwnd, lMsg) = p_MessageClassCount(lHwnd, lMsg) + 1
  216.         If m_lAdd = 0 Then
  217.             Call Error_Raise(5)
  218.             Exit Sub
  219.         End If
  220.         p_MessageClass(lHwnd, lMsg, p_MessageClassCount(lHwnd, lMsg)) = ObjPtr(ISC)
  221.         If m_lAdd = 0 Then
  222.             p_MessageClassCount(lHwnd, lMsg) = p_MessageClassCount(lHwnd, lMsg) - 1
  223.             Call Error_Raise(5)
  224.             Exit Sub
  225.         End If
  226.         lMsgCount = p_MessageCount(lHwnd)
  227.         If lMsgCount = 0 Then
  228.             lProcOld = SetWindowLong(lHwnd, GWL_WNDPROC, m_lClassAddr)
  229.             If lProcOld = 0 Then
  230.                 p_MessageClass(lHwnd, lMsg, p_MessageClassCount(lHwnd, lMsg)) = 0
  231.                 p_MessageClassCount(lHwnd, lMsg) = p_MessageClassCount(lHwnd, lMsg) - 1
  232.                 Call Error_Raise(eeCantSubclass)
  233.                 Exit Sub
  234.             End If
  235.             p_OldWindowProc(lHwnd) = lProcOld
  236.             If m_lAdd = 0 Then
  237.                 Call SetWindowLong(lHwnd, GWL_WNDPROC, lProcOld)
  238.                 p_MessageClass(lHwnd, lMsg, p_MessageClassCount(lHwnd, lMsg)) = 0
  239.                 p_MessageClassCount(lHwnd, lMsg) = p_MessageClassCount(lHwnd, lMsg) - 1
  240.                 Call Error_Raise(5)
  241.                 Exit Sub
  242.             End If
  243.         End If
  244.         p_MessageCount(lHwnd) = p_MessageCount(lHwnd) + 1
  245.         If m_lAdd = 0 Then
  246.             p_MessageClass(lHwnd, lMsg, p_MessageClassCount(lHwnd, lMsg)) = 0
  247.             p_MessageClassCount(lHwnd, lMsg) = p_MessageClassCount(lHwnd, lMsg) - 1
  248.             If p_MessageCount(lHwnd) = 0 Then
  249.                 lProcOld = p_OldWindowProc(lHwnd)
  250.                 If Not (lProcOld = 0) Then
  251.                     Call SetWindowLong(lHwnd, GWL_WNDPROC, lProcOld)
  252.                     p_OldWindowProc(lHwnd) = 0
  253.                 End If
  254.             End If
  255.             Call Error_Raise(5)
  256.         End If
  257.     End If
  258.  
  259. End Sub
  260.  
  261. Public Sub Detach_Message(ByRef ISC As MISubclass, ByVal lHwnd&, ByVal lMsg&)
  262.  
  263.     Dim lMsgClassCount&, lMsgClass&, lMsgClassIndex&, lMsgCount&, lProcOld&
  264.  
  265.     If IsWindow(lHwnd) = False Then Exit Sub
  266.     If Not Window_Local(lHwnd) Then Exit Sub
  267.     lMsgClassCount = p_MessageClassCount(lHwnd, lMsg)
  268.     If lMsgClassCount = 0 Then Exit Sub
  269.     lMsgClassIndex = 0
  270.     For lMsgClass = 1 To lMsgClassCount
  271.         If (p_MessageClass(lHwnd, lMsg, lMsgClass) = ObjPtr(ISC)) Then
  272.             lMsgClassIndex = lMsgClass
  273.             Exit For
  274.         End If
  275.     Next lMsgClass
  276.     If lMsgClassIndex = 0 Then Exit Sub
  277.     For lMsgClass = lMsgClassIndex To lMsgClassCount - 1
  278.         p_MessageClass(lHwnd, lMsg, lMsgClass) = p_MessageClass(lHwnd, lMsg, lMsgClass + 1)
  279.     Next lMsgClass
  280.     p_MessageClass(lHwnd, lMsg, lMsgClassCount) = 0
  281.     p_MessageClassCount(lHwnd, lMsg) = p_MessageClassCount(lHwnd, lMsg) - 1
  282.     lMsgCount = p_MessageCount(lHwnd)
  283.     If lMsgCount = 1 Then
  284.         lProcOld = p_OldWindowProc(lHwnd)
  285.         If Not (lProcOld = 0) Then Call SetWindowLong(lHwnd, GWL_WNDPROC, lProcOld)
  286.         p_OldWindowProc(lHwnd) = 0
  287.     End If
  288.     p_MessageCount(lHwnd) = p_MessageCount(lHwnd) - 1
  289.  
  290. End Sub
  291.  
  292. Public Function Window_Local(ByVal lHwnd&) As Boolean
  293.  
  294.     Dim idWnd&
  295.  
  296.     Call GetWindowThreadProcessId(lHwnd, idWnd)
  297.     Window_Local = (idWnd = GetCurrentProcessId())
  298.  
  299. End Function
  300.  
  301. Private Function Function_Address&(ByVal sDLL$, ByVal sProc$)
  302.  
  303.     Function_Address = GetProcAddress(GetModuleHandle(sDLL), sProc)
  304.     Debug.Assert Function_Address
  305.  
  306. End Function
  307.  
  308. Private Sub Patch_Address(ByVal lOffset&, ByVal lTarget&)
  309.  
  310.     Call CopyMemory(ByVal (m_lClassAddr + lOffset), lTarget - m_lClassAddr - lOffset - 4, 4)
  311.  
  312. End Sub
  313.  
  314. Private Sub Patch_Value(ByVal lOffset&, ByVal lValue&)
  315.  
  316.     Call CopyMemory(ByVal (m_lClassAddr + lOffset), lValue, 4)
  317.  
  318. End Sub
  319.  
  320. Public Function Get_OldProc&(ByVal lHwnd&, ByVal lMsg&, ByVal wParam&, ByVal lParam&)
  321.  
  322.     Dim lProcOld&
  323.  
  324.     lProcOld = p_OldWindowProc(lHwnd)
  325.     If lProcOld = 0 Then Exit Function
  326.     Get_OldProc = CallWindowProc(lProcOld, lHwnd, lMsg, wParam, lParam)
  327.  
  328.  
  329. End Function
  330.  
  331. Private Function Ide_True(bValue As Boolean) As Boolean
  332.  
  333.     Ide_True = True
  334.     bValue = True
  335.  
  336. End Function
  337.  
  338. Public Function In_IDE() As Boolean
  339.  
  340.     Debug.Assert Ide_True(In_IDE)
  341.  
  342. End Function
  343.  
  344. Private Sub Error_Raise(ByVal lErr&)
  345.  
  346.     Dim sText$, sSource$
  347.  
  348.     If lErr > 1000 Then
  349.         sSource = App.EXEName + ".WindowProc"
  350.         Select Case lErr
  351.         Case eeCantSubclass
  352.             sText = "Can't subclass window"
  353.         Case eeAlreadyAttached
  354.             sText = "Message already handled by another class"
  355.         Case eeInvalidWindow
  356.             sText = "Invalid window"
  357.         Case eeNoExternalWindow
  358.             sText = "Can't modify external window"
  359.         End Select
  360.         Call Err.Raise(lErr Or vbObjectError, sSource, sText)
  361.     Else
  362.         Call Err.Raise(lErr, sSource)
  363.     End If
  364.  
  365. End Sub
  366.  
  367. Public Sub Clean_Up(ByVal lHwnd&)
  368.  
  369.     Dim lMsgCount&, lProcOld&
  370.  
  371.     lMsgCount = p_MessageCount(lHwnd)
  372.     If lMsgCount = 0 Then Exit Sub
  373.     lProcOld = p_OldWindowProc(lHwnd)
  374.     If Not (lProcOld = 0) Then Call SetWindowLong(lHwnd, GWL_WNDPROC, lProcOld)
  375.     p_OldWindowProc(lHwnd) = 0
  376.     p_MessageCount(lHwnd) = 0
  377.  
  378. End Sub
  379.  
  380. Private Sub Class_Terminate()
  381.  
  382.     Call GlobalFree(m_lCurrMsg)
  383.     Call GlobalFree(m_lClassAddr)
  384.  
  385. End Sub
  386.  
  387.  
  388.