Jaafar Tribak

Well-known Member
Joined
Dec 5, 2002
Messages
8,114
Office Version
  1. 2016
Platform
  1. Windows
Hi dear forum,

As you know, the MsForms Multipage control doesn't offer a built-in functionality for changing the colors of individual tabs. I have seen many requests for this functionality over the years and the usual workaround has always been to add some helper buttons\labels , to change the tabs style to fmTabStyleButtons or to dynamically change the tab caption text of the currently active tab.

Here, I am resorting to a more radical approach which consists of handling the WM_PAINT message and doing our custom drawing of choice from scratch.

In order to change the font and\or Back color of a given individual tab, all we need to do is call the following routine :
VBA Code:
Sub PaintTab( _
    ByVal Page As Object, _
    Optional ByVal Paint As Boolean, _
    Optional ByVal FontColor As Variant, _
    Optional ByVal BackColor As Variant, _
    Optional ByVal ExtendTabColorToWholePage As Boolean, _
    Optional ByVal TabShape As eTabShape = Flat)

The arguments are self-explanatory. The last eTabShape argument offers 3 different possible shapes for the Tabs, namely Flat = 0 , Bumped = 1 and Trapezoid = 2.

Issues:
Due to the fact that the code subclasses the userform, this method will only work in Modal UserForms... Also, careful error handling in any other existing code is advised (Actually, automatic error handling is actually built-in in the "SafeExit routine", but still, propper defensive error handling is recommended when using this code just in case)

Demo workbook: MultiPageTabPainting.xls








1-API code in a Standard Module:
VBA Code:
Option Explicit

Public Enum eTabShape
    Flat = 0
    Bumped = 1
    Trapezoid = 2
End Enum

Private Type POINTAPI
    x As Long
    Y As Long
End Type

Private Type POINTF
   x As Single
   Y As Single
End Type

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Type PAINTSTRUCT
    #If Win64 Then
        hdc As LongLong
    #Else
        hdc As Long
    #End If
    fErase As Long
    rcPaint As RECT
    fRestore As Long
    fIncUpdate As Long
    rgbReserved(0 To 31) As Byte
End Type

Private Type uPicDesc
    size As Long
    Type As Long
    #If Win64 Then
        hPic As LongLong
        hPal As LongLong
    #Else
       hPic As Long
       hPal As Long
    #End If
End Type

Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(0 To 7) As Byte
End Type

Private Type LOGPEN
    lopnStyle As Long
    lopnWidth As POINTAPI
    lopnColor As Long
End Type

Private Type CWPSTRUCT
    #If Win64 Then
        lParam As LongLong
        wParam As LongLong
        message As Long
        hwnd As LongLong
    #Else
        lParam As Long
        wParam As Long
        message As Long
        hwnd As Long
    #End If
End Type

Private Type GdiplusStartupInput
   GdiplusVersion As Long
  #If Win64 Then
        DebugEventCallback As LongLong
        SuppressBackgroundThread As LongLong
  #Else
        DebugEventCallback As Long
        SuppressBackgroundThread As Long
  #End If
   SuppressExternalCodecs As Long
End Type

