vbAccelerator - Contents of code file: cTitleBar.cls

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "cTitleBar"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Option Explicit

' ==========================================================================
' Filename: cTitlebar.cls
' Author:   Steve McMahon
' Date:     25 November 1998
'
' Mostly based on Ben Baird's code, see below.
' Changes:
'   -Change Subclass method to SSUBTMR
'   -Added WM_STYLECHANGED and WM_SETTEXT to allow titlebar to be
'   repainted when caption changes.
'   -Icon is now drawn transparent rather than with black background
'   -Added facility to change start/end and text colours (although if
'   the end colour isn't the title bar colour, it doesn't really work)
'   -Removed WM_SIZE subclass this prevented the form
'    from being resized and/or lost the Form_Resize message
'    and was also unnecessary
'   -Now determines what buttons are present when drawing gradient
'   -Check for tool window and appropriately smaller Tbar
'   -Added owner draw background support
'
' ==========================================================================

'//================================================
'+ Gradient titlebar example, version 1.1
'+ Author: Ben Baird
'+ Comments: Uploaded to Visual Basic Thunder
'            with Excalibur CodeLib on Monday,
'            September 1, 1997.
'            Thanks goes to Eric Dimayuga for
'            letting me bounce some ideas off
'            him. He also assisted me with the
'            theory of the code.
'
'+ If you release this code or any modified version
'  of it to the private, I would appreciate some
'  credit for the original code.
'+ FIXED IN THIS VERSION:
'   - Some trouble with the GradientGetCapsFont routine,
'   mainly a problem with the LOGFONT declaration.
'   - Added some more cleanup code.
'//================================================

Dim GradhWnd As Long, GradIcon As Long
Dim DrawDC As Long, tmpDC As Long
Dim hRgn As Long
Dim tmpGradFont As Long
Private m_bInSubClass As Boolean
Private m_bMDI As Boolean
Private m_pic As StdPicture
Private m_lHdc As Long
Private m_lHBmpOld As Long
Private m_lhPalOld As Long
Private m_lBitmapW As Long
Private m_lBitmapH As Long
Private m_sFileName As String
Private m_bCustomDraw As Boolean
Private m_bTextTransparent As Boolean
Implements ISubclass
Private m_emr As EMsgResponse
Private m_oColor(1 To 6) As OLE_COLOR
Public Enum EGradTitleBarColors
    eActiveStartColor = 1
    eActiveEndColor = 2
    eActiveText = 3
    einActivestartcolor = 4
    eInactiveEndColor = 5
    eInActiveText = 6
End Enum
Public Enum EGradTitleBarDrawStage
    eDrawBackground
    eDrawIcon
    eDrawText
End Enum
Public Event CustomDraw(ByVal eDrawStage As EGradTitleBarDrawStage, ByRef
 bDoDefault As Boolean, ByVal lhDC As Long, ByVal lLeft As Long, ByVal lTop As
 Long, ByVal lWidth As Long, ByVal lHeight As Long, ByVal bActive As Boolean)

Private Type DRAWTEXTPARAMS
    cbSize As Long
    iTabLength As Long
    iLeftMargin As Long
    iRightMargin As Long
    uiLengthDrawn As Long
End Type
Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
End Type
Private Type LOGFONT
        lfHeight As Long
        lfWidth As Long
        lfEscapement As Long
        lfOrientation As Long
        lfWeight As Long
        lfItalic As Byte
        lfUnderline As Byte
        lfStrikeOut As Byte
        lfCharSet As Byte
        lfOutPrecision As Byte
        lfClipPrecision As Byte
        lfQuality As Byte
        lfPitchAndFamily As Byte
        lfFaceName As String * 32
End Type

Private 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 Const SPI_GETNONCLIENTMETRICS = 41
Private Type NONCLIENTMETRICS
    cbSize As Long
    iBorderWidth As Long
    iScrollWidth As Long
    iScrollHeight As Long
    iCaptionWidth As Long
    iCaptionHeight As Long
    lfCaptionFont As LOGFONT
    iSMCaptionWidth As Long
    iSMCaptionHeight As Long
    lfSMCaptionFont As LOGFONT
    iMenuWidth As Long
    iMenuHeight As Long
    lfMenuFont As LOGFONT
    lfStatusFont As LOGFONT
    lfMessageFont As LOGFONT
End Type
Dim CaptionFont As LOGFONT
Private Declare Function CreateFontIndirect Lib "gdi32" Alias
 "CreateFontIndirectA" (lpLogFont As LOGFONT) 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 GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd
 As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA"
 (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetWindowRgn Lib "user32" (ByVal hwnd As Long, ByVal
 hRgn As Long) As Long
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect
 As RECT) As Long
Private Declare Function GetActiveWindow Lib "user32" () As Long
Private Declare Function GetClassLong Lib "user32" Alias "GetClassLongA" (ByVal
 hwnd As Long, ByVal nIndex 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 SetClassLong Lib "user32" Alias "SetClassLongA" (ByVal
 hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong 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 Const GWL_WNDPROC = (-4)
Private Const GWL_STYLE = (-16)
Private Const GWL_EXSTYLE = (-20)
Private Const GCL_WNDPROC = (-24)
Private Const GCL_HICON = (-14)
Private Const WS_BORDER = &H800000
Private Const WS_CAPTION = &HC00000 'WS_BORDER Or WS_DLGFRAME
Private Const WS_CHILD = &H40000000
Private Const WS_CHILDWINDOW = (WS_CHILD)
Private Const WS_CLIPCHILDREN = &H2000000
Private Const WS_CLIPSIBLINGS = &H4000000
Private Const WS_DISABLED = &H8000000
Private Const WS_DLGFRAME = &H400000
Private Const WS_EX_ACCEPTFILES = &H10&
Private Const WS_EX_DLGMODALFRAME = &H1&
Private Const WS_EX_NOPARENTNOTIFY = &H4&
Private Const WS_EX_TOPMOST = &H8&
Private Const WS_EX_TRANSPARENT = &H20&
Private Const WS_GROUP = &H20000
Private Const WS_HSCROLL = &H100000
Private Const WS_MINIMIZE = &H20000000
Private Const WS_ICONIC = WS_MINIMIZE
Private Const WS_MAXIMIZE = &H1000000
Private Const WS_MAXIMIZEBOX = &H10000
Private Const WS_MINIMIZEBOX = &H20000
Private Const WS_OVERLAPPED = &H0&
Private Const WS_SYSMENU = &H80000
Private Const WS_THICKFRAME = &H40000
Private Const WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED Or WS_CAPTION Or WS_SYSMENU
 Or WS_THICKFRAME Or WS_MINIMIZEBOX Or WS_MAXIMIZEBOX)
Private Const WS_POPUP = &H80000000
Private Const WS_POPUPWINDOW = (WS_POPUP Or WS_BORDER Or WS_SYSMENU)
Private Const WS_SIZEBOX = WS_THICKFRAME
Private Const WS_TILED = WS_OVERLAPPED
Private Const WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW
Private Const WS_VISIBLE = &H10000000
Private Const WS_VSCROLL = &H200000
Private Const WS_EX_TOOLWINDOW = &H80&

Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long

Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As
 Long
Private Declare Function OffsetClipRgn Lib "gdi32" (ByVal hDC As Long, ByVal X
 As Long, ByVal Y As Long) As Long
Private Declare Function DestroyIcon Lib "user32" (ByVal hIcon As Long) As Long
Private Declare Function OffsetRect Lib "user32" (lpRect As RECT, ByVal X As
 Long, ByVal Y As Long) As Long
Private Declare Function DrawIcon Lib "user32" (ByVal hDC As Long, ByVal X As
 Long, ByVal Y As Long, ByVal hIcon As Long) As Long
Private Declare Function DrawIconEx Lib "user32" (ByVal hDC As Long, ByVal
 xLeft As Long, ByVal yTop As Long, ByVal hIcon As Long, ByVal cxWidth As Long,
 ByVal cyWidth As Long, ByVal istepIfAniCur As Long, hbrFlickerFreeDraw As
 Long, ByVal diFlags As Long) As Long
Private Const DI_MASK = &H1
Private Const DI_IMAGE = &H2
Private Const DI_NORMAL = &H3
Private Const DI_COMPAT = &H4
Private Const DI_DEFAULTSIZE = &H8

Private Declare Function RectInRegion Lib "gdi32" (ByVal hRgn As Long, lpRect
 As RECT) As Long
Private Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hDC As
 Long, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal
 wFormat As Long) As Long
Private Declare Function DrawTextEx Lib "user32" Alias "DrawTextExA" (ByVal hDC
 As Long, ByVal lpsz As String, ByVal n As Long, lpRect As RECT, ByVal un As
 Long, lpDrawTextParams As DRAWTEXTPARAMS) As Long
Private Const DT_SINGLELINE = &H20
Private Const DT_VCENTER = &H4
Private Const DT_END_ELLIPSIS = &H8000&
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDC
 As Long) As Long
Private Declare Function SelectClipRgn Lib "gdi32" (ByVal hDC As Long, ByVal
 hRgn As Long) As Long
Private Declare Function GetClipRgn Lib "gdi32" (ByVal hDC As Long, ByVal hRgn
 As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal
 hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function DrawCaption Lib "user32" (ByVal hwnd As Long, ByVal
 hDC As Long, pcRect As RECT, ByVal un As Long) As Long
Private Declare Function ReleaseCapture Lib "user32" () As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, ByVal
 hObject As Long) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As
 Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal
 hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long)
 As Long
Private Const SRCCOPY = &HCC0020
Private Declare Function GetStockObject Lib "gdi32" (ByVal nIndex As Long) As
 Long
Private Declare Function SetBkMode Lib "gdi32" (ByVal hDC As Long, ByVal
 nBkMode As Long) As Long
Private Const TRANSPARENT = 1
Private Const OPAQUE = 2
Private Declare Function SetBkColor Lib "gdi32" (ByVal hDC As Long, ByVal
 crColor As Long) As Long
Private Declare Function OleTranslateColor Lib "OLEPRO32.DLL" (ByVal OLE_COLOR
 As Long, ByVal HPALETTE As Long, pccolorref As Long) As Long
Private Type BITMAP
    bmType As Long
    bmWidth As Long
    bmHeight As Long
    bmWidthBytes As Long
    bmPlanes As Integer
    bmBitsPixel As Integer
    bmBits As Long
End Type
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" (ByVal
 hObject As Long, ByVal nCount As Long, lpObject As Any) As Long

Private Declare Function CopyImage Lib "user32" (ByVal handle As Long, ByVal
 un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As Long
Private Declare Function SetTextColor Lib "gdi32" (ByVal hDC As Long, ByVal
 crColor As Long) As Long

Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long)
 As Long
Private Const SM_CMETRICS = 44
Private Const SM_CMOUSEBUTTONS = 43
Private Const SM_CXBORDER = 5
Private Const SM_CXCURSOR = 13
Private Const SM_CXDLGFRAME = 7
Private Const SM_CXDOUBLECLK = 36
Private Const SM_CXFIXEDFRAME = SM_CXDLGFRAME
Private Const SM_CXFRAME = 32
Private Const SM_CXFULLSCREEN = 16
Private Const SM_CXHSCROLL = 21
Private Const SM_CXHTHUMB = 10
Private Const SM_CXICON = 11
Private Const SM_CXICONSPACING = 38
Private Const SM_CXMIN = 28
Private Const SM_CXMINTRACK = 34
Private Const SM_CXSCREEN = 0
Private Const SM_CXSMSIZE = 30
Private Const SM_CXSIZEFRAME = SM_CXFRAME
Private Const SM_CXVSCROLL = 2
Private Const SM_CYBORDER = 6
Private Const SM_CYCAPTION = 4
Private Const SM_CYCURSOR = 14
Private Const SM_CYDLGFRAME = 8
Private Const SM_CYDOUBLECLK = 37
Private Const SM_CYFIXEDFRAME = SM_CYDLGFRAME
Private Const SM_CYFRAME = 33
Private Const SM_CYFULLSCREEN = 17
Private Const SM_CYHSCROLL = 3
Private Const SM_CYICON = 12
Private Const SM_CYICONSPACING = 39
Private Const SM_CYKANJIWINDOW = 18
Private Const SM_CYMENU = 15
Private Const SM_CYMIN = 29
Private Const SM_CYMINTRACK = 35
Private Const SM_CYSCREEN = 1
Private Const SM_CYSMSIZE = 31
Private Const SM_CYSIZEFRAME = SM_CYFRAME
Private Const SM_CYVSCROLL = 20
Private Const SM_CYVTHUMB = 9
Private Const SM_DBCSENABLED = 42
Private Const SM_DEBUG = 22
Private Const SM_MENUDROPALIGNMENT = 40
Private Const SM_MOUSEPRESENT = 19
Private Const SM_PENWINDOWS = 41
Private Const SM_RESERVED1 = 24
Private Const SM_RESERVED2 = 25
Private Const SM_RESERVED3 = 26
Private Const SM_RESERVED4 = 27
Private Const SM_SWAPBUTTON = 23
Private Const SM_CYSMCAPTION = 51


Private Declare Function FillRect Lib "user32" (ByVal hDC As Long, lpRect As
 RECT, ByVal hBrush As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hDC As Long,
 ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As
 Long
Private Declare Function CreateRectRgnIndirect Lib "gdi32" (lpRect As RECT) As
 Long
Private Declare Function CreateRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1
 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function ExcludeClipRect Lib "gdi32" (ByVal hDC As Long, ByVal
 X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long)
 As Long

Private Declare Function DrawFrameControl Lib "user32" (ByVal hDC As Long,
 lpRect As RECT, ByVal un1 As Long, ByVal un2 As Long) As Long
Private Const DFC_CAPTION = 1
Private Const DFCS_CAPTIONRESTORE = &H3
Private Const DFCS_CAPTIONMIN = &H1
Private Const DFCS_CAPTIONMAX = &H2
Private Const DFCS_CAPTIONHELP = &H4
Private Const DFCS_CAPTIONCLOSE = &H0
Private Const DFCS_INACTIVE = &H100

' GetSysColor:
Private Declare Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long

Private Const COLOR_SCROLLBAR = 0
Private Const COLOR_BACKGROUND = 1
Private Const COLOR_ACTIVECAPTION = 2
Private Const COLOR_INACTIVECAPTION = 3
Private Const COLOR_MENU = 4
Private Const COLOR_WINDOW = 5
Private Const COLOR_WINDOWFRAME = 6
Private Const COLOR_MENUTEXT = 7
Private Const COLOR_WINDOWTEXT = 8
Private Const COLOR_CAPTIONTEXT = 9
Private Const COLOR_ACTIVEBORDER = 10
Private Const COLOR_INACTIVEBORDER = 11
Private Const COLOR_APPWORKSPACE = 12
Private Const COLOR_HIGHLIGHT = 13
Private Const COLOR_HIGHLIGHTTEXT = 14
Private Const COLOR_BTNFACE = 15
Private Const COLOR_BTNSHADOW = 16
Private Const COLOR_GRAYTEXT = 17
Private Const COLOR_BTNTEXT = 18
Private Const COLOR_INACTIVECAPTIONTEXT = 19
Private Const COLOR_BTNHIGHLIGHT = 20

'#if(WINVER >= 0x0400)
Private Const COLOR_3DDKSHADOW = 21
Private Const COLOR_3DLIGHT = 22
Private Const COLOR_INFOTEXT = 23
Private Const COLOR_INFOBK = 24
Private Const COLOR_HOTLIGHT = 26
Private Const COLOR_GRADIENTACTIVECAPTION = 27
Private Const COLOR_GRADIENTINACTIVECAPTION = 28
'#if(WINVER >= 0x0501)
Private Const COLOR_MENUHILIGHT = 29
Private Const COLOR_MENUBAR = 30

' Windows Version
Private Declare Function GetVersion Lib "kernel32" () As Long
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA"
 (lpVersionInformation As OSVERSIONINFO) As Long
Private Type OSVERSIONINFO
   dwOSVersionInfoSize As Long
   dwMajorVersion As Long
   dwMinorVersion As Long
   dwBuildNumber As Long
   dwPlatformId As Long
   szCSDVersion As String * 128      '  Maintenance string for PSS usage
End Type

' Messages:
Private Const WM_ACTIVATE = &H6
Private Const WM_SIZE = &H5
Private Const WM_GETFONT = &H31
Private Const WM_STYLECHANGED = &H7D
Private Const WM_GETTEXT = &HD
Private Const WM_SETTEXT = &HC

'  WM_ACTIVATE state values
Private Const WA_INACTIVE = 0
Private Const WA_ACTIVE = 1
Private Const WA_CLICKACTIVE = 2

Private Const WM_NCHITTEST = &H84
Private Const WM_NCPAINT = &H85
Private Const WM_NCACTIVATE = &H86

Private Const WM_MDIACTIVATE = &H222
Private Const WM_MDIGETACTIVE = &H229
Public Property Let TextTransparent(ByVal bState As Boolean)
    m_bTextTransparent = bState
End Property
Public Property Get TextTransparent() As Boolean
    TextTransparent = m_bTextTransparent
End Property
Public Property Let CustomDraw(ByVal bState As Boolean)
    m_bCustomDraw = bState
End Property
Public Property Get CustomDraw() As Boolean
    CustomDraw = m_bCustomDraw
End Property

Public Property Get Color(ByVal eType As EGradTitleBarColors) As OLE_COLOR
    Color = m_oColor(eType)
End Property
Public Property Let Color(ByVal eType As EGradTitleBarColors, oColor As
 OLE_COLOR)
    If (m_oColor(eType) <> oColor) Then
        m_oColor(eType) = oColor
        If (GradhWnd <> 0) Then
            SendMessage GradhWnd, WM_NCPAINT, 0, 0
        End If
    End If
End Property

Public Property Get Picture() As StdPicture
   Set Picture = m_pic
End Property
Public Property Let Picture(oPic As StdPicture)
    ' Load a picture from a StdPicture object:
    pClearUp
    If (pbEnsurePicture()) Then
        Set m_pic = oPic
        If (Err.Number = 0) Then
            pbGetBitmapIntoDC
        End If
    End If
End Property
Private Function pbEnsurePicture() As Boolean
On Error Resume Next
    pbEnsurePicture = True
    If (m_pic Is Nothing) Then
        Set m_pic = New StdPicture
        If (Err.Number <> 0) Then
            pErr 3, "Unable to allocate memory for picture object."
            pbEnsurePicture = False
        Else
        End If
    End If
On Error GoTo 0
    Exit Function
End Function
Private Function pbGetBitmapIntoDC() As Boolean
Dim tB As BITMAP
Dim lhDC As Long, lHwnd As Long

    ' Make a DC to hold the picture bitmap which we can blt from:
    lHwnd = GetDesktopWindow()
    lhDC = GetDC(lHwnd)
    m_lHdc = CreateCompatibleDC(lhDC)
    ReleaseDC lHwnd, lhDC
    If (m_lHdc <> 0) Then
        ' Get size of bitmap:
        GetObjectAPI m_pic.handle, LenB(tB), tB
        m_lBitmapW = tB.bmWidth
        m_lBitmapH = tB.bmHeight
        
        ' Select bitmap into DC:
        m_lHBmpOld = SelectObject(m_lHdc, m_pic.handle)
        If (m_lHBmpOld <> 0) Then
            ' Select the palette into the DC:
            m_lhPalOld = SelectObject(m_lHdc, m_pic.hPal)
            pbGetBitmapIntoDC = True
        Else
            pClearUp
            pErr 2, "Unable to select bitmap into DC"
        End If
    Else
        pErr 1, "Unable to create compatible DC"
    End If
End Function
Private Sub pClearUp()
    ' Clear reference to the filename:
    m_sFileName = ""
    ' If we have a DC, then clear up:
    If (m_lHdc <> 0) Then
        ' Select the bitmap out of DC:
        If (m_lHBmpOld <> 0) Then
            SelectObject m_lHdc, m_lHBmpOld
            ' The original bitmap does not have to deleted because it is owned
             by m_pic
        End If
        ' Select the palette out of the DC:
        If (m_lhPalOld <> 0) Then
            SelectObject m_lHdc, m_lhPalOld
            ' The original palette does not have to deleted because it is owned
             by m_pic
        End If
        ' Remove the DC:
        DeleteObject m_lHdc
    End If
End Sub
Private Sub pErr(lNumber As Long, sMsg As String)
    Err.Raise vbObjectError + 1048 + lNumber, App.EXEName & ".cTitleBar", sMsg
     & ", [" & lNumber & "]"
End Sub

Private Function GradientCallback(ByVal hwnd As Long, ByVal wMsg As Long, ByVal
 wParam As Long, ByVal lParam As Long) As Long

Dim OldBMP As Long, NewBMP As Long
Dim rcWnd As RECT

   Select Case wMsg
   Case WM_NCACTIVATE, WM_MDIACTIVATE
       'Debug.Print "ACTIVATE"
      GetWindowRect GradhWnd, rcWnd

      'Create memory DC to draw the titlebar in.
      tmpDC = GetWindowDC(GradhWnd)
      DrawDC = CreateCompatibleDC(tmpDC)
      NewBMP = CreateCompatibleBitmap(tmpDC, rcWnd.Right - rcWnd.Left, 50)
      OldBMP = SelectObject(DrawDC, NewBMP)
      With rcWnd
         hRgn = CreateRectRgn(.Left, .Top, .Right, .Bottom)
         SelectClipRgn tmpDC, hRgn
         OffsetClipRgn tmpDC, -.Left, -.Top
      End With
      'Find out what color the titlebar needs
      'to be...
      If wParam And GetParent(GradhWnd) = 0 Then
         DrawGradient TranslateColor(Color(eActiveStartColor)),
          TranslateColor(Color(eActiveEndColor)), True
      ElseIf wParam = GradhWnd And GetParent(GradhWnd) <> 0 Then
         DrawGradient TranslateColor(Color(einActivestartcolor)),
          TranslateColor(Color(eInactiveEndColor)), False
      ElseIf SendMessage(GetParent(GradhWnd), WM_MDIGETACTIVE, 0, 0) = GradhWnd
       Then
         DrawGradient TranslateColor(Color(eActiveStartColor)),
          TranslateColor(Color(eActiveEndColor)), True
      Else
         DrawGradient TranslateColor(Color(einActivestartcolor)),
          TranslateColor(Color(eInactiveEndColor)), False
      End If
      'Cleanup
      SelectObject DrawDC, OldBMP
      DeleteObject NewBMP
      DeleteDC DrawDC
      
      OffsetClipRgn tmpDC, rcWnd.Left, rcWnd.Top
      GetClipRgn tmpDC, hRgn
      ReleaseDC GradhWnd, tmpDC
      DeleteObject hRgn
      tmpDC = 0
      GradientCallback = 1

   Case WM_NCPAINT
  
      ' Debug.Print "NCPAINT"
  
     'Basically same as above.
      GetWindowRect GradhWnd, rcWnd
      tmpDC = GetWindowDC(GradhWnd)
      DrawDC = CreateCompatibleDC(tmpDC)
      NewBMP = CreateCompatibleBitmap(tmpDC, rcWnd.Right - rcWnd.Left, 50)
      OldBMP = SelectObject(DrawDC, NewBMP)
      With rcWnd
         hRgn = CreateRectRgn(.Left, .Top, .Right, .Bottom)
         SelectClipRgn tmpDC, hRgn
         OffsetClipRgn tmpDC, -.Left, -.Top
      End With
      'Get the color to paint the caption with.
      If GetActiveWindow() = GradhWnd Then
         DrawGradient TranslateColor(Color(eActiveStartColor)),
          TranslateColor(Color(eActiveEndColor)), True
      ElseIf SendMessage(GetParent(GradhWnd), WM_MDIGETACTIVE, 0, 0) = GradhWnd
       Then
         DrawGradient TranslateColor(Color(eActiveStartColor)),
          TranslateColor(Color(eActiveEndColor)), True
      Else
         DrawGradient TranslateColor(Color(einActivestartcolor)),
          TranslateColor(Color(eInactiveEndColor)), False
      End If
      'Cleanup
      SelectObject DrawDC, OldBMP
      DeleteObject NewBMP
      DeleteDC DrawDC
      OffsetClipRgn tmpDC, rcWnd.Left, rcWnd.Top
      GetClipRgn tmpDC, hRgn
     
      'Call the old proc. This will only
      'draw the titlebar's min/max/close buttons
      'because we told it not to do the rest (this
      'eliminates flicker.)
      GradientCallback = CallOldWindowProc(hwnd, WM_NCPAINT, hRgn, lParam)
      ReleaseDC GradhWnd, tmpDC
      DeleteObject hRgn
      tmpDC = 0

   Case WM_SIZE, WM_STYLECHANGED, WM_SETTEXT
      'Whoa, we need to paint the caption.
      If hwnd = GradhWnd Then SendMessage GradhWnd, WM_NCPAINT, 0, 0
   End Select

End Function

Public Sub RefreshTitleBar()
   If GradhWnd <> 0 Then
      SendMessage GradhWnd, WM_NCPAINT, 0, 0
   End If
End Sub

Public Sub GradientForm(frm As Object)

   If (m_bInSubClass) Then
      GradientReleaseForm
   End If
   
   GradhWnd = frm.hwnd
   GradIcon = frm.Icon
   
   If (TypeOf frm Is MDIForm) Then
      m_bMDI = True
   End If
   AttachMessage Me, GradhWnd, WM_NCPAINT
   AttachMessage Me, GradhWnd, WM_NCACTIVATE
   AttachMessage Me, GradhWnd, WM_MDIACTIVATE
   ' Check for change in form caption:
   AttachMessage Me, GradhWnd, WM_STYLECHANGED
   AttachMessage Me, GradhWnd, WM_SETTEXT
   
   m_bInSubClass = True
   
   GradientGetCapsFont

End Sub

Public Sub GradientReleaseForm()

   If (m_bInSubClass) Then
      DetachMessage Me, GradhWnd, WM_NCPAINT
      DetachMessage Me, GradhWnd, WM_NCACTIVATE
      DetachMessage Me, GradhWnd, WM_MDIACTIVATE
      DetachMessage Me, GradhWnd, WM_STYLECHANGED
      DetachMessage Me, GradhWnd, WM_SETTEXT
      GradhWnd = 0
   End If

End Sub

Private Function DrawGradient( _
      ByVal Color1 As Long, _
      ByVal Color2 As Long, _
      ByVal bActive As Boolean _
   ) As Long

Dim i As Integer
Dim DestWidth As Long, DestHeight As Long
Dim StartPnt As Integer, EndPnt As Integer
Dim PixelStep As Long, XBorder As Long
Dim WndRect As RECT
Dim OldFont As Long
Dim fText As String
Dim iBmTop As Long
Dim lS As Long
Dim lBtnWidth As Long
Dim bDoDefault As Boolean
Dim bShowBitmap As Boolean

On Error Resume Next

   GetWindowRect GradhWnd, WndRect
   With WndRect
      DestWidth = .Right - .Left
   End With
   
   bShowBitmap = ((m_lHdc <> 0) And (DestWidth > (m_lBitmapW * 4)))
      
   'Get height of caption bar
   lS = GetWindowLong(GradhWnd, GWL_EXSTYLE)
   If ((lS And WS_EX_TOOLWINDOW) = WS_EX_TOOLWINDOW) Then
       DestHeight = GetSystemMetrics(SM_CYSMCAPTION)
   Else
       DestHeight = GetSystemMetrics(SM_CYCAPTION)
   End If
   'Get the text of the form's caption
   fText = Space$(255)
   GetWindowText GradhWnd, fText, 255
   fText = Trim$(fText)
   'Get the width of the border
   XBorder = GetSystemMetrics(SM_CXFRAME)
   'The width of the area we need to paint:
   DestWidth = DestWidth - (XBorder * 2) + 6
   lS = GetWindowLong(GradhWnd, GWL_STYLE)
   If ((lS And WS_MINIMIZEBOX) = WS_MINIMIZEBOX) Or ((lS And WS_MAXIMIZEBOX) =
    WS_MAXIMIZEBOX) Then
       lBtnWidth = lBtnWidth + (GetSystemMetrics(SM_CXSMSIZE)) * 2
   End If
   If ((lS And WS_SYSMENU) = WS_SYSMENU) Then
       lBtnWidth = lBtnWidth + (GetSystemMetrics(SM_CXSMSIZE))
   End If
   If (lBtnWidth <> 0) Then lBtnWidth = lBtnWidth + 1
   DestWidth = DestWidth - lBtnWidth
   
   
   'Where the painting begins:
   StartPnt = XBorder
   'Where the painting ends:
   EndPnt = XBorder + DestWidth - 4
   
   'How many steps do we need to
   'paint the titlebar?
   If (bShowBitmap) Then
       PixelStep = DestWidth - 16 - m_lBitmapW
   Else
       PixelStep = DestWidth \ 8
   End If
   ReDim Colors(PixelStep) As Long
   'Create gradient colors in the array
   GradateColors Colors(), Color1, Color2
   
   Dim rct As RECT
   Dim hBr As Long
   
   With rct
      .Top = XBorder
      .Left = XBorder
      .Right = XBorder + (DestWidth \ PixelStep)
      .Bottom = XBorder + DestHeight - 1
      bDoDefault = True
      If (m_bCustomDraw) Then
          RaiseEvent CustomDraw(eDrawBackground, bDoDefault, DrawDC, XBorder,
           XBorder, EndPnt - XBorder, DestHeight - 1, bActive)
      End If
      If (bDoDefault) Then
          If (bShowBitmap) Then
              ' the first box is going to extend all the way from
              ' the icon to the end of the bitmap, and the gradient
              ' is only doing to start afterwards:
              rct.Right = rct.Left + 16 + m_lBitmapW
          End If
          hBr = CreateSolidBrush(Colors(0))
          FillRect DrawDC, rct, hBr
          DeleteObject hBr
          If (bShowBitmap) Then
              rct.Left = rct.Right
              rct.Right = rct.Left + (DestWidth \ PixelStep)
          End If
          For i = 1 To PixelStep - 1
           'Paint the titlebar in increments, increasing
           'the color index with each iteration.
           hBr = CreateSolidBrush(Colors(i))
           FillRect DrawDC, rct, hBr
           'Cleanup
           DeleteObject hBr
           'Prepare for the next iteration
           OffsetRect rct, (DestWidth \ PixelStep), 0
           If i = PixelStep - 2 Then .Right = EndPnt
          Next
      End If
      
      bDoDefault = True
      If (m_bCustomDraw) Then
          RaiseEvent CustomDraw(eDrawIcon, bDoDefault, DrawDC, XBorder,
           XBorder, EndPnt - XBorder, DestHeight - 1, bActive)
      End If
      If (bDoDefault) Then
          If GradIcon <> 0 Then 'Paint the icon
           'Move the caption text's start point over
           'to make room for the icon
           .Left = XBorder + GetSystemMetrics(SM_CXSMSIZE) + 2
           DrawIconEx DrawDC, XBorder + 1, XBorder + 1, GradIcon,
            GetSystemMetrics(SM_CXSMSIZE) - 2, GetSystemMetrics(SM_CYSMSIZE) -
            2, ByVal 0&, ByVal 0&, DI_NORMAL
          Else
           'No icon
           .Left = XBorder
          End If
      End If
   
      'If we have a picture:
      If (bShowBitmap) Then
         ' Draw it and shift left & right
         iBmTop = 2 + .Top + ((.Bottom - .Top - m_lBitmapH) \ 2)
         BitBlt DrawDC, .Left, iBmTop, m_lBitmapW, m_lBitmapH, m_lHdc, 0, 0,
          SRCCOPY
         .Left = .Left + m_lBitmapW + 2
      Else
         .Left = .Left + 2
      End If
   
      bDoDefault = True
      If (m_bCustomDraw) Then
         RaiseEvent CustomDraw(eDrawText, bDoDefault, DrawDC, XBorder, XBorder,
          EndPnt - XBorder - 10, DestHeight - 1, bActive)
      End If
      If (bDoDefault) Then
         'If getting the caption font failed, use the font
         'from the gradient caption form.
         If CaptionFont.lfHeight = 0 And tmpGradFont = 0 Then
            tmpGradFont = SendMessage(GradhWnd, WM_GETFONT, 0, 0)
         ElseIf tmpGradFont = 0 Then
            tmpGradFont = CreateFontIndirect(CaptionFont)
         End If
         OldFont = SelectObject(DrawDC, tmpGradFont)
         'This is like setting FontTransparent on a Form to True:
         SetBkMode DrawDC, 1
         'Use a white caption, since the background is black
         'on the left side
         If (bActive) Then
            SetTextColor DrawDC, TranslateColor(m_oColor(eActiveText)) '
             &HFFFFFF 'RGB(255, 255, 255)
         Else
            SetTextColor DrawDC, TranslateColor(m_oColor(eInActiveText))
             '&HC0C0C0 'RGB(128, 128, 128)
         End If
         .Right = .Right - 10
         'Draw the caption text
         If (m_bTextTransparent) Then
            SetBkMode DrawDC, TRANSPARENT
         Else
            SetBkMode DrawDC, OPAQUE
            If (bActive) Then
                SetBkColor DrawDC, TranslateColor(m_oColor(eActiveStartColor))
            Else
                SetBkColor DrawDC, TranslateColor(m_oColor(einActivestartcolor))
            End If
         End If
         DrawText DrawDC, fText, Len(fText) - 1, rct, DT_SINGLELINE Or
          DT_END_ELLIPSIS Or DT_VCENTER
         'Cleanup
         SelectObject DrawDC, OldFont
         DeleteObject tmpGradFont
         tmpGradFont = 0
      End If
   
      .Left = XBorder
      .Right = .Right + 12
      If tmpDC <> 0 Then
         'Blit our work from the memory DC to the form's
         'window DC to finish the job.
         BitBlt tmpDC, .Left, .Top, .Right - .Left - 10, .Bottom - .Top,
          DrawDC, .Left, .Top, vbSrcCopy
         'Tell windows that we already painted most of
         'the titlebar.
         ExcludeClipRect tmpDC, XBorder, XBorder, .Right - .Left - 7, .Bottom -
          .Top + 4
   
      End If
   
   End With

End Function

Private Sub GradateColors(Colors() As Long, ByVal Color1 As Long, ByVal Color2
 As Long)

'Alright, I admit -- this routine was
'taken from a VBPJ issue a few months back.

Dim i As Integer
Dim dblR As Double, dblG As Double, dblB As Double
Dim addR As Double, addG As Double, addB As Double
Dim bckR As Double, bckG As Double, bckB As Double

   dblR = CDbl(Color1 And &HFF)
   dblG = CDbl(Color1 And &HFF00&) / 255
   dblB = CDbl(Color1 And &HFF0000) / &HFF00&
   bckR = CDbl(Color2 And &HFF&)
   bckG = CDbl(Color2 And &HFF00&) / 255
   bckB = CDbl(Color2 And &HFF0000) / &HFF00&
   
   addR = (bckR - dblR) / UBound(Colors)
   addG = (bckG - dblG) / UBound(Colors)
   addB = (bckB - dblB) / UBound(Colors)
   
   For i = 0 To UBound(Colors)
      dblR = dblR + addR
      dblG = dblG + addG
      dblB = dblB + addB
      If dblR > 255 Then dblR = 255
      If dblG > 255 Then dblG = 255
      If dblB > 255 Then dblB = 255
      If dblR < 0 Then dblR = 0
      If dblG < 0 Then dblG = 0
      If dblG < 0 Then dblB = 0
      Colors(i) = RGB(dblR, dblG, dblB)
   Next

End Sub

Private Sub GradientGetCapsFont()

'Tries to retrieve the Windows caption font
'in the current Appearance scheme. Doesn't
'seem to work all the time, so if anyone knows
'why I'd appreciate being told.

Dim NCM As NONCLIENTMETRICS
Dim lfNew As LOGFONT

   NCM.cbSize = Len(NCM)
   Call SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, NCM, 0)
   
   If NCM.iCaptionHeight = 0 Then
      CaptionFont.lfHeight = 0
   Else
      CaptionFont = NCM.lfCaptionFont
   End If

