Module1.bas

 Attribute VB_Name = "Module1"
Option Explicit

Private Type SCROLLINFO
    cbSize As Long
    fMask As Long
    nMin As Long
    nMax As Long
    nPage As Long
    nPos As Long
    nTrackPos As Long
End Type

Private Type RECT
     left As Long
     top As Long
     right As Long
     bottom As Long
End Type

Private Declare Function SetScrollInfo Lib "user32" (ByVal hWnd As Long, ByVal n As Long, lpcScrollInfo As SCROLLINFO, ByVal bool As Boolean) As Long
Private Declare Function GetScrollInfo Lib "user32" (ByVal hWnd As Long, ByVal n As Long, lpScrollInfo As SCROLLINFO) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function SetWindowPos Lib "user32" (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 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 Declare Function ScrollWindowByNum& Lib "user32" Alias "ScrollWindow" (ByVal hWnd As Long, ByVal XAmount As Long, ByVal YAmount As Long, ByVal lpRect As Long, ByVal lpClipRect As Long)
Private Declare Function GetWindowRect& Lib "user32" (ByVal hWnd As Long, lpRect As RECT)
Private Declare Function GetProp Lib "user32" Alias "GetPropA" (ByVal hWnd As Long, ByVal lpString As String) As Long
Private Declare Function SetProp Lib "user32" Alias "SetPropA" (ByVal hWnd As Long, ByVal lpString As String, ByVal hData As Long) As Long
Private Declare Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hWnd As Long, ByVal lpString As String) As Long
Private Declare Function GetSystemMetrics& Lib "user32" (ByVal nIndex As Long)

Private Const GWL_STYLE = (-16)
Private Const GWL_WNDPROC = (-4)
Private Const WS_VSCROLL = &H200000
Private Const WS_HSCROLL = &H100000
Private Const SWP_FRAMECHANGED = &H20
Private Const SWP_NOMOVE = &H2
Private Const SWP_NOZORDER = &H4
Private Const SWP_NOSIZE = &H1
Private Const SB_HORZ = 0
Private Const SB_VERT = 1
Private Const SB_BOTH = 3
Private Const SB_LINEDOWN = 1
Private Const SB_LINEUP = 0
Private Const SB_PAGEDOWN = 3
Private Const SB_PAGEUP = 2
Private Const SB_THUMBTRACK = 5
Private Const SB_ENDSCROLL = 8

Private Const WM_HSCROLL = &H114
Private Const WM_VSCROLL = &H115
Private Const WM_DESTROY = &H2
Private Const SIF_ALL = &H17
Private Const SIF_DISABLENOSCROLL = &H8
Private Const SM_CXVSCROLL = 2
Private Const SM_CYHSCROLL = 3

Dim s As SCROLLINFO
Dim OriginHeight As Long, OriginWidth As Long

Public Sub SetScrollBar(hObj As Long, sbPos As ScrollBarConstants, Optional bShowAlways As Boolean = False)
  Dim lStyle As Long, rc As RECT, OldProc As Long
  lStyle = sbPos * &H100000
  SetWindowLong hObj, GWL_STYLE, GetWindowLong(hObj, GWL_STYLE) Or lStyle
  SetWindowPos hObj, 0, 0, 0, 0, 0, SWP_FRAMECHANGED Or SWP_NOMOVE Or SWP_NOZORDER Or SWP_NOSIZE
  Call GetWindowRect(hObj, rc)
  OriginHeight = rc.bottom - rc.top + GetSystemMetrics(SM_CYHSCROLL) * (sbPos And vbHorizontal)
  OriginWidth = rc.right - rc.left + GetSystemMetrics(SM_CXVSCROLL) * (sbPos And vbVertical) / 2
  s.cbSize = Len(s)
  s.fMask = SIF_ALL
  If bShowAlways Then s.fMask = s.fMask Or SIF_DISABLENOSCROLL
  s.nMin = 0
  s.nPos = 0
  OldProc = SetWindowLong(hObj, GWL_WNDPROC, AddressOf WndProc)
  SetProp hObj, "OLDPROC", OldProc
  SetProp hObj, "SB_POS", sbPos
  SetProp hObj, "ORIGIN_WIDTH", OriginWidth
  SetProp hObj, "ORIGIN_HEIGHT", OriginHeight
