Open the Windows Color Dialog from VBA

The other day I was working on a project where I needed to prompt the user to provide a custom background color for a form.  I wanted to use the built-in Windows color picker control.  You know the one:

At first I headed for Google, but there can be a lot of noise in Google web search results.  So, instead, I went to Daniel Pineault's site, devhut.net, and searched for "color picker."  I was not disappointed:

VBA - ChooseColor API x32 & x64 | DEVelopers HUT
A demonstration, both x32 and x64, of how to use the VBA ChooseColor API to allow users to make color selections in your application.

Minor Modifications

Daniel's DialogColor function did almost exactly what I needed.  I just made a few tweaks to customize it to my situation, including:

  • The modified function requires that you pass a default color
  • You can pass up to 16 custom colors as optional parameters
  • Default color returned if user cancels

Default Color is a Required Parameter

My modified function requires that you pass a default color.   The default color is an optional parameter in Daniel's original code.  Passing a value of 0 for the default color sets the default to black, which has the same effect of not passing a default at all in Daniel's original code.

Custom Colors May be Passed as an Optional ParamArray

By making the DefaultColor a required parameter, I was able to use a ParamArray to accept up to 16 prefilled custom colors.  One of the rules with procedures in my Code Library is that they cannot be application-specific.  I must be able to replace one version of a code library module with a newer version without requiring any tweaks.  

Daniel's version lets you set up custom colors, too, but the colors are hard-coded into the function.  You would need a new function for each different set of custom colors you wanted to support.

Default Color Returned if User Cancels

In the original function, Daniel returns the color white if the user cancels out of the color picker dialog.  Since I made the default color a required parameter, I thought it made more sense to return that instead.

The Modified Code: DialogColor()

Below is my modified version of Daniel's original function, complete with backlinks to Daniel's site in the code comments.

'-----------------------------------------------------------------------
'Declarations for DialogColor function

Private Const CC_ANYCOLOR = &H100
'Private Const CC_ENABLEHOOK = &H10
'Private Const CC_ENABLETEMPLATE = &H20
'Private Const CC_ENABLETEMPLATEHANDLE = &H40
Private Const CC_FULLOPEN = &H2
Private Const CC_PREVENTFULLOPEN = &H4
Private Const CC_RGBINIT = &H1
'Private Const CC_SHOWHELP = &H8
'Private Const CC_SOLIDCOLOR = &H80

#If VBA7 Then
    Private Type ChooseColor
        lStructSize               As Long
        hwndOwner                 As LongPtr
        hInstance                 As LongPtr
        rgbResult                 As Long
        lpCustColors              As LongPtr
        Flags                     As Long
        lCustData                 As LongPtr
        lpfnHook                  As LongPtr
        lpTemplateName            As String
    End Type
    Private Declare PtrSafe Function ChooseColor Lib "comdlg32.dll" Alias "ChooseColorA" (pChoosecolor As ChooseColor) As Long
#Else
    Private Type ChooseColor
        lStructSize               As Long
        hwndOwner                 As Long
        hInstance                 As Long
        rgbResult                 As Long
        lpCustColors              As Long
        Flags                     As Long
        lCustData                 As Long
        lpfnHook                  As Long
        lpTemplateName            As String
    End Type
    Private Declare Function ChooseColor Lib "comdlg32.dll" Alias "ChooseColorA" (pChoosecolor As ChooseColor) As Long
#End If
'=======================================================================


' ----------------------------------------------------------------
' Procedure : DialogColor
' Author    : Daniel Pineault
' Source    : https://www.devhut.net/vba-choosecolor-api-x32-x64/
' Adapted by: Mike Wolfe
' Date      : 2/2/2023
' Purpose   : Display the Windows color chooser dialog.
' Notes     - Returns the default color if the user cancels.
'           - Pass 0 as the DefaultColor to use the Color Picker default of black.
'           - DefaultColor is required so that custom colors can be
'               passed via optional ParamArray.
'           - Custom colors should be passed as long integers.
' Sample Usage:
'   UserColorChoice = DialogColor(0, RGB(240, 240, 240), vbRed, vbGreen, vbBlue)
' ----------------------------------------------------------------
Public Function DialogColor(DefaultColor As Long, ParamArray CustomColors() As Variant) As Long
    'Populate array of custom colors
    Dim Colors(16) As Long, i As Long
    For i = LBound(CustomColors) To UBound(CustomColors)
        Colors(i) = CustomColors(i)
    Next i

    Dim CC As ChooseColor
    With CC
        .lStructSize = LenB(CC)
        .hwndOwner = Application.hWndAccessApp
        .Flags = CC_ANYCOLOR Or CC_FULLOPEN Or CC_PREVENTFULLOPEN Or CC_RGBINIT
        .rgbResult = DefaultColor    'Set the initial color of the dialog
        .lpCustColors = VarPtr(Colors(0))
    End With
    
    Dim ReturnCode As Long
    ReturnCode = ChooseColor(CC)
    If ReturnCode = 0 Then
        'Cancelled by the user
        DialogColor = DefaultColor
    Else
        DialogColor = CC.rgbResult
    End If
End Function