#If VBA7 Then
    Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    Private Declare PtrSafe Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (dest As Any, ByVal numBytes As LongPtr)
    Private Declare PtrSafe Function DefSubclassProc Lib "comctl32.dll" Alias "#413" (ByVal hwnd As LongPtr, ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
    Private Declare PtrSafe Function SetWindowSubclass Lib "comctl32.dll" Alias "#410" (ByVal hwnd As LongPtr, ByVal pfnSubclass As LongPtr, ByVal uIdSubclass As LongPtr, Optional ByVal dwRefData As LongPtr) As LongPtr
    Private Declare PtrSafe Function RemoveWindowSubclass Lib "comctl32.dll" Alias "#412" (ByVal hwnd As LongPtr, ByVal pfnSubclass As LongPtr, ByVal uIdSubclass As LongPtr) As LongPtr
    Private Declare PtrSafe Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As LongPtr, ByVal wFlag As Long) As LongPtr
    Private Declare PtrSafe Function SetProp Lib "user32" Alias "SetPropA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal hData As LongPtr) As Long
    Private Declare PtrSafe Function GetProp Lib "user32" Alias "GetPropA" (ByVal hwnd As LongPtr, ByVal lpString As String) As LongPtr
    Private Declare PtrSafe Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hwnd As LongPtr, ByVal lpString As String) As LongPtr
    Private Declare PtrSafe Function GetWindowRect Lib "user32" (ByVal hwnd As LongPtr, lpRect As RECT) As Long
    Private Declare PtrSafe Function GetClientRect Lib "user32" (ByVal hwnd As LongPtr, lpRect As RECT) As Long
    Private Declare PtrSafe Function ScreenToClient Lib "user32" (ByVal hwnd As LongPtr, lpPoint As POINTAPI) As Long
    Private Declare PtrSafe Function BeginPaint Lib "user32" (ByVal hwnd As LongPtr, lpPaint As PAINTSTRUCT) As LongPtr
    Private Declare PtrSafe Function EndPaint Lib "user32" (ByVal hwnd As LongPtr, lpPaint As PAINTSTRUCT) As Long
    Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
    Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hdc As LongPtr) As Long
    Private Declare PtrSafe Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As LongPtr, ByVal nWidth As Long, ByVal nHeight As Long) As LongPtr
    Private Declare PtrSafe Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As LongPtr) As LongPtr
    Private Declare PtrSafe Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As LongPtr
    Private Declare PtrSafe Function CreatePenIndirect Lib "gdi32" (lpLogPen As LOGPEN) As LongPtr
    Private Declare PtrSafe Function GetStockObject Lib "gdi32" (ByVal nIndex As Long) As LongPtr
    Private Declare PtrSafe Function SelectObject Lib "gdi32" (ByVal hdc As LongPtr, ByVal hObject As LongPtr) As LongPtr
    Private Declare PtrSafe Function DeleteDC Lib "gdi32" (ByVal hdc As LongPtr) As Long
    Private Declare PtrSafe Function DeleteObject Lib "gdi32" (ByVal hObject As LongPtr) As Long
    Private Declare PtrSafe Function SetBkMode Lib "gdi32" (ByVal hdc As LongPtr, ByVal nBkMode As Long) As Long
    Private Declare PtrSafe Function SetTextColor Lib "gdi32" (ByVal hdc As LongPtr, ByVal crColor As Long) As Long
    Private Declare PtrSafe Function SetRect Lib "user32" (lpRect As RECT, ByVal x1 As Long, ByVal y1 As Long, ByVal x2 As Long, ByVal y2 As Long) As Long
    Private Declare PtrSafe Function BitBlt Lib "gdi32" (ByVal hDestDC As LongPtr, ByVal x As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As LongPtr, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
    Private Declare PtrSafe Function FloodFill Lib "gdi32" (ByVal hdc As LongPtr, ByVal x As Long, ByVal Y As Long, ByVal crColor As Long) As Long
    Private Declare PtrSafe Function FillRect Lib "user32" (ByVal hdc As LongPtr, lpRect As RECT, ByVal hBrush As LongPtr) As Long
    Private Declare PtrSafe Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hdc As LongPtr, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long) As Long
    Private Declare PtrSafe Function DrawFocusRect Lib "user32" (ByVal hdc As LongPtr, lpRect As RECT) As Long
    Private Declare PtrSafe Function MoveToEx Lib "gdi32" (ByVal hdc As LongPtr, ByVal x As Long, ByVal Y As Long, lpPoint As POINTAPI) As Long
    Private Declare PtrSafe Function LineTo Lib "gdi32" (ByVal hdc As LongPtr, ByVal x As Long, ByVal Y As Long) As Long
    Private Declare PtrSafe Function TranslateColor Lib "oleAut32.dll" Alias "OleTranslateColor" (ByVal clr As OLE_COLOR, ByVal palet As Long, Col As Long) As Long
    Private Declare PtrSafe Function OleCreatePictureIndirect Lib "oleAut32.dll" (PicDesc As uPicDesc, RefIID As GUID, ByVal fPictureOwnsHandle As Long, iPic As IPicture) As Long
    Private Declare PtrSafe Function CopyImage Lib "user32" (ByVal handle As LongPtr, ByVal un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As LongPtr
    Private Declare PtrSafe Function RedrawWindow Lib "user32" (ByVal hwnd As LongPtr, lprcUpdate As RECT, ByVal hrgnUpdate As LongPtr, ByVal fuRedraw As Long) As Long
    Private Declare PtrSafe Function UpdateWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
    Private Declare PtrSafe Function GetParent Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
    Private Declare PtrSafe Function GetSysColor Lib "user32.dll" (ByVal nIndex As Long) As Long
    Private Declare PtrSafe Function CreateRectRgn Lib "gdi32" (ByVal x1 As Long, ByVal y1 As Long, ByVal x2 As Long, ByVal y2 As Long) As LongPtr
    Private Declare PtrSafe Function FillRgn Lib "gdi32" (ByVal hdc As LongPtr, ByVal hRgn As LongPtr, ByVal hBrush As LongPtr) As Long
    Private Declare PtrSafe Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As LongPtr
    Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long
    Private Declare PtrSafe Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As LongPtr, ByVal hmod As LongPtr, ByVal dwThreadId As Long) As LongPtr
    Private Declare PtrSafe Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As LongPtr) As Long
    Private Declare PtrSafe Function CallNextHookEx Lib "user32" (ByVal hHook As LongPtr, ByVal ncode As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr
    Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As LongPtr, lpdwProcessId As Long) As Long
    Private Declare PtrSafe Function GetFocus Lib "user32" () As LongPtr
    Private Declare PtrSafe Function GdiplusStartup Lib "gdiplus" (Token As Long, inputbuf As GdiplusStartupInput, Optional ByVal outputbuf As Long = 0) As Long
    Private Declare PtrSafe Sub GdiplusShutdown Lib "gdiplus" (ByVal Token As Long)
    Private Declare PtrSafe Function GdipCreateFromHDC Lib "gdiplus" (ByVal hdc As LongPtr, hGraphics As LongPtr) As Long
    Private Declare PtrSafe Function GdipSetSmoothingMode Lib "gdiplus" (ByVal graphics As LongPtr, ByVal SmoothingMd As Long) As Long
    Private Declare PtrSafe Function GdipCreatePen1 Lib "gdiplus" (ByVal color As Long, ByVal Width As Single, ByVal unit As Long, pen As LongPtr) As Long
    Private Declare PtrSafe Function GdipSetPenColor Lib "gdiplus" (ByVal pen As LongPtr, ByVal argb As Long) As Long
    Private Declare PtrSafe Function GdipSetPenWidth Lib "gdiplus" (ByVal pen As LongPtr, ByVal Width As Single) As Long
    Private Declare PtrSafe Function GdipSetPenDashStyle Lib "gdiplus" (ByVal pen As LongPtr, ByVal dStyle As Long) As Long
    Private Declare PtrSafe Function GdipDrawLine Lib "gdiplus" (ByVal graphics As LongPtr, ByVal pen As LongPtr, ByVal x1 As Single, ByVal y1 As Single, ByVal x2 As Single, ByVal y2 As Single) As Long
    Private Declare PtrSafe Function GdipDrawRectangle Lib "gdiplus" (ByVal graphics As LongPtr, ByVal pen As LongPtr, ByVal x As Single, ByVal Y As Single, ByVal Width As Single, ByVal Height As Single) As Long
    Private Declare PtrSafe Function GdipCreateSolidFill Lib "gdiplus" (ByVal argb As Long, brush As LongPtr) As Long
    Private Declare PtrSafe Function GdipDrawPolygon Lib "gdiplus" (ByVal graphics As LongPtr, ByVal pen As LongPtr, Points As POINTF, ByVal count As Long) As Long
    Private Declare PtrSafe Function GdipFillPolygon Lib "gdiplus" (ByVal graphics As LongPtr, ByVal brush As LongPtr, Points As POINTF, ByVal count As Long, ByVal FillMd As Long) As Long
    Private Declare PtrSafe Function GdipDeleteGraphics Lib "GdiPlus.dll" (ByVal mGraphics As LongPtr) As Long
    Private Declare PtrSafe Function GdipDeleteBrush Lib "gdiplus" (ByVal brush As LongPtr) As Long
    Private Declare PtrSafe Function GdipDeletePen Lib "gdiplus" (ByVal pen As LongPtr) As Long
  
    Private hHook As LongPtr
#Else
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    Private Declare Sub ZeroMemory Lib "KERNEL32" Alias "RtlZeroMemory" (dest As Any, ByVal numBytes As Long)
    Private Declare Function DefSubclassProc Lib "comctl32.dll" Alias "#413" (ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Private Declare Function SetWindowSubclass Lib "comctl32.dll" Alias "#410" (ByVal hwnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long, Optional ByVal dwRefData As Long) As Long
    Private Declare Function RemoveWindowSubclass Lib "comctl32.dll" Alias "#412" (ByVal hwnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long) As Long
    Private Declare Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As Long, ByVal wFlag As Long) 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 GetProp Lib "user32" Alias "GetPropA" (ByVal hwnd As Long, ByVal lpString As String) As Long
    Private Declare Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hwnd As Long, ByVal lpString As String) As Long
    Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
    Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
    Private Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
    Private Declare Function BeginPaint Lib "user32" (ByVal hwnd As Long, lpPaint As PAINTSTRUCT) As Long
    Private Declare Function EndPaint Lib "user32" (ByVal hwnd As Long, lpPaint As PAINTSTRUCT) As Long
    Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
    Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc 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 CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
    Private Declare Function CreatePenIndirect Lib "gdi32" (lpLogPen As LOGPEN) As Long
    Private Declare Function GetStockObject Lib "gdi32" (ByVal nIndex As Long) As Long
    Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject 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 SetBkMode Lib "gdi32" (ByVal hdc As Long, ByVal nBkMode As Long) As Long
    Private Declare Function SetTextColor Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long) As Long
    Private Declare Function SetRect Lib "user32" (lpRect As RECT, ByVal x1 As Long, ByVal y1 As Long, ByVal x2 As Long, ByVal y2 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 Declare Function FloodFill Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal crColor As Long) As Long
    Private Declare Function FillRect Lib "user32" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) 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 DrawFocusRect Lib "user32" (ByVal hdc As Long, lpRect As RECT) As Long
    Private Declare Function MoveToEx Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, lpPoint As POINTAPI) As Long
    Private Declare Function LineTo Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long) As Long
    Private Declare Function TranslateColor Lib "oleAut32.dll" Alias "OleTranslateColor" (ByVal clr As OLE_COLOR, ByVal palet As Long, Col As Long) As Long
    Private Declare Function OleCreatePictureIndirect Lib "oleAut32.dll" (PicDesc As uPicDesc, RefIID As GUID, ByVal fPictureOwnsHandle As Long, iPic As IPicture) 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 RedrawWindow Lib "user32" (ByVal hwnd As Long, lprcUpdate As RECT, ByVal hrgnUpdate As Long, ByVal fuRedraw As Long) As Long
    Private Declare Function UpdateWindow Lib "user32" (ByVal hwnd As Long) As Long
    Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
    Private Declare Function GetSysColor Lib "user32.dll" (ByVal nIndex As Long) 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 FillRgn Lib "gdi32" (ByVal hdc As Long, ByVal hRgn As Long, ByVal hBrush As Long) As Long
    Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) 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 SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
    Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
    Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
    Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
    Private Declare Function GetFocus Lib "user32" () As Long
    Private Declare Function GdiplusStartup Lib "gdiplus" (Token As Long, inputbuf As GdiplusStartupInput, Optional ByVal outputbuf As Long = 0) As Long
    Private Declare Sub GdiplusShutdown Lib "gdiplus" (ByVal Token As Long)
    Private Declare Function GdipCreateFromHDC Lib "gdiplus" (ByVal hdc As Long, hGraphics As Long) As Long
    Private Declare Function GdipSetSmoothingMode Lib "gdiplus" (ByVal graphics As Long, ByVal SmoothingMd As Long) As Long
    Private Declare Function GdipCreatePen1 Lib "gdiplus" (ByVal color As Long, ByVal Width As Single, ByVal unit As Long, pen As Long) As Long
    Private Declare Function GdipSetPenColor Lib "gdiplus" (ByVal pen As Long, ByVal argb As Long) As Long
    Private Declare Function GdipSetPenWidth Lib "gdiplus" (ByVal pen As Long, ByVal Width As Single) As Long
    Private Declare Function GdipSetPenDashStyle Lib "gdiplus" (ByVal pen As Long, ByVal dStyle As Long) As Long
    Private Declare Function GdipDrawLine Lib "gdiplus" (ByVal graphics As Long, ByVal pen As Long, ByVal x1 As Single, ByVal y1 As Single, ByVal x2 As Single, ByVal y2 As Single) As Long
    Private Declare Function GdipDrawRectangle Lib "gdiplus" (ByVal graphics As Long, ByVal pen As Long, ByVal X As Single, ByVal Y As Single, ByVal Width As Single, ByVal Height As Single) As Long
    Private Declare Function GdipCreateSolidFill Lib "gdiplus" (ByVal argb As Long, brush As Long) As Long
    Private Declare Function GdipDrawPolygon Lib "gdiplus" (ByVal graphics As Long, ByVal pen As Long, Points As POINTF, ByVal count As Long) As Long
    Private Declare Function GdipFillPolygon Lib "gdiplus" (ByVal graphics As Long, ByVal brush As Long, Points As POINTF, ByVal count As Long, ByVal FillMd As Long) As Long
    Private Declare Function GdipDeleteGraphics Lib "GdiPlus.dll" (ByVal mGraphics As Long) As Long
    Private Declare Function GdipDeleteBrush Lib "gdiplus" (ByVal brush As Long) As Long
    Private Declare Function GdipDeletePen Lib "gdiplus" (ByVal pen As Long) As Long
  
    Private hHook As Long
#End If
  


Public Sub PaintTab( _
    ByVal Page As Object, _
    Optional ByVal Paint As Boolean, _
    Optional ByVal FontColor As Variant, _
    Optional ByVal BackColor As Variant, _
    Optional ByVal ExtendTabColorToWholePage As Boolean, _
    Optional ByVal TabShape As eTabShape = Flat)

    #If Win64 Then
        Dim hwnd As LongLong
    #Else
        Dim hwnd As Long
    #End If
  
    Const WH_CALLWNDPROC = 4

    Dim oMultiPage As Control
  
    Set oMultiPage = Page.Parent
    hwnd = oMultiPage.[_GethWnd]
  
    If IsMissing(FontColor) Then FontColor = 0
    If IsMissing(BackColor) Then
        BackColor = oMultiPage.BackColor
        Call TranslateColor(oMultiPage.BackColor, 0, BackColor)
    End If

    Page.Tag = FontColor & "||" & BackColor & "||" & ExtendTabColorToWholePage & "||" & TabShape & "||" & Paint
  
    If GetProp(hwnd, "MultiPageSubclassed") = 0 Then
        If hHook = 0 Then
            hHook = SetWindowsHookEx(WH_CALLWNDPROC, AddressOf SafeSubclassingHookFunction, _
            GetModuleHandle(vbNullString), GetWindowThreadProcessId(Application.hwnd, 0))
        End If
        Call SetProp(hwnd, "MultiPageSubclassed", 1)
        Call SetWindowSubclass(hwnd, AddressOf WndProc, ObjPtr(oMultiPage), 0)
    End If
  
End Sub



'_______________________________PRIVATE ROUTINES__________________________________________

#If Win64 Then
    Private Function WndProc( _
            ByVal hwnd As LongLong, _
            ByVal wMsg As Long, _
            ByVal wParam As LongLong, _
            ByVal lParam As LongLong, _
            ByVal uIdSubclass As Object, _
            ByVal This As LongLong) As LongLong
#Else
    Private Function WndProc( _
            ByVal hwnd As Long, _
            ByVal wMsg As Long, _
            ByVal wParam As Long, _
            ByVal lParam As Long, _
            ByVal uIdSubclass As Object, _
            ByVal This As Long) As Long
#End If

    Const WM_DESTROY = &H2
    Const WM_PAINT As Long = &HF&
    Const RDW_INVALIDATE = &H1
  
    Static oPrevPage As Object
    Static tPrevTabRect As RECT
  
    Dim tPS As PAINTSTRUCT, tTabRect As RECT, tCurTabRect As RECT
    Dim p1 As POINTAPI, p2 As POINTAPI
    Dim oPage As Object

    Select Case wMsg
  
        Case WM_PAINT
            Call BeginPaint(hwnd, tPS)
            Call DrawMultiPageBackGround(uIdSubclass)
            For Each oPage In uIdSubclass.Pages
                tTabRect = GetPageRect(oPage, hwnd)
                If oPage Is uIdSubclass.SelectedItem Then
                    If Not oPrevPage Is Nothing Then
                        If Not oPrevPage Is uIdSubclass.SelectedItem Then
                            With tPrevTabRect
                                p1.x = .Left: p1.Y = .Top - 10
                                p2.x = .Right: p2.Y = .Bottom
                            End With
                            Call ScreenToClient(GetParent(hwnd), p1)
                            Call ScreenToClient(GetParent(hwnd), p2)
                            With tPrevTabRect
                                .Left = p1.x:     .Top = p1.Y
                                .Right = p2.x: .Bottom = p2.Y
                            End With
                            Call RedrawWindow(GetParent(hwnd), tPrevTabRect, 0, RDW_INVALIDATE)
                        End If
                    End If
                    Set oPrevPage = uIdSubclass.SelectedItem
                    tPrevTabRect = tTabRect
                    tCurTabRect = tTabRect
                End If

                If Len(oPage.Tag) Then
                    Call DrawTab(True, hwnd, oPage, VarPtr(tTabRect))
                    If oPage Is uIdSubclass.SelectedItem Then
                        Call DrawPageOutline(True, hwnd, oPage, VarPtr(tCurTabRect))
                    End If
                Else
                    Call DrawTab(False, hwnd, oPage, VarPtr(tTabRect))
                    If oPage Is uIdSubclass.SelectedItem Then
                        Call DrawPageOutline(False, hwnd, oPage, VarPtr(tCurTabRect))
                    End If
                End If
              
            Next oPage
            Call EndPaint(hwnd, tPS)
          
        Case WM_DESTROY
            Call UnhookWindowsHookEx(hHook)
            hHook = 0
            Call RemoveWindowSubclass(hwnd, WinProcAddr, ObjPtr(uIdSubclass))
            Call RemoveProp(hwnd, "MultiPageSubclassed")
          
    End Select
  
    WndProc = DefSubclassProc(hwnd, wMsg, wParam, lParam)

End Function


Private Sub DrawMultiPageBackGround(ByVal MultiPage As Object)

    #If Win64 Then
        Dim hwnd As LongLong
        Dim hdc As LongLong, hMemDC As LongLong, hMemBmp As LongLong, hOldBmp As LongLong
        Dim hBrush As LongLong, OldBrush As LongLong, hRegion As LongLong
    #Else
        Dim hwnd As Long
        Dim hdc As Long, hMemDC As Long, hMemBmp As Long, hOldBmp As Long
        Dim hBrush As Long, OldBrush As Long, hRegion As Long
    #End If

    Const SRCCOPY = &HCC0020
  
    Dim oMultiPage As Control
    Dim tWinRect As RECT
    Dim lWidth As Long, lHeight As Long, lBackColor As Long
  
  
    Set oMultiPage = MultiPage
    hwnd = oMultiPage.[_GethWnd]
    Call GetWindowRect(hwnd, tWinRect)
  
    lWidth = tWinRect.Right - tWinRect.Left
    lHeight = tWinRect.Bottom - tWinRect.Top
  
    hdc = GetDC(hwnd)
    hMemDC = CreateCompatibleDC(hdc)
    hMemBmp = CreateCompatibleBitmap(hdc, lWidth, lHeight)
    hOldBmp = SelectObject(hMemDC, hMemBmp)
    Call TranslateColor(MultiPage.BackColor, 0, lBackColor)
    hBrush = CreateSolidBrush(lBackColor)
    hRegion = CreateRectRgn(0, 0, lWidth, lHeight)
    OldBrush = SelectObject(hMemDC, hBrush)
    Call FillRgn(hMemDC, hRegion, hBrush)
    Call BitBlt(hdc, 0, 0, lWidth, lHeight, hMemDC, 0, 0, SRCCOPY)
  
    Call SelectObject(hMemDC, hOldBmp)
    Call SelectObject(hMemDC, OldBrush)
  
    Call DeleteDC(hMemDC)
    Call DeleteDC(hMemBmp)
    Call DeleteObject(hBrush)
    Call DeleteObject(hRegion)
    Call ReleaseDC(hwnd, hdc)

End Sub


#If Win64 Then
    Private Sub DrawTab(ByVal IsTagged As Boolean, ByVal hwnd As LongLong, ByVal Page As Object, ByVal pRect As LongLong)
        Dim hdc As LongLong, hMemDC As LongLong, hMemBmp As LongLong, hRegion As LongLong
        Dim OldBrush As LongLong, hOldBmp As LongLong
        Dim hBrush As LongLong, hFont As LongLong
        Dim hPrevFont As LongLong
        Dim hPen As LongLong, hOldPen As LongLong
        Dim hGraphics As LongLong
#Else
    Private Sub DrawTab(ByVal IsTagged As Boolean, ByVal hwnd As Long, ByVal Page As Object, ByVal pRect As Long)
        Dim hdc As Long, hMemDC As Long, hMemBmp As Long, hRegion As Long
        Dim OldBrush As Long, hOldBmp As Long
        Dim hBrush As Long, hFont As Long
        Dim hPrevFont As Long
        Dim hPen As Long, hOldPen As Long
        Dim hGraphics As Long
#End If

    Const TRANSPARENT = 1
    Const DT_CENTER = &H1
    Const DT_VCENTER = &H4
    Const DT_LEFT = &H0
    Const SRCCOPY = &HCC0020
    Const DEFAULT_GUI_FONT = 17
    Const S_OK = 0&
    Const UnitPixel = 2
    Const SmoothingModeAntiAlias As Long = &H4
    Const DashStyleSolid = 0

    Dim tTabRect As RECT, tTextRect As RECT, tPoly(1 To 3) As POINTF
    Dim p1 As POINTAPI, p2 As POINTAPI, tpt As POINTAPI, tPen As LOGPEN
    Dim TagArray As Variant
    Dim sCaption As String
    Dim lFontColor As Long
    Dim lBackColor As Long
    Dim bExtendTabColToPage As Boolean
    Dim bPaint As Boolean
    Dim lTabShape As Long
    Dim lPenColor As Long, lRealColor As Long
    Dim lWidth As Long, lHeight As Long
    Dim tSI As GdiplusStartupInput
    Dim lRes As Long
    Dim lToken As Long
  

    sCaption = Replace(Page.Caption, Page.Accelerator, "&" & Page.Accelerator, 1, 1, vbTextCompare)

    If IsTagged Then
        TagArray = Split(Page.Tag, "||")
        lFontColor = CLng(TagArray(0))
        Call TranslateColor(CLng(TagArray(1)), 0, lBackColor)
        bExtendTabColToPage = CBool(TagArray(2))
        lTabShape = TagArray(3)
        bPaint = TagArray(4)
    End If
  
    If bPaint = False Then
        lFontColor = 0&
        Call TranslateColor(Page.Parent.BackColor, 0, lBackColor)
    End If
  
    Call CopyMemory(tTabRect, ByVal pRect, LenB(tTabRect))

    If Page Is Page.Parent.SelectedItem Then
        With tTabRect
            .Top = .Top - 20
        End With
    End If
  
    With tTabRect
        p1.x = .Left + 1: p1.Y = .Top
        p2.x = .Right: p2.Y = .Bottom + 2
    End With
    Call ScreenToClient(hwnd, p1)
    Call ScreenToClient(hwnd, p2)
    With tTabRect
        .Left = p1.x:     .Top = p1.Y
        .Right = p2.x: .Bottom = p2.Y
    End With
  
    With tTabRect

        lWidth = .Right - .Left:  lHeight = .Bottom - .Top
        hdc = GetDC(hwnd)
        hMemDC = CreateCompatibleDC(hdc)
        hMemBmp = CreateCompatibleBitmap(hdc, lWidth, lHeight)
        hOldBmp = SelectObject(hMemDC, hMemBmp)
        hBrush = CreateSolidBrush(lBackColor)
        hRegion = CreateRectRgn(0, 0, lWidth, lHeight)
        OldBrush = SelectObject(hMemDC, hBrush)
        Call FillRgn(hMemDC, hRegion, hBrush)
        Call SelectObject(hMemDC, OldBrush)
        Call DeleteObject(hBrush)
    
        tSI.GdiplusVersion = 1
        lRes = GdiplusStartup(lToken, tSI)
      
        If lRes = S_OK Then
            lRes = GdipCreateFromHDC(hMemDC, hGraphics)
            GdipSetSmoothingMode hGraphics, SmoothingModeAntiAlias
  
            Select Case lTabShape
  
                Case Flat
                    lPenColor = RGBtoARGB(lFontColor, 255)
                    Call GdipCreatePen1(lPenColor, 1, UnitPixel, hPen)
                    Call GdipSetPenDashStyle(hPen, DashStyleSolid)
                    If Page Is Page.Parent.SelectedItem Then
                        Call GdipDrawRectangle(hGraphics, hPen, 0, 18, lWidth - 1, lHeight - 1)
                    Else
                        Call GdipDrawRectangle(hGraphics, hPen, 0, 0, lWidth - 1, lHeight - 1)
                    End If
                    Call GdipDeletePen(hPen)
          
                Case Bumped
                    lPenColor = RGBtoARGB(0, 255)
                    Call GdipCreatePen1(lPenColor, 4, UnitPixel, hPen)
                    Call GdipSetPenDashStyle(hPen, DashStyleSolid)
                    Call GdipDrawLine(hGraphics, hPen, lWidth, 1, lWidth, lHeight)
                    If Page Is Page.Parent.SelectedItem Then
                        Call GdipSetPenColor(hPen, RGBtoARGB(0, 200))
                        Call GdipSetPenWidth(hPen, 1)
                        Call GdipDrawLine(hGraphics, hPen, 2, 18, lWidth, 18)
                        GdipSetPenWidth hPen, 2
                        GdipSetPenColor hPen, RGBtoARGB(0, 180)
                        Call GdipDrawLine(hGraphics, hPen, 1, 0, 1, lHeight)
                        GdipSetPenWidth hPen, 2
                        GdipSetPenColor hPen, RGBtoARGB(vbWhite, 255)
                        Call GdipDrawLine(hGraphics, hPen, 0, 0, 0, lHeight)
                        Call GdipDeletePen(hPen)
                    End If
                
                Case Trapezoid
                    tPoly(1).x = IIf(Page Is Page.Parent.SelectedItem, lWidth, lWidth - lWidth / 2)
                    tPoly(1).Y = 0
                    tPoly(2).x = lWidth
                    tPoly(2).Y = 0
                    tPoly(3).x = lWidth
                    tPoly(3).Y = IIf(Page Is Page.Parent.SelectedItem, lHeight, lHeight / 2)
                    Call TranslateColor(Page.Parent.BackColor, 0, lRealColor)
                    Call GdipCreateSolidFill(RGBtoARGB(lRealColor, 255), hBrush)
                    lPenColor = RGBtoARGB(lRealColor, 255)
                    Call GdipCreatePen1(lPenColor, 1, UnitPixel, hPen)
                    GdipDrawPolygon hGraphics, hPen, tPoly(1), 3
                    GdipFillPolygon hGraphics, hBrush, tPoly(1), 3, 0
                    GdipSetPenColor hPen, RGBtoARGB(lFontColor, 255)
                    Call GdipDrawLine(hGraphics, hPen, 0, 0, tPoly(1).x + 2, 0)
                    Call GdipDrawLine(hGraphics, hPen, 0, 0, 0, lHeight)
                    Call GdipDrawLine(hGraphics, hPen, tPoly(1).x - 1, tPoly(1).Y - 1, tPoly(3).x - 1, tPoly(3).Y - 1)
                    Call GdipSetPenWidth(hPen, 4)
                    Call GdipDrawLine(hGraphics, hPen, tPoly(3).x, tPoly(3).Y - 1, tPoly(3).x, lHeight)
                    If Page Is Page.Parent.SelectedItem Then
                        Call GdipSetPenColor(hPen, RGBtoARGB(vbWhite, 255))
                        Call GdipSetPenWidth(hPen, 1)
                        Call GdipDrawLine(hGraphics, hPen, 0, 7, tPoly(2).x + 2, 7)
                        Call GdipSetPenColor(hPen, RGBtoARGB(lFontColor, 255))
                        Call GdipSetPenWidth(hPen, 2)
                        Call GdipDrawLine(hGraphics, hPen, 0, 18, tPoly(3).x, 18)
                    End If
                    Call GdipDeleteBrush(hBrush)
                    Call GdipDeletePen(hPen)
        
            End Select
        
            Call GdipDeleteGraphics(hGraphics)
          
        End If
                        
        Call GdiplusShutdown(lToken)
          
        hFont = GetStockObject(DEFAULT_GUI_FONT)
        hPrevFont = SelectObject(hMemDC, hFont)
        Call SetBkMode(hMemDC, TRANSPARENT)
        Call SetTextColor(hMemDC, lFontColor)
      
        If Page Is Page.Parent.SelectedItem Then
            Call SetRect(tTextRect, 4, 21, lWidth - 4, lHeight - 4)
            Call DrawText(hMemDC, sCaption, Len(sCaption), tTextRect, DT_VCENTER + DT_CENTER)
            If GetFocus = hwnd Then
                Call DrawFocusRect(hMemDC, tTextRect)
            End If
        Else
            Call SetRect(tTextRect, 4, 2, lWidth, lHeight)
            Call DrawText(hMemDC, sCaption, Len(sCaption), tTextRect, IIf(lTabShape = Trapezoid, DT_LEFT, DT_VCENTER))
        End If
          
        Call BitBlt(hdc, .Left, .Top, lWidth, lHeight, hMemDC, 0, 0, SRCCOPY)

    End With
  
    Call ZeroMemory(tTabRect, ByVal LenB(tTabRect))
  
    If bExtendTabColToPage Then
        Call DrawEntirePage(Page, lBackColor)
    End If
  
    Call SelectObject(hMemDC, hOldBmp)
    Call SelectObject(hMemDC, hPrevFont)
  
    Call DeleteDC(hMemDC)
    Call DeleteObject(hMemBmp)
    Call DeleteObject(hFont)
    Call DeleteObject(hRegion)
    Call ReleaseDC(hwnd, hdc)