End Sub

Public Sub AdjustScrollInfo(hObj As Long)
  Dim sb As Long, rc As RECT
  sb = GetProp(hObj, "SB_POS")
  Call GetWindowRect(hObj, rc)
  If (sb And vbVertical) = vbVertical Then
     Call GetScrollInfo(hObj, SB_VERT, s)
     s.nMax = GetProp(hObj, "ORIGIN_HEIGHT")
     s.nPage = rc.bottom - rc.top + 1
     If s.nPage > s.nMax - s.nPos + 1 Then
        s.nPage = s.nMax - s.nPos + 1
     End If
     Call SetScrollInfo(hObj, SB_VERT, s, True)
  End If
  If (sb And vbHorizontal) = vbHorizontal Then
     Call GetScrollInfo(hObj, SB_HORZ, s)
     s.nMax = GetProp(hObj, "ORIGIN_WIDTH")
     s.nPage = rc.right - rc.left + 1
     If s.nPage > s.nMax - s.nPos + 1 Then
        s.nPage = s.nMax - s.nPos + 1
     End If
     Call SetScrollInfo(hObj, SB_HORZ, s, True)
  End If
End Sub

Public Function WndProc(ByVal hOwner As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
   Dim nOldPos As Long, n As Long
   Select Case wMsg
      Case WM_VSCROLL, WM_HSCROLL
           GetScrollInfo hOwner, wMsg - WM_HSCROLL, s
           nOldPos = s.nPos
           Select Case GetLoWord(wParam)
               Case SB_LINEDOWN
                    s.nPos = s.nPos + s.nPage \ 10
               Case SB_LINEUP
                    s.nPos = s.nPos - s.nPage \ 10
               Case SB_PAGEDOWN
                    s.nPos = s.nPos + s.nPage
               Case SB_PAGEUP
                    s.nPos = s.nPos - s.nPage
               Case SB_THUMBTRACK
                    s.nPos = GetHiWord(wParam)
               Case SB_ENDSCROLL
                    If s.nPos = 0 Then
                       AdjustScrollInfo hOwner
                       Exit Function
                    End If
           End Select
           SetScrollInfo hOwner, wMsg - WM_HSCROLL, s, True
           GetScrollInfo hOwner, wMsg - WM_HSCROLL, s
           If wMsg = WM_VSCROLL Then
              ScrollWindowByNum hOwner, 0, nOldPos - s.nPos, 0, 0
           Else
              ScrollWindowByNum hOwner, nOldPos - s.nPos, 0, 0, 0
           End If
      Case WM_DESTROY
           RemoveProp hOwner, "SB_POS"
           RemoveProp hOwner, "ORIGIN_WIDTH"
           RemoveProp hOwner, "ORIGIN_HEIGHT"
           Call SetWindowLong(hOwner, GWL_WNDPROC, GetProp(hOwner, "OLDPROC"))
      Case Else
   End Select
   WndProc = CallWindowProc(GetProp(hOwner, "OLDPROC"), hOwner, wMsg, wParam, lParam)
End Function

Private Function GetHiWord(dw As Long) As Long
  If dw And &H80000000 Then
     GetHiWord = (dw \ 65535) - 1
  Else
     GetHiWord = dw \ 65535
  End If
End Function

Private Function GetLoWord(dw As Long) As Long
   If dw And &H8000& Then
      GetLoWord = &H8000 Or (dw And &H7FFF&)
   Else
      GetLoWord = dw And &HFFFF&
   End If
End Function

Project Homepage: