Custom Color Dialog

ChooseColor dialog with a COLORDLGPROC hook


Imports System
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Public Class Form1
    Inherits Form

    Private btnPickColor As Button
    Private lblColor As Label

    Public Sub New()
        Text = "COLORDLGPROC Hook Example"
        Size = New Size(320, 150)

        btnPickColor = New Button() With {
            .Text = "Pick Color...",
            .Location = New Point(10, 10),
            .AutoSize = True
        }
        AddHandler btnPickColor.Click, AddressOf OnPickColor

        lblColor = New Label() With {
            .Text = "Selected Color: None",
            .Location = New Point(10, 50),
            .AutoSize = True
        }

        Controls.Add(btnPickColor)
        Controls.Add(lblColor)
    End Sub

    ' Delegate type for hook procedure
    Private Delegate Function ColorDlgProc(hWnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr) As Integer

    ' Hold a reference to the delegate to avoid GC
    Private Shared hookDelegate As ColorDlgProc = AddressOf MyColorHook

    ' CHOOSECOLOR struct (interop-safe version)
    
    Private Structure CHOOSECOLOR2
        Public lStructSize As Integer
        Public hwndOwner As IntPtr
        Public hInstance As IntPtr
        Public rgbResult As Integer
        Public lpCustColors As IntPtr
        Public Flags As Integer
        Public lCustData As IntPtr
        Public lpfnHook As IntPtr
        Public lpTemplateName As IntPtr
    End Structure

    ' Constants
    Private Const CC_RGBINIT As Integer = &H1
    Private Const CC_FULLOPEN As Integer = &H2
    Private Const CC_ENABLEHOOK As Integer = &H10
    Private Const WM_INITDIALOG As Integer = &H110

    ' Win32 API declarations
    
    Private Shared Function ChooseColor(ByRef cc As CHOOSECOLOR2) As Boolean
    End Function

    
    Private Shared Function SetWindowText(hWnd As IntPtr, lpString As String) As Boolean
    End Function

    ' Hook procedure to modify the dialog
    Private Shared Function MyColorHook(hWnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr) As Integer
        If msg = WM_INITDIALOG Then
            SetWindowText(hWnd, "Custom Color Dialog 🎨")
        End If
        Return 0
    End Function

    ' Show the color picker dialog with hook
    Private Sub OnPickColor(sender As Object, e As EventArgs)
        Dim customColors(15) As Integer ' 16 color slots
        Dim gch = GCHandle.Alloc(customColors, GCHandleType.Pinned)

        Try
            Dim cc As New CHOOSECOLOR2()
            cc.lStructSize = Marshal.SizeOf(GetType(CHOOSECOLOR2))
            cc.hwndOwner = Me.Handle
            cc.lpCustColors = gch.AddrOfPinnedObject()
            cc.rgbResult = ColorTranslator.ToWin32(Color.LightGreen)
            cc.Flags = CC_RGBINIT Or CC_FULLOPEN Or CC_ENABLEHOOK
            cc.lpfnHook = Marshal.GetFunctionPointerForDelegate(hookDelegate)

            If ChooseColor(cc) Then
                Dim selectedColor As Color = ColorTranslator.FromWin32(cc.rgbResult)
                lblColor.Text = $"Selected Color: R={selectedColor.R} G={selectedColor.G} B={selectedColor.B}"
                lblColor.ForeColor = selectedColor
            Else
                MessageBox.Show("Color dialog canceled.")
            End If
        Finally
            gch.Free()
        End Try
    End Sub

    
    Public Shared Sub Main()
        Application.EnableVisualStyles()
        Application.Run(New Form1())
    End Sub
End Class

Download 'Custom Color Dialog.vb':

📥 Download custom-color-dialog.vb