End Sub


Private Sub DrawEntirePage(ByVal Page As Object, ByVal Col As Long)

     Const IMAGE_BITMAP = 0
     Const PICTYPE_BITMAP = 1
     Const LR_COPYRETURNORG = &H4
     Const S_OK = 0&
  
    #If Win64 Then
        Dim hdc As LongLong, hMemBmp As LongLong, hMemDC As LongLong, hBrush As LongLong
        Dim hCopy As LongLong, OldMemBmp As LongLong
    #Else
        Dim hdc As Long, hMemBmp As Long, hMemDC As Long, hBrush As Long
        Dim hCopy As Long, OldMemBmp As Long
    #End If

    Dim tBmpRect As RECT
    Dim IID_IDispatch As GUID
    Dim uPicinfo As uPicDesc
    Dim iPic As IPicture

    hdc = GetDC(0)
    SetRect tBmpRect, 0, 0, 1, 1

    With tBmpRect
        hMemBmp = CreateCompatibleBitmap(hdc, .Right - .Left, .Bottom - .Top)
    End With

    hMemDC = CreateCompatibleDC(hdc)
    OldMemBmp = SelectObject(hMemDC, hMemBmp)
    hBrush = CreateSolidBrush(Col)

    Call FillRect(hMemDC, tBmpRect, hBrush)
    hCopy = CopyImage(hMemBmp, IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG)

    With IID_IDispatch
        .Data1 = &H20400
        .Data4(0) = &HC0
        .Data4(7) = &H46
    End With

    With uPicinfo
        .size = Len(uPicinfo)
        .Type = PICTYPE_BITMAP
        .hPic = hCopy
        .hPal = 0
    End With

    Page.PictureSizeMode = fmPictureSizeModeStretch
    If OleCreatePictureIndirect(uPicinfo, IID_IDispatch, True, iPic) = S_OK Then
        Set Page.Picture = iPic
    End If

    Call SelectObject(hMemDC, OldMemBmp)
    Call DeleteObject(hMemBmp)
    Call DeleteObject(hMemDC)
    Call DeleteObject(hBrush)
    Call ReleaseDC(0, hdc)

End Sub


#If Win64 Then
    Private Sub DrawPageOutline(ByVal IsTagged As Boolean, ByVal hwnd As LongLong, ByVal Page As Object, ByVal pRect As LongLong)
        Dim hdc As LongLong, hPen As LongLong, hOldPen As LongLong
#Else
    Private Sub DrawPageOutline(ByVal IsTagged As Boolean, ByVal hwnd As Long, ByVal Page As Object, ByVal pRect As Long)
        Dim hdc As Long, hPen As Long, hOldPen As Long
#End If

    Const GW_CHILD = 5
    Const PS_SOLID = 0&

    Dim p1 As POINTAPI, p2 As POINTAPI
    Dim tPen As LOGPEN, tpt As POINTAPI
    Dim tMultiPageRect As RECT
    Dim lPenColor As Long
    Dim TagArray As Variant
    Dim sCaption As String
    Dim lBackColor As Long
    Dim bExtend As Boolean
    Dim tCurTabRect As RECT
  
    hwnd = GetNextWindow(hwnd, GW_CHILD)
    GetClientRect hwnd, tMultiPageRect
    hdc = GetDC(hwnd)
  
   Call UpdateWindow(hwnd)

    With tPen
        .lopnColor = vbWhite
        .lopnStyle = PS_SOLID
        .lopnWidth.x = 2
        .lopnWidth.Y = 1
    End With
    hPen = CreatePenIndirect(tPen)
    hOldPen = SelectObject(hdc, hPen)
    With tMultiPageRect
        Call MoveToEx(hdc, .Left, .Bottom, tpt)
        Call LineTo(hdc, .Left, .Top)
        Call MoveToEx(hdc, .Left, .Top, tpt)
        Call LineTo(hdc, .Right, .Top)
        Call SelectObject(hdc, hOldPen)
        DeleteObject hPen
        Call TranslateColor(&H80000010, 0, lPenColor)
        With tPen
            .lopnColor = lPenColor
            .lopnStyle = PS_SOLID
            .lopnWidth.x = 5
            .lopnWidth.Y = 5
        End With
        hPen = CreatePenIndirect(tPen)
        hOldPen = SelectObject(hdc, hPen)
        Call MoveToEx(hdc, .Right, .Top, tpt)
        Call LineTo(hdc, .Right, .Bottom)
        Call MoveToEx(hdc, .Right, .Bottom, tpt)
        Call LineTo(hdc, .Left, .Bottom)
    End With

    Call SelectObject(hdc, hOldPen)
    Call DeleteObject(hPen)

    If IsTagged Then
        TagArray = Split(Page.Tag, "||")
        Call TranslateColor(CLng(TagArray(1)), 0, lBackColor)
    Else
        Call TranslateColor(Page.Parent.BackColor, 0, lBackColor)   ' <= !
    End If
      
    Call CopyMemory(tCurTabRect, ByVal pRect, LenB(tCurTabRect))
      
    With tCurTabRect
        p1.x = .Left: p1.Y = .Top
        p2.x = .Right: p2.Y = .Bottom + 2
    End With
    Call ScreenToClient(hwnd, p1)
    Call ScreenToClient(hwnd, p2)
    With tCurTabRect
        .Left = p1.x:     .Top = p1.Y
        .Right = p2.x: .Bottom = p2.Y
    End With
  
    With tPen
        .lopnColor = lBackColor
        .lopnStyle = PS_SOLID
        .lopnWidth.x = 2
        .lopnWidth.Y = 1
    End With
    hPen = CreatePenIndirect(tPen)
    hOldPen = SelectObject(hdc, hPen)

    With tCurTabRect
        Call MoveToEx(hdc, .Left, .Bottom, tpt)
        Call LineTo(hdc, .Right - 2, .Bottom)
    End With

    Call ZeroMemory(tCurTabRect, ByVal LenB(tCurTabRect))
  
    Call SelectObject(hdc, hOldPen)
    Call DeleteObject(hPen)
    Call ReleaseDC(hwnd, hdc)

End Sub


#If Win64 Then
    Private Function GetPageRect(ByVal Page As Object, ByVal hwnd As LongLong) As RECT
#Else
    Private Function GetPageRect(ByVal Page As Object, ByVal hwnd As Long) As RECT
#End If
  
    'A design-time reference to the UIAutomationClient library is required for this routine.
  
    Const UIA_TabItemControlTypeId = &HC363&

    Dim oAutomation As CUIAutomation
    Dim oAllElements As IUIAutomationElementArray
    Dim oElement As IUIAutomationElement
    Dim oCondition As IUIAutomationCondition
    Dim tTagRect As RECT, i As Long
  
    On Error Resume Next
  
    Set oAutomation = New CUIAutomation
    Set oElement = oAutomation.ElementFromHandle(ByVal hwnd)
    Set oCondition = oAutomation.CreateTrueCondition
    Set oAllElements = oElement.FindAll(TreeScope_Descendants, oCondition)
  
    For i = 0 To oAllElements.Length - 1
        Set oElement = oAllElements.GetElement(i)
        If oElement.CurrentControlType = UIA_TabItemControlTypeId Then
            If oElement.CurrentName = Page.Caption Then
                Call CopyMemory(tTagRect, oElement.CurrentBoundingRectangle, LenB(tTagRect))
                GetPageRect = tTagRect
                Call ZeroMemory(tTagRect, ByVal LenB(tTagRect))
                Exit Function
            End If
        End If
    Next i
  