End Sub
Private Function TranslateColor(ByVal clr As OLE_COLOR, _
                        Optional hPal As Long = 0) As Long
    If OleTranslateColor(clr, hPal, TranslateColor) Then
        TranslateColor = -1 'CLR_INVALID
    End If
End Function

Private Sub Class_Initialize()
   m_bCustomDraw = True
   m_bTextTransparent = True
   m_oColor(eActiveStartColor) = 0
   m_oColor(einActivestartcolor) = 0
   If (GetVersion() And &HFFFF) >= 4 Then
      m_oColor(eActiveEndColor) = GetSysColor(COLOR_GRADIENTACTIVECAPTION)
      m_oColor(eInactiveEndColor) = GetSysColor(COLOR_GRADIENTINACTIVECAPTION)
   Else
      m_oColor(eActiveEndColor) = vbActiveTitleBar
      m_oColor(eInactiveEndColor) = vbInactiveTitleBar
   End If
   m_oColor(eActiveText) = &HFFFFFF
   m_oColor(eInActiveText) = &HC0C0C0
   
End Sub

Private Sub Class_Terminate()
   GradientReleaseForm
End Sub

Private Property Let ISubclass_MsgResponse(ByVal RHS As SSubTimer.EMsgResponse)
   m_emr = RHS
End Property

Private Property Get ISubclass_MsgResponse() As SSubTimer.EMsgResponse
   'Debug.Print "Get MsgResponse", CurrentMessage
   Select Case CurrentMessage
   Case WM_NCACTIVATE, WM_MDIACTIVATE
     'This will cause a slight flicker because we
     'let Windows paint the caption before we do.
     'We don't let this happen in the WM_NCPAINT message,
     'which is called more often than NCACTIVATE.
      m_emr = emrPreprocess
      
   Case WM_NCPAINT
     'Call the old proc. This will only
     'draw the titlebar's min/max/close buttons
     'because we told it not to do the rest (this
     'eliminates flicker.
     m_emr = emrConsume
   
   Case Else
      m_emr = emrPostProcess
   End Select
   
   ISubclass_MsgResponse = m_emr
End Property

Private Function ISubclass_WindowProc(ByVal hwnd As Long, ByVal iMsg As Long,
 ByVal wParam As Long, ByVal lParam As Long) As Long
   'Debug.Print "Get Msg" & vbCrLf
   ISubclass_WindowProc = GradientCallback(hwnd, iMsg, wParam, lParam)
End Function