如何模拟鼠标点击消息,使tabstrip的click事件发生

解决方案 »

  1.   

    本人API菜鸟,希望有详细代码 谢谢。
      

  2.   

    仿照
    http://topic.csdn.net/u/20090325/07/ab133e9f-de30-4ae0-a3d0-4c0238a651ff.html
      

  3.   

    这是一段经典代码,从枕善居来的代码,写自己的消息处理,在你前面的帖子中老鸟提到过Option Explicit
    '========================================================================================
    ' Subclasser declarations
    '========================================================================================Private Enum eMsgWhen
        [MSG_AFTER] = 1                                  'Message calls back after the original (previous) WndProc
        [MSG_BEFORE] = 2                                 'Message calls back before the original (previous) WndProc
        [MSG_BEFORE_AND_AFTER] = MSG_AFTER Or MSG_BEFORE 'Message calls back before and after the original (previous) WndProc
    End EnumPrivate Const ALL_MESSAGES     As Long = -1          'All messages added or deleted
    Private Const CODE_LEN         As Long = 197         'Length of the machine code in bytes
    Private Const GWL_WNDPROC      As Long = -4          'Get/SetWindow offset to the WndProc procedure address
    Private Const PATCH_04         As Long = 88          'Table B (before) address patch offset
    Private Const PATCH_05         As Long = 93          'Table B (before) entry count patch offset
    Private Const PATCH_08         As Long = 132         'Table A (after) address patch offset
    Private Const PATCH_09         As Long = 137         'Table A (after) entry count patch offsetPrivate Type tSubData                                'Subclass data type
        hWnd                       As Long               'Handle of the window being subclassed
        nAddrSub                   As Long               'The address of our new WndProc (allocated memory).
        nAddrOrig                  As Long               'The address of the pre-existing WndProc
        nMsgCntA                   As Long               'Msg after table entry count
        nMsgCntB                   As Long               'Msg before table entry count
        aMsgTblA()                 As Long               'Msg after table array
        aMsgTblB()                 As Long               'Msg Before table array
    End TypePrivate sc_aSubData()          As tSubData           'Subclass data array
    Private sc_aBuf(1 To CODE_LEN) As Byte               'Code buffer byte array
    Private sc_pCWP                As Long               'Address of the CallWindowsProc
    Private sc_pEbMode             As Long               'Address of the EbMode IDE break/stop/running function
    Private sc_pSWL                As Long               'Address of the SetWindowsLong function
      
    Private Declare Sub RtlMoveMemory Lib "kernel32" (Destination As Any, Source As Any, ByVal Length 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 GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
    Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem 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 VirtualProtect Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long'========================================================================================
    ' cMagneticWnd
    '========================================================================================'-- APIPrivate Type POINTAPI
        x1 As Long
        y1 As Long
    End TypePrivate Type RECT2
        x1 As Long
        y1 As Long
        x2 As Long
        y2 As Long
    End TypePrivate Const SPI_GETWORKAREA  As Long = 48Private Const WM_SIZING        As Long = &H214
    Private Const WM_MOVING        As Long = &H216
    Private Const WM_ENTERSIZEMOVE As Long = &H231
    Private Const WM_EXITSIZEMOVE  As Long = &H232
    Private Const WM_SYSCOMMAND    As Long = &H112
    Private Const WM_COMMAND       As Long = &H111Private Const WMSZ_LEFT        As Long = 1
    Private Const WMSZ_RIGHT       As Long = 2
    Private Const WMSZ_TOP         As Long = 3
    Private Const WMSZ_TOPLEFT     As Long = 4
    Private Const WMSZ_TOPRIGHT    As Long = 5
    Private Const WMSZ_BOTTOM      As Long = 6
    Private Const WMSZ_BOTTOMLEFT  As Long = 7
    Private Const WMSZ_BOTTOMRIGHT As Long = 8Private Const SC_MINIMIZE      As Long = &HF020&
    Private Const SC_RESTORE       As Long = &HF120&Private Const SWP_NOSIZE       As Long = &H1
    Private Const SWP_NOZORDER     As Long = &H4
    Private Const SWP_NOACTIVATE   As Long = &H10Private Declare Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" (ByVal uAction As Long, ByVal uParam As Long, lpvParam As Any, ByVal fuWinIni As Long) As Long
    Private Declare Function IsWindow Lib "user32" (ByVal hWnd As Long) As Long
    Private Declare Function IsZoomed Lib "user32" (ByVal hWnd As Long) As Long
    Private Declare Function BeginDeferWindowPos Lib "user32" (ByVal nNumWindows As Long) As Long
    Private Declare Function DeferWindowPos Lib "user32" (ByVal hWinPosInfo As Long, ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
    Private Declare Function EndDeferWindowPos Lib "user32" (ByVal hWinPosInfo As Long) As Long
    Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
    Private Declare Function GetWindowRect Lib "user32" (ByVal hWnd As Long, lpRect As RECT2) As Long
    Private Declare Function OffsetRect Lib "user32" (lpRect As RECT2, ByVal x As Long, ByVal y As Long) As Long
    Private Declare Function UnionRect Lib "user32" (lpDestRect As RECT2, lpSrc1Rect As RECT2, lpSrc2Rect As RECT2) As LongPrivate Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSrc As Any, ByVal ByteLen As Long)'-- Private types:Private Type WND_INFO
        hWnd       As Long
        hWndParent As Long
        Glue       As Boolean
    End Type'-- Private constants:Private Const LB_RECT As Long = 16'-- Private variables:Private m_uWndInfo()  As WND_INFO
    Private m_lWndCount   As Long
    Private m_rcWnd()     As RECT2
    Private m_ptAnchor    As POINTAPI
    Private m_ptOffset    As POINTAPI
    Private m_ptCurr      As POINTAPI
    Private m_ptLast      As POINTAPI'-- Property variables:Private m_lSnapWidth As Long'//
      

  4.   

    Private Sub Class_Initialize()
        
        '-- Default snap width
        m_lSnapWidth = 10
        
        '-- Initialize array (handled windows info)
        ReDim m_uWndInfo(0) As WND_INFO
        m_lWndCount = 0
    End SubPrivate Sub Class_Terminate()
        
        '-- Stop subclassing
        If (m_lWndCount) Then
            Call Subclass_StopAll
        End If
    End Sub'========================================================================================
    ' Subclass handler: MUST be the first Public routine in this file.
    '                   That includes public properties also.
    '========================================================================================Public Sub zSubclass_Proc(ByVal bBefore As Boolean, ByRef bHandled As Boolean, ByRef lReturn As Long, ByRef lng_hWnd As Long, ByRef uMsg As Long, ByRef wParam As Long, ByRef lParam As Long)
    '
    'Parameters:
    '   bBefore  - Indicates whether the the message is being processed before or after the default handler - only really needed if a message is set to callback both before & after.
    '   bHandled - Set this variable to True in a 'before' callback to prevent the message being subsequently processed by the default handler... and if set, an 'after' callback
    '   lReturn  - Set this variable as per your intentions and requirements, see the MSDN documentation for each individual message value.
    '   lng_hWnd - The window handle
    '   uMsg     - The message number
    '   wParam   - Message related data
    '   lParam   - Message related data
    '
    'Notes:
    '   If you really know what you're doing, it's possible to change the values of the
    '   hWnd, uMsg, wParam and lParam parameters in a 'before' callback so that different
    '   values get passed to the default handler.. and optionaly, the 'after' callback
      
      Dim rcWnd As RECT2
      Dim lc    As Long
      
        Select Case uMsg
            
            '-- Size/Move starting
            Case WM_ENTERSIZEMOVE
                
                '-- Get Desktop area (as first rectangle)
                Call SystemParametersInfo(SPI_GETWORKAREA, 0, m_rcWnd(0), 0)
                
                '-- Get rectangles of all handled windows
                For lc = 1 To m_lWndCount
                    
                    '-- Window maximized ?
                    If (IsZoomed(m_uWndInfo(lc).hWnd)) Then
                        '-- Take work are rectangle
                        Call CopyMemory(m_rcWnd(lc), m_rcWnd(0), LB_RECT)
                      Else
                        '-- Get window rectangle
                        Call GetWindowRect(m_uWndInfo(lc).hWnd, m_rcWnd(lc))
                    End If
                    
                    '-- Is it our current window ?
                    If (m_uWndInfo(lc).hWnd = lng_hWnd) Then
                        '-- Get anchor-offset
                        Call GetCursorPos(m_ptAnchor)
                        Call GetCursorPos(m_ptLast)
                        m_ptOffset.x1 = m_rcWnd(lc).x1 - m_ptLast.x1
                        m_ptOffset.y1 = m_rcWnd(lc).y1 - m_ptLast.y1
                    End If
                Next lc
            
            '-- Sizing
            Case WM_SIZING
                
                Call CopyMemory(rcWnd, ByVal lParam, LB_RECT)
                Call pvSizeRect(lng_hWnd, rcWnd, wParam)
                Call CopyMemory(ByVal lParam, rcWnd, LB_RECT)
                
                bHandled = True
                lReturn = 1
            
            '-- Moving
            Case WM_MOVING
                
                Call CopyMemory(rcWnd, ByVal lParam, LB_RECT)
                Call pvMoveRect(lng_hWnd, rcWnd)
                Call CopyMemory(ByVal lParam, rcWnd, LB_RECT)
                
                bHandled = True
                lReturn = 1
            
            '-- Size/Move finishing
            Case WM_EXITSIZEMOVE
                
                Call pvCheckGlueing
                
            '-- Special case: *menu* call
            Case WM_SYSCOMMAND
                
                If (wParam = SC_MINIMIZE Or wParam = SC_RESTORE) Then
                    Call pvCheckGlueing
                End If
            
            '-- Special case: *control* call
            Case WM_COMMAND
                
                Call pvCheckGlueing
        End Select
    End Sub
      

  5.   

    '========================================================================================
    ' Methods
    '========================================================================================Public Function AddWindow(ByVal hWnd As Long, Optional ByVal hWndParent As Long = 0) As Boolean  Dim lc As Long
        
        '-- Already in collection ?
        For lc = 1 To m_lWndCount
            If (hWnd = m_uWndInfo(lc).hWnd) Then Exit Function
        Next lc
        
        '-- Validate windows
        If (IsWindow(hWnd) And (IsWindow(hWndParent) Or hWndParent = 0)) Then
            
            '-- Increase count
            m_lWndCount = m_lWndCount + 1
            '-- Resize arrays
            ReDim Preserve m_uWndInfo(0 To m_lWndCount)
            ReDim Preserve m_rcWnd(0 To m_lWndCount)
            
            '-- Add info
            With m_uWndInfo(m_lWndCount)
                .hWnd = hWnd
                .hWndParent = hWndParent
            End With
            
            '-- Check glueing for first time
            Call pvCheckGlueing
            
            '-- Start subclassing
            Call Subclass_Start(hWnd)
            Call Subclass_AddMsg(hWnd, WM_ENTERSIZEMOVE)
            Call Subclass_AddMsg(hWnd, WM_SIZING, [MSG_BEFORE])
            Call Subclass_AddMsg(hWnd, WM_MOVING, [MSG_BEFORE])
            Call Subclass_AddMsg(hWnd, WM_EXITSIZEMOVE)
            Call Subclass_AddMsg(hWnd, WM_SYSCOMMAND)
            Call Subclass_AddMsg(hWnd, WM_COMMAND)
            
            '-- Success
            AddWindow = True
        End If
    End FunctionPublic Function RemoveWindow(ByVal hWnd As Long) As Boolean  Dim lc1 As Long
      Dim lc2 As Long    For lc1 = 1 To m_lWndCount
            
            If (hWnd = m_uWndInfo(lc1).hWnd) Then
                
                '-- Move down
                For lc2 = lc1 To m_lWndCount - 1
                    m_uWndInfo(lc2) = m_uWndInfo(lc2 + 1)
                Next lc2
                
                '-- Resize arrays
                m_lWndCount = m_lWndCount - 1
                ReDim Preserve m_uWndInfo(m_lWndCount)
                ReDim Preserve m_rcWnd(m_lWndCount)
                
                '-- Remove parent relationships
                For lc2 = 1 To m_lWndCount
                    If (m_uWndInfo(lc2).hWndParent = hWnd) Then
                        m_uWndInfo(lc2).hWndParent = 0
                    End If
                Next lc2
                
                '-- Stop subclassing / verify connections
                Call Subclass_Stop(hWnd)
                Call pvCheckGlueing
                
                '-- Success
                RemoveWindow = True
                Exit For
            End If
        Next lc1
    End FunctionPublic Sub CheckGlueing()
            
        '-- Check ALL windows for possible new *connections*.
        Call pvCheckGlueing
    End Sub'========================================================================================
    ' Properties
    '========================================================================================Public Property Get SnapWidth() As Long
        SnapWidth = m_lSnapWidth
    End PropertyPublic Property Let SnapWidth(ByVal New_SnapWidth As Long)
        m_lSnapWidth = New_SnapWidth
    End Property'========================================================================================
    ' Private
    '========================================================================================Private Sub pvSizeRect(ByVal hWnd As Long, rcWnd As RECT2, ByVal lfEdge As Long)
        
      Dim rcTmp As RECT2
      Dim lc    As Long
        
        '-- Get a copy
        Call CopyMemory(rcTmp, rcWnd, LB_RECT)
        
        '-- Check all windows
        For lc = 0 To m_lWndCount
            
            With m_rcWnd(lc)
                
                '-- Avoid current window
                If (m_uWndInfo(lc).hWnd <> hWnd) Then
                    
                    '-- X magnetism
                    If (rcWnd.y1 < .y2 + m_lSnapWidth And rcWnd.y2 > .y1 - m_lSnapWidth) Then
                        
                        Select Case lfEdge
                            
                          Case WMSZ_LEFT, WMSZ_TOPLEFT, WMSZ_BOTTOMLEFT
                        
                            Select Case True
                              Case Abs(rcTmp.x1 - .x1) < m_lSnapWidth: rcWnd.x1 = .x1
                              Case Abs(rcTmp.x1 - .x2) < m_lSnapWidth: rcWnd.x1 = .x2
                            End Select
                    
                          Case WMSZ_RIGHT, WMSZ_TOPRIGHT, WMSZ_BOTTOMRIGHT
                            
                            Select Case True
                              Case Abs(rcTmp.x2 - .x1) < m_lSnapWidth: rcWnd.x2 = .x1
                              Case Abs(rcTmp.x2 - .x2) < m_lSnapWidth: rcWnd.x2 = .x2
                            End Select
                        End Select
                    End If
                    
                    '-- Y magnetism
                    If (rcWnd.x1 < .x2 + m_lSnapWidth And rcWnd.x2 > .x1 - m_lSnapWidth) Then
                        
                        Select Case lfEdge
                            
                          Case WMSZ_TOP, WMSZ_TOPLEFT, WMSZ_TOPRIGHT
                            
                            Select Case True
                              Case Abs(rcTmp.y1 - .y1) < m_lSnapWidth: rcWnd.y1 = .y1
                              Case Abs(rcTmp.y1 - .y2) < m_lSnapWidth: rcWnd.y1 = .y2
                            End Select
                        
                          Case WMSZ_BOTTOM, WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT
                            
                            Select Case True
                              Case Abs(rcTmp.y2 - .y1) < m_lSnapWidth: rcWnd.y2 = .y1
                              Case Abs(rcTmp.y2 - .y2) < m_lSnapWidth: rcWnd.y2 = .y2
                            End Select
                        End Select
                    End If
                End If
            End With
        Next lc
    End Sub
      

  6.   


    Private Sub pvMoveRect(ByVal hWnd As Long, rcWnd As RECT2)
        
      Dim lc1   As Long
      Dim lc2   As Long
      Dim lWId  As Long
      Dim rcTmp As RECT2
      Dim lOffx As Long
      Dim lOffy As Long
      Dim hDWP  As Long
        
        '== Get current cursor position
        
        Call GetCursorPos(m_ptCurr)
        
        '== Check magnetism for current window
        
        '-- 'Move' current window
        Call OffsetRect(rcWnd, (m_ptCurr.x1 - rcWnd.x1) + m_ptOffset.x1, 0)
        Call OffsetRect(rcWnd, 0, (m_ptCurr.y1 - rcWnd.y1) + m_ptOffset.y1)
        
        '-- Check all windows
        For lc1 = 0 To m_lWndCount
            
            '-- Avoid current window
            If (m_uWndInfo(lc1).hWnd <> hWnd) Then
                    
                '-- Avoid child windows
                If (m_uWndInfo(lc1).Glue = False Or m_uWndInfo(lc1).hWndParent <> hWnd) Then
                        
                    With m_rcWnd(lc1)
                    
                        '-- X magnetism
                        If (rcWnd.y1 < .y2 + m_lSnapWidth And rcWnd.y2 > .y1 - m_lSnapWidth) Then
                        
                            Select Case True
                              Case Abs(rcWnd.x1 - .x1) < m_lSnapWidth: lOffx = .x1 - rcWnd.x1
                              Case Abs(rcWnd.x1 - .x2) < m_lSnapWidth: lOffx = .x2 - rcWnd.x1
                              Case Abs(rcWnd.x2 - .x1) < m_lSnapWidth: lOffx = .x1 - rcWnd.x2
                              Case Abs(rcWnd.x2 - .x2) < m_lSnapWidth: lOffx = .x2 - rcWnd.x2
                            End Select
                        End If
                        
                        '-- Y magnetism
                        If (rcWnd.x1 < .x2 + m_lSnapWidth And rcWnd.x2 > .x1 - m_lSnapWidth) Then
                        
                            Select Case True
                              Case Abs(rcWnd.y1 - .y1) < m_lSnapWidth: lOffy = .y1 - rcWnd.y1
                              Case Abs(rcWnd.y1 - .y2) < m_lSnapWidth: lOffy = .y2 - rcWnd.y1
                              Case Abs(rcWnd.y2 - .y1) < m_lSnapWidth: lOffy = .y1 - rcWnd.y2
                              Case Abs(rcWnd.y2 - .y2) < m_lSnapWidth: lOffy = .y2 - rcWnd.y2
                            End Select
                        End If
                    End With
                End If
            End If
        Next lc1
        
        '== Check magnetism for child windows
        
        For lc1 = 1 To m_lWndCount
            
            '-- Child and connected window ?
            If (m_uWndInfo(lc1).Glue And m_uWndInfo(lc1).hWndParent = hWnd) Then
                
                '-- 'Move' child window
                Call CopyMemory(rcTmp, m_rcWnd(lc1), LB_RECT)
                Call OffsetRect(rcTmp, m_ptCurr.x1 - m_ptAnchor.x1, 0)
                Call OffsetRect(rcTmp, 0, m_ptCurr.y1 - m_ptAnchor.y1)
                
                For lc2 = 0 To m_lWndCount
                                            
                    If (lc1 <> lc2) Then
                        
                        '-- Avoid child windows
                        If (m_uWndInfo(lc2).Glue = False And m_uWndInfo(lc2).hWnd <> hWnd) Then
                        
                            With m_rcWnd(lc2)
                        
                                '-- X magnetism
                                If (rcTmp.y1 < .y2 + m_lSnapWidth And rcTmp.y2 > .y1 - m_lSnapWidth) Then
                                    
                                    Select Case True
                                      Case Abs(rcTmp.x1 - .x1) < m_lSnapWidth: lOffx = .x1 - rcTmp.x1
                                      Case Abs(rcTmp.x1 - .x2) < m_lSnapWidth: lOffx = .x2 - rcTmp.x1
                                      Case Abs(rcTmp.x2 - .x1) < m_lSnapWidth: lOffx = .x1 - rcTmp.x2
                                      Case Abs(rcTmp.x2 - .x2) < m_lSnapWidth: lOffx = .x2 - rcTmp.x2
                                    End Select
                                End If
                                
                                '-- Y magnetism
                                If (rcTmp.x1 < .x2 + m_lSnapWidth And rcTmp.x2 > .x1 - m_lSnapWidth) Then
                                
                                    Select Case True
                                      Case Abs(rcTmp.y1 - .y1) < m_lSnapWidth: lOffy = .y1 - rcTmp.y1
                                      Case Abs(rcTmp.y1 - .y2) < m_lSnapWidth: lOffy = .y2 - rcTmp.y1
                                      Case Abs(rcTmp.y2 - .y1) < m_lSnapWidth: lOffy = .y1 - rcTmp.y2
                                      Case Abs(rcTmp.y2 - .y2) < m_lSnapWidth: lOffy = .y2 - rcTmp.y2
                                    End Select
                                End If
                            End With
                        End If
                    End If
                Next lc2
            End If
        Next lc1
        
        '== Apply offsets
        
        Call OffsetRect(rcWnd, lOffx, lOffy)
        
        '== Glueing (move child windows, if any)
        
        hDWP = BeginDeferWindowPos(1)
        
        For lc1 = 1 To m_lWndCount
            With m_uWndInfo(lc1)
                '-- Is parent our current window ?
                If (.hWndParent = hWnd And .Glue) Then
                    '-- Move 'child' window
                    lWId = pvWndGetInfoIndex(hWnd)
                    With m_rcWnd(lc1)
                        Call DeferWindowPos(hDWP, m_uWndInfo(lc1).hWnd, 0, .x1 - (m_rcWnd(lWId).x1 - rcWnd.x1), .y1 - (m_rcWnd(lWId).y1 - rcWnd.y1), 0, 0, SWP_NOACTIVATE Or SWP_NOSIZE Or SWP_NOZORDER)
                    End With
                End If
            End With
        Next lc1
        
        Call EndDeferWindowPos(hDWP)
        
        '== Store last cursor position
        
        m_ptLast = m_ptCurr
    End Sub
      

  7.   

    Private Sub pvCheckGlueing()
        
      Dim lcMain As Long
      Dim lc1    As Long
      Dim lc2    As Long
      Dim lWId   As Long
        
        '-- Get all windows rectangles / Reset glueing
        For lc1 = 1 To m_lWndCount
            
            Call GetWindowRect(m_uWndInfo(lc1).hWnd, m_rcWnd(lc1))
            m_uWndInfo(lc1).Glue = False
        Next lc1
        
        '-- Check direct connection
        For lc1 = 1 To m_lWndCount
            
            If (m_uWndInfo(lc1).hWndParent) Then
            
                '-- Get parent window info index
                lWId = pvWndParentGetInfoIndex(m_uWndInfo(lc1).hWndParent)
                '-- Connected ?
                m_uWndInfo(lc1).Glue = pvWndsConnected(m_rcWnd(lWId), m_rcWnd(lc1))
            End If
        Next lc1
        
        '-- Check indirect connection
        For lcMain = 1 To m_lWndCount
            
            For lc1 = 1 To m_lWndCount
                
                If (m_uWndInfo(lc1).Glue) Then
                    
                    For lc2 = 1 To m_lWndCount
                    
                        If (lc1 <> lc2) Then
                        
                            If (m_uWndInfo(lc1).hWndParent = m_uWndInfo(lc2).hWndParent) Then
                                '-- Connected ?
                                If (m_uWndInfo(lc2).Glue = False) Then
                                    m_uWndInfo(lc2).Glue = pvWndsConnected(m_rcWnd(lc1), m_rcWnd(lc2))
                                End If
                            End If
                        End If
                    Next lc2
                End If
            Next lc1
        Next lcMain
    End SubPrivate Function pvWndsConnected(rcWnd1 As RECT2, rcWnd2 As RECT2) As Boolean
        
      Dim rcUnion As RECT2
      
        '-- Calc. union rectangle of windows
        Call UnionRect(rcUnion, rcWnd1, rcWnd2)
        
        '-- Bounding glue-rectangle
        If ((rcUnion.x2 - rcUnion.x1) <= (rcWnd1.x2 - rcWnd1.x1) + (rcWnd2.x2 - rcWnd2.x1) And _
            (rcUnion.y2 - rcUnion.y1) <= (rcWnd1.y2 - rcWnd1.y1) + (rcWnd2.y2 - rcWnd2.y1) _
             ) Then
            
            '-- Edge coincidences ?
            If (rcWnd1.x1 = rcWnd2.x1 Or rcWnd1.x1 = rcWnd2.x2 Or _
                rcWnd1.x2 = rcWnd2.x1 Or rcWnd1.x2 = rcWnd2.x2 Or _
                rcWnd1.y1 = rcWnd2.y1 Or rcWnd1.y1 = rcWnd2.y2 Or _
                rcWnd1.y2 = rcWnd2.y1 Or rcWnd1.y2 = rcWnd2.y2 _
                ) Then
                
                pvWndsConnected = True
            End If
        End If
    End FunctionPrivate Function pvWndGetInfoIndex(ByVal hWnd As Long) As Long
        
      Dim lc As Long
        
        For lc = 1 To m_lWndCount
            If (m_uWndInfo(lc).hWnd = hWnd) Then
                pvWndGetInfoIndex = lc
                Exit For
            End If
        Next lc
    End FunctionPrivate Function pvWndParentGetInfoIndex(ByVal hWndParent As Long) As Long
        
      Dim lc As Long
        
        For lc = 1 To m_lWndCount
            If (m_uWndInfo(lc).hWnd = hWndParent) Then
                pvWndParentGetInfoIndex = lc
                Exit For
            End If
        Next lc
    End Function
      

  8.   

    TabStrip1.Tabs(1).Selected = True
      

  9.   


    '========================================================================================
    ' Subclass code - The programmer may call any of the following Subclass_??? routines
    '========================================================================================Private Sub Subclass_AddMsg(ByVal lng_hWnd As Long, ByVal uMsg As Long, Optional ByVal When As eMsgWhen = MSG_AFTER)
    'Add a message to the table of those that will invoke a callback. You should Subclass_Start first and then add the messages
    'Parameters:
    '   lng_hWnd - The handle of the window for which the uMsg is to be added to the callback table
    '   uMsg     - The message number that will invoke a callback. NB Can also be ALL_MESSAGES, ie all messages will callback
    '   When     - Whether the msg is to callback before, after or both with respect to the the default (previous) handler
      
        With sc_aSubData(zIdx(lng_hWnd))
            If (When And eMsgWhen.MSG_BEFORE) Then
                Call zAddMsg(uMsg, .aMsgTblB, .nMsgCntB, eMsgWhen.MSG_BEFORE, .nAddrSub)
            End If
            If (When And eMsgWhen.MSG_AFTER) Then
                Call zAddMsg(uMsg, .aMsgTblA, .nMsgCntA, eMsgWhen.MSG_AFTER, .nAddrSub)
            End If
        End With
    End SubPrivate Sub Subclass_DelMsg(ByVal lng_hWnd As Long, ByVal uMsg As Long, Optional ByVal When As eMsgWhen = MSG_AFTER)
    'Delete a message from the table of those that will invoke a callback.
    'Parameters:
    '   lng_hWnd - The handle of the window for which the uMsg is to be removed from the callback table
    '   uMsg     - The message number that will be removed from the callback table. NB Can also be ALL_MESSAGES, ie all messages will callback
    '   When     - Whether the msg is to be removed from the before, after or both callback tables
      
        With sc_aSubData(zIdx(lng_hWnd))
            If (When And eMsgWhen.MSG_BEFORE) Then
                Call zDelMsg(uMsg, .aMsgTblB, .nMsgCntB, eMsgWhen.MSG_BEFORE, .nAddrSub)
            End If
            If (When And eMsgWhen.MSG_AFTER) Then
                Call zDelMsg(uMsg, .aMsgTblA, .nMsgCntA, eMsgWhen.MSG_AFTER, .nAddrSub)
            End If
        End With
    End SubPrivate Function Subclass_InIDE() As Boolean
    'Return whether we're running in the IDE.
        Debug.Assert zSetTrue(Subclass_InIDE)
    End Function
      

  10.   


    Private Function Subclass_Start(ByVal lng_hWnd As Long) As Long
    'Start subclassing the passed window handle
    'Parameters:
    '   lng_hWnd - The handle of the window to be subclassed
    'Returns;
    '   The sc_aSubData() index  Dim i                        As Long                       'Loop index
      Dim J                        As Long                       'Loop index
      Dim nSubIdx                  As Long                       'Subclass data index
      Dim sSubCode                 As String                     'Subclass code string
      
      Const GMEM_FIXED             As Long = 0                   'Fixed memory GlobalAlloc flag
      Const PAGE_EXECUTE_READWRITE As Long = &H40&               'Allow memory to execute without violating XP SP2 Data Execution Prevention
      Const PATCH_01               As Long = 18                  'Code buffer offset to the location of the relative address to EbMode
      Const PATCH_02               As Long = 68                  'Address of the previous WndProc
      Const PATCH_03               As Long = 78                  'Relative address of SetWindowsLong
      Const PATCH_06               As Long = 116                 'Address of the previous WndProc
      Const PATCH_07               As Long = 121                 'Relative address of CallWindowProc
      Const PATCH_0A               As Long = 186                 'Address of the owner object
      Const FUNC_CWP               As String = "CallWindowProcA" 'We use CallWindowProc to call the original WndProc
      Const FUNC_EBM               As String = "EbMode"          'VBA's EbMode function allows the machine code thunk to know if the IDE has stopped or is on a breakpoint
      Const FUNC_SWL               As String = "SetWindowLongA"  'SetWindowLongA allows the cSubclasser machine code thunk to unsubclass the subclasser itself if it detects via the EbMode function that the IDE has stopped
      Const MOD_USER               As String = "user32"          'Location of the SetWindowLongA & CallWindowProc functions
      Const MOD_VBA5               As String = "vba5"            'Location of the EbMode function if running VB5
      Const MOD_VBA6               As String = "vba6"            'Location of the EbMode function if running VB6    'If it's the first time through here..
        If (sc_aBuf(1) = 0) Then        'Build the hex pair subclass string
            sSubCode = "5589E583C4F85731C08945FC8945F8EB0EE80000000083F802742185C07424E830000000837DF800750AE838000000E84D0000005F8B45FCC9C21000E826000000EBF168000000006AFCFF7508E800000000EBE031D24ABF00000000B900000000E82D000000C3FF7514FF7510FF750CFF75086800000000E8000000008945FCC331D2BF00000000B900000000E801000000C3E32F09C978078B450CF2AF75248D4514508D4510508D450C508D4508508D45FC508D45F85052B800000000508B00FF501CC3"
        
            'Convert the string from hex pairs to bytes and store in the machine code buffer
            i = 1
            Do While J < CODE_LEN
                J = J + 1
                sc_aBuf(J) = CByte("&H" & Mid$(sSubCode, i, 2))                       'Convert a pair of hex characters to an eight-bit value and store in the static code buffer array
                i = i + 2
            Loop                                                                      'Next pair of hex characters
        
            'Get API function addresses
            If (Subclass_InIDE) Then                                                  'If we're running in the VB IDE
                sc_aBuf(16) = &H90                                                    'Patch the code buffer to enable the IDE state code
                sc_aBuf(17) = &H90                                                    'Patch the code buffer to enable the IDE state code
                sc_pEbMode = zAddrFunc(MOD_VBA6, FUNC_EBM)                            'Get the address of EbMode in vba6.dll
                If (sc_pEbMode = 0) Then                                              'Found?
                    sc_pEbMode = zAddrFunc(MOD_VBA5, FUNC_EBM)                        'VB5 perhaps
                End If
            End If
        
            Call zPatchVal(VarPtr(sc_aBuf(1)), PATCH_0A, ObjPtr(Me))                  'Patch the address of this object instance into the static machine code buffer
        
            sc_pCWP = zAddrFunc(MOD_USER, FUNC_CWP)                                   'Get the address of the CallWindowsProc function
            sc_pSWL = zAddrFunc(MOD_USER, FUNC_SWL)                                   'Get the address of the SetWindowLongA function
            ReDim sc_aSubData(0 To 0) As tSubData                                     'Create the first sc_aSubData element
        
          Else
            nSubIdx = zIdx(lng_hWnd, True)
            If (nSubIdx = -1) Then                                                    'If an sc_aSubData element isn't being re-cycled
                nSubIdx = UBound(sc_aSubData()) + 1                                   'Calculate the next element
                ReDim Preserve sc_aSubData(0 To nSubIdx) As tSubData                  'Create a new sc_aSubData element
            End If
        
            Subclass_Start = nSubIdx
        End If    With sc_aSubData(nSubIdx)
            
            .nAddrSub = GlobalAlloc(GMEM_FIXED, CODE_LEN)                             'Allocate memory for the machine code WndProc
            Call VirtualProtect(ByVal .nAddrSub, CODE_LEN, PAGE_EXECUTE_READWRITE, i) 'Mark memory as executable
            Call RtlMoveMemory(ByVal .nAddrSub, sc_aBuf(1), CODE_LEN)                 'Copy the machine code from the static byte array to the code array in sc_aSubData
        
            .hWnd = lng_hWnd                                                          'Store the hWnd
            .nAddrOrig = SetWindowLongA(.hWnd, GWL_WNDPROC, .nAddrSub)                'Set our WndProc in place
        
            Call zPatchRel(.nAddrSub, PATCH_01, sc_pEbMode)                           'Patch the relative address to the VBA EbMode api function, whether we need to not.. hardly worth testing
            Call zPatchVal(.nAddrSub, PATCH_02, .nAddrOrig)                           'Original WndProc address for CallWindowProc, call the original WndProc
            Call zPatchRel(.nAddrSub, PATCH_03, sc_pSWL)                              'Patch the relative address of the SetWindowLongA api function
            Call zPatchVal(.nAddrSub, PATCH_06, .nAddrOrig)                           'Original WndProc address for SetWindowLongA, unsubclass on IDE stop
            Call zPatchRel(.nAddrSub, PATCH_07, sc_pCWP)                              'Patch the relative address of the CallWindowProc api function
        End With
    End Function
      

  11.   


    Private Sub Subclass_StopAll()
    'Stop all subclassing
      
      Dim i As Long
      
        i = UBound(sc_aSubData())                                                     'Get the upper bound of the subclass data array
        Do While i >= 0                                                               'Iterate through each element
            With sc_aSubData(i)
                If (.hWnd <> 0) Then                                                  'If not previously Subclass_Stop'd
                    Call Subclass_Stop(.hWnd)                                         'Subclass_Stop
                End If
            End With
        
            i = i - 1                                                                 'Next element
        Loop
    End SubPrivate Sub Subclass_Stop(ByVal lng_hWnd As Long)
    'Stop subclassing the passed window handle
    'Parameters:
    '   lng_hWnd - The handle of the window to stop being subclassed
      
        With sc_aSubData(zIdx(lng_hWnd))
            Call SetWindowLongA(.hWnd, GWL_WNDPROC, .nAddrOrig)                       'Restore the original WndProc
            Call zPatchVal(.nAddrSub, PATCH_05, 0)                                    'Patch the Table B entry count to ensure no further 'before' callbacks
            Call zPatchVal(.nAddrSub, PATCH_09, 0)                                    'Patch the Table A entry count to ensure no further 'after' callbacks
            Call GlobalFree(.nAddrSub)                                                'Release the machine code memory
            .hWnd = 0                                                                 'Mark the sc_aSubData element as available for re-use
            .nMsgCntB = 0                                                             'Clear the before table
            .nMsgCntA = 0                                                             'Clear the after table
            Erase .aMsgTblB                                                           'Erase the before table
            Erase .aMsgTblA                                                           'Erase the after table
        End With
    End Sub'----------------------------------------------------------------------------------------
    'These z??? routines are exclusively called by the Subclass_??? routines.
    '----------------------------------------------------------------------------------------Private Sub zAddMsg(ByVal uMsg As Long, ByRef aMsgTbl() As Long, ByRef nMsgCnt As Long, ByVal When As eMsgWhen, ByVal nAddr As Long)
    'Worker sub for Subclass_AddMsg
      
      Dim nEntry  As Long                                                             'Message table entry index
      Dim nOff1   As Long                                                             'Machine code buffer offset 1
      Dim nOff2   As Long                                                             'Machine code buffer offset 2
      
        If (uMsg = ALL_MESSAGES) Then                                                 'If all messages
            nMsgCnt = ALL_MESSAGES                                                    'Indicates that all messages will callback
          Else                                                                        'Else a specific message number
            Do While nEntry < nMsgCnt                                                 'For each existing entry. NB will skip if nMsgCnt = 0
                nEntry = nEntry + 1
            
                If (aMsgTbl(nEntry) = 0) Then                                         'This msg table slot is a deleted entry
                    aMsgTbl(nEntry) = uMsg                                            'Re-use this entry
                    Exit Sub                                                          'Bail
                ElseIf (aMsgTbl(nEntry) = uMsg) Then                                  'The msg is already in the table!
                    Exit Sub                                                          'Bail
                End If
            Loop                                                                      'Next entry        nMsgCnt = nMsgCnt + 1                                                     'New slot required, bump the table entry count
            ReDim Preserve aMsgTbl(1 To nMsgCnt) As Long                              'Bump the size of the table.
            aMsgTbl(nMsgCnt) = uMsg                                                   'Store the message number in the table
        End If    If (When = eMsgWhen.MSG_BEFORE) Then                                          'If before
            nOff1 = PATCH_04                                                          'Offset to the Before table
            nOff2 = PATCH_05                                                          'Offset to the Before table entry count
          Else                                                                        'Else after
            nOff1 = PATCH_08                                                          'Offset to the After table
            nOff2 = PATCH_09                                                          'Offset to the After table entry count
        End If    If (uMsg <> ALL_MESSAGES) Then
            Call zPatchVal(nAddr, nOff1, VarPtr(aMsgTbl(1)))                          'Address of the msg table, has to be re-patched because Redim Preserve will move it in memory.
        End If
        Call zPatchVal(nAddr, nOff2, nMsgCnt)                                         'Patch the appropriate table entry count
    End SubPrivate Function zAddrFunc(ByVal sDLL As String, ByVal sProc As String) As Long
    'Return the memory address of the passed function in the passed dll
        zAddrFunc = GetProcAddress(GetModuleHandleA(sDLL), sProc)
        Debug.Assert zAddrFunc                                                        'You may wish to comment out this line if you're using vb5 else the EbMode GetProcAddress will stop here everytime because we look for vba6.dll first
    End FunctionPrivate Sub zDelMsg(ByVal uMsg As Long, ByRef aMsgTbl() As Long, ByRef nMsgCnt As Long, ByVal When As eMsgWhen, ByVal nAddr As Long)
    'Worker sub for Subclass_DelMsg
      
      Dim nEntry As Long
      
        If (uMsg = ALL_MESSAGES) Then                                                 'If deleting all messages
            nMsgCnt = 0                                                               'Message count is now zero
            If When = eMsgWhen.MSG_BEFORE Then                                        'If before
                nEntry = PATCH_05                                                     'Patch the before table message count location
              Else                                                                    'Else after
                nEntry = PATCH_09                                                     'Patch the after table message count location
            End If
            Call zPatchVal(nAddr, nEntry, 0)                                          'Patch the table message count to zero
          Else                                                                        'Else deleteting a specific message
            Do While nEntry < nMsgCnt                                                 'For each table entry
                nEntry = nEntry + 1
                If (aMsgTbl(nEntry) = uMsg) Then                                      'If this entry is the message we wish to delete
                    aMsgTbl(nEntry) = 0                                               'Mark the table slot as available
                    Exit Do                                                           'Bail
                End If
            Loop                                                                      'Next entry
        End If
    End Sub
      

  12.   

    Private Function zIdx(ByVal lng_hWnd As Long, Optional ByVal bAdd As Boolean = False) As Long
    'Get the sc_aSubData() array index of the passed hWnd
    'Get the upper bound of sc_aSubData() - If you get an error here, you're probably Subclass_AddMsg-ing before Subclass_Start
      
        zIdx = UBound(sc_aSubData)
        Do While zIdx >= 0                                                            'Iterate through the existing sc_aSubData() elements
            With sc_aSubData(zIdx)
                If (.hWnd = lng_hWnd) Then                                            'If the hWnd of this element is the one we're looking for
                    If (Not bAdd) Then                                                'If we're searching not adding
                        Exit Function                                                 'Found
                    End If
                ElseIf (.hWnd = 0) Then                                               'If this an element ed for reuse.
                    If (bAdd) Then                                                    'If we're adding
                        Exit Function                                                 'Re-use it
                    End If
                End If
            End With
            zIdx = zIdx - 1                                                           'Decrement the index
        Loop
      
        If (Not bAdd) Then
            Debug.Assert False                                                        'hWnd not found, programmer error
        End If'If we exit here, we're returning -1, no freed elements were found
    End FunctionPrivate Sub zPatchRel(ByVal nAddr As Long, ByVal nOffset As Long, ByVal nTargetAddr As Long)
    'Patch the machine code buffer at the indicated offset with the relative address to the target address.
        Call RtlMoveMemory(ByVal nAddr + nOffset, nTargetAddr - nAddr - nOffset - 4, 4)
    End SubPrivate Sub zPatchVal(ByVal nAddr As Long, ByVal nOffset As Long, ByVal nValue As Long)
    'Patch the machine code buffer at the indicated offset with the passed value
        Call RtlMoveMemory(ByVal nAddr + nOffset, nValue, 4)
    End SubPrivate Function zSetTrue(ByRef bValue As Boolean) As Boolean
    'Worker function for Subclass_InIDE
        zSetTrue = True
        bValue = True
    End Function你也可以使用sendmessage,网上一大把 - -
    或者callbyname
    CallByName obj_name, method_name, VbMethod
    再就是楼上各位说的,直接呼叫方法
    晕了,每次只允许发这么一点点 郁闷
      

  13.   

    先谢谢AisaC 我得好好学习消化一下 再结帖哈
      

  14.   

    还是用TabStrip1.Tabs(1).Selected = True这样的代码来实现比较好,模拟鼠标移上去点击一下会把人下一跳的 ^_^
      

  15.   

    使用PostMessage试试. Private Function SendClick(hwnd As Long, mX As Long, mY As Long) 
         '发送点击消息 
        Dim I As Long 
         
        I = PostMessage(hwnd, WM_LBUTTONDOWN, 0, (mX And &HFFFF) + (mY And &HFFFF) * &H10000) 
        I = PostMessage(hwnd, WM_LBUTTONUP, 0, (mX And &HFFFF) + (mY And &HFFFF) * &H10000) 
    End Function 调用SendClick,指定句柄,及坐标就可以了.坐标是窗体内的绝对坐标,只要你的TAB控件不会在窗体里跑来跑去即可句柄是主窗体句柄,找一次坐标即可.
      

  16.   

    to aisac: 今天才来学习你留下的课程。可是我理解力好差啊,看来看去怎么觉得你在所答非所问呀?
      

  17.   

    在老马17楼的代码上修正一下,传入hWnd为控件句柄、坐标为相对坐标。
      

  18.   

    to happy_sea, 你在15楼的方法不错。奇怪的是,我设置treeview的节点的selected为true的时候,却不能触发node click 消息。另外,请问像这种设置属性后会连带触发消息的 资料 在什么地方可以系统地查到?我有一本VB的控件参考手册,貌似里面并没有系统地讲到。
      

  19.   

    谢谢小马和zhao,折腾出来了,秀一下我的办法:
        Set aa = Me.TabStrip0.Object
    Call SendClick(aa.hwnd, aa.Tabs(2).Left / 15, aa.Tabs(2).Top / 15)
    注意,这里面这个15,那是缇和像素之间的转换窍要,呵呵。参看这里:http://blog.csdn.net/slowgrace/archive/2009/02/22/3916962.aspx以及下面的摘抄:“Left-返回或设置对象内部的左边与它的容器的左边之间的距离。Top-返回或设置对象的内顶部和它的容器的顶边之间的距离。
    对于窗体,Left 和 Top 属性总以缇为单位来表达;对于控件,它们的度量单位决定于它的容器的坐标系统。这些属性值随着用户或程序中移动该对象而改变。”BUT,不幸的是,这种办法和mouse-eventhttp://topic.csdn.net/u/20090325/07/ab133e9f-de30-4ae0-a3d0-4c0238a651ff.html一样,是在随后语句运行之后再激发相应的事件过程的。我不理解这后面是什么机制?什么在决定它们执行的顺序?
      

  20.   

    另外,关于WM_LBUTTONDOWN消息,摘抄如下(日后好做笔记:)http://baike.baidu.com/view/1514116.htmlParam 
      The low-order word specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area. 
      The high-order word specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area. 
      

  21.   

    谢谢Modest :)另外,post和send的区别我大概查到了。貌似我想同步地发消息触发这个事件的话,还是没找到解决方法……
      

  22.   

            
            '-- Special case: *menu* call
            Case WM_SYSCOMMAND
                
                If (wParam = SC_MINIMIZE Or wParam = SC_RESTORE) Then
                    Call pvCheckGlueing
                End If
            
            '-- Special case: *control* call
            Case WM_COMMAND
                
                Call pvCheckGlueing
        End Select
    End Sub
      

  23.   

    Private Function SendClick(hwnd As Long, mX As Long, mY As Long) 
         '发送点击消息 
        Dim I As Long 
         
        I = PostMessage(hwnd, WM_LBUTTONDOWN, 0, (mX And &HFFFF) + (mY And &HFFFF) * &H10000) 
        I = PostMessage(hwnd, WM_LBUTTONUP, 0, (mX And &HFFFF) + (mY And &HFFFF) * &H10000) 
    End Function 貌似正确,待测
      

  24.   

    仿照 
    http://topic.csdn.net/u/20090325/07/ab133e9f-de30-4ae0-a3d0-4c0238a651ff.html
      

  25.   

    谢谢各位指点。虽然问题没有完全解决,但是学到了很多东西,小结在这里:http://blog.csdn.net/slowgrace/archive/2009/04/15/4076404.aspx遗留的问题开新帖继续讨教,恳请各位移步前来指点:http://topic.csdn.net/u/20090416/15/f990c1f4-34d0-48b6-8fdf-ac3bb4836bd7.html
      

  26.   

    另外,to AISA C 你贴的代码我可一点也没用上啊可是你费那么大劲贴 不给你分的话 9有点不thick road了 是吧:)