End Function


#If Win64 Then
    Private Function WinProcAddr() As LongLong
        WinProcAddr = VBA.CLngLng(AddressOf WndProc)
    #Else
    Private Function WinProcAddr() As Long
        WinProcAddr = VBA.CLng(AddressOf WndProc)
    #End If
End Function


Private Function RGBtoARGB(ByVal RGBColor As Long, ByVal Opacity As Long) As Long

    If (RGBColor And &H80000000) Then RGBColor = GetSysColor(RGBColor And &HFF&)
    RGBtoARGB = (RGBColor And &HFF00&) Or (RGBColor And &HFF0000) \ &H10000 Or (RGBColor And &HFF) * &H10000
    If Opacity < 128 Then
        If Opacity < 0& Then Opacity = 0&
        RGBtoARGB = RGBtoARGB Or Opacity * &H1000000
    Else
        If Opacity > 255& Then Opacity = 255&
        RGBtoARGB = RGBtoARGB Or (Opacity - 128&) * &H1000000 Or &H80000000
    End If
  
End Function


'______________________SAFETY ROUTINES IN CASE OF AN UNHANDLED ERROR_______________________

#If Win64 Then
    Private Function SafeSubclassingHookFunction(ByVal ncode As Long, ByVal wParam As LongLong, lParam As CWPSTRUCT) As LongLong
#Else
    Private Function SafeSubclassingHookFunction(ByVal ncode As Long, ByVal wParam As Long, lParam As CWPSTRUCT) As Long
#End If

    Const WM_CREATE = &H1
    Dim strClass As String * 256

    If lParam.message = WM_CREATE Then
        strClass = Left(strClass, GetWindowText(lParam.hwnd, ByVal strClass, 256))
        If InStr(1, strClass, "Microsoft Visual Basic") Then
            Call SafeExit
            Call UnhookWindowsHookEx(hHook)
        End If
    End If
  
    SafeSubclassingHookFunction = CallNextHookEx(hHook, ncode, wParam, ByVal lParam)
  
End Function


Private Sub SafeExit()

    Dim oMul As Control
    Dim oUserForm As Object
  
    For Each oUserForm In VBA.UserForms
        For Each oMul In oUserForm.Controls
            If TypeOf oMul Is MultiPage Then
                Call RemoveWindowSubclass(oMul.[_GethWnd], WinProcAddr, ObjPtr(oMul))
                Call RemoveProp(oMul.[_GethWnd], "MultiPageSubclassed")
            End If
        Next oMul
    Next oUserForm

End Sub




2- Code Usage as per the Demo Workbook.


UserForm1:
VBA Code:
Option Explicit

Private Sub UserForm_Initialize()

    PaintTab Me.MultiPage1.Pages(0), 1, vbRed, , False, Flat
    PaintTab Me.MultiPage1.Pages(1), 1, vbBlack, , False, Flat
    PaintTab Me.MultiPage1.Pages(2), 1, vbBlue, , False, Flat
    PaintTab Me.MultiPage1.Pages(3), 1, vbMagenta, , False, Flat
    PaintTab Me.MultiPage1.Pages(4), 1, vbGreen, , False, Flat

    PaintTab Me.MultiPage2.Pages(0), True, vbBlack, &HFFC0FF, True, Bumped
    PaintTab Me.MultiPage2.Pages(1), True, vbMagenta, vbGreen, True, Bumped
    PaintTab Me.MultiPage2.Pages(2), True, RGB(100, 2, 150), vbCyan, True, Bumped
    PaintTab Me.MultiPage2.Pages(3), True, RGB(200, 200, 80), vbRed, True, Bumped

    PaintTab Me.MultiPage3.Pages(0), True, vbBlack, &HFFFFC0, True, Flat
    PaintTab Me.MultiPage3.Pages(1), True, vbMagenta, vbGreen, True, Trapezoid
    PaintTab Me.MultiPage3.Pages(2), True, vbWhite, &H8000&, True, Trapezoid
    PaintTab Me.MultiPage3.Pages(3), True, vbYellow, &H8080FF, True, Bumped
    PaintTab Me.MultiPage3.Pages(4), True, vbRed, vbCyan, True, Bumped

    PaintTab Me.MultiPage4.Pages(0), True, vbBlack, vbGreen, True, Trapezoid
    PaintTab Me.MultiPage4.Pages(1), True, vbRed, vbYellow, True, Trapezoid
    PaintTab Me.MultiPage4.Pages(2), True, vbBlue, vbWhite, True, Trapezoid
    PaintTab Me.MultiPage4.Pages(3), True, 0, vbRed, True, Trapezoid

End Sub

Private Sub BtnShowForm2_Click()
    UserForm2.Show vbModal
End Sub

Private Sub BtnClose_Click()
    Unload Me
End Sub



UserForm2:
VBA Code:
Option Explicit

Private Sub UserForm_Initialize()
    PaintTab Me.MultiPage1.SelectedItem, True, vbRed, &H80FFFF, True, Flat
End Sub

Private Sub MultiPage1_Change()

    Dim oPage As Control

    For Each oPage In Me.MultiPage1.Pages
        PaintTab oPage, IIf(oPage Is Me.MultiPage1.SelectedItem, True, False), vbRed, &H80FFFF, True, Flat
    Next oPage

End Sub

Tested on excel 2007,2010 and 2016 32bit and x64bit.... I hope this works consistently accross different platforms.
 

Some videos you may like

Excel Facts

When did Power Query debut in Excel?
Although it was an add-in in Excel 2010 & Excel 2013, Power Query became a part of Excel in 2016, in Data, Get & Transform Data.

Watch MrExcel Video

Forum statistics

Threads
1,122,628
Messages
5,597,247
Members
414,133
Latest member
lucid33

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Top