VBA Msgbox Custom Button Text

One functionality missing from the VBA MsgBox function is the ability to customize the button text. Using the MessageBox API, I wrote my own class to customize the button text, re-purposing some of the existing messagebox types to return which button was clicked (first, second, third). Custom Msgbox Buttons

Note: Updated 5-25-2016 to support 64-bit versions of Office.
Note: Updated 12-29-2016 to to have close button enabled by default.
Note: Updated 5-22-2017 to use Win API to get handle to application object window.
Note: Updated 6-8-2017 fixed bug – Thanks to Greg Donnells and Brian High for pointing this out.

VBA Msgbox Custom Button Text
Custom MessageBox Button Text

Example Usage :

    Dim cC As clsMsgbox
    Dim iR As Integer

    Set cC = New clsMsgbox
    iR = cC.MessageBoxEx("Do you want to save the changes you made to whatever?", Exclamation + DefaultButton2, , "&Save", "Do&n't Save", "&Cancel")
    If iR = Button1 Then
        Debug.Print "Button1 Clicked"
    ElseIf iR = Button2 Then
        Debug.Print "Button2 Clicked"
    ElseIf iR = Button3 Then
        Debug.Print "Button3 Clicked"
    End If
    Set cC = New clsMsgbox
    cC.Title = "Title"
    cC.Prompt = "Prompt"
    cC.Icon = Question + DefaultButton3
    cC.ButtonText1 = "ButtonText1"
    cC.ButtonText2 = "ButtonText2"
    cC.ButtonText3 = "ButtonText3"
    iR = cC.MessageBox()
    If iR = Button1 Then
        Debug.Print "Button1 Clicked"
    ElseIf iR = Button2 Then
        Debug.Print "Button2 Clicked"
    ElseIf iR = Button3 Then
        Debug.Print "Button3 Clicked"
    End If

21 thoughts on “VBA Msgbox Custom Button Text”

  1. I get the following dialog when I try to open CustomMsgbox.xlsm:

    —————————
    Microsoft Visual Basic for Applications
    —————————
    Compile error:

    The code in this project must be updated for use on 64-bit systems. Please review and update Declare statements and then mark them with the PtrSafe attribute.
    —————————
    OK Help
    —————————

    1. Howdy. I knew this day was coming 😉

      I updated the CustomMsgbox.xlsm to work with both 64 and 32 bit flavors of Office.
      Redownload and let me know if it works now for you.

  2. Yes, I do have both in my project. I get a Run-time error ‘438’ “Object doesn’t support this property or method” in “modUnitTest” at “Set cC = New clsMsgbox”

  3. Thanks for this class, it really helps a lot.

    Any chance you can add support for setting the second parameter of the msgbox beside the icon types? Specially vbMsgBoxRtlReading?

    Thanks a lot.

  4. Hi, I get the following error, running on 64 system in access 2016.
    Compile error: can’t find method or data member
    The second hwnd is highlighted. What can be the problem?

    Private Sub Class_Initialize()
    #If Win64 Then
    m_hInstance = GetWindowLong(CLngPtr(Application.hwnd), GWL_HINSTANCE)
    #Else
    m_hInstance = GetWindowLong(Application.hwnd, GWL_HINSTANCE)
    #End If

    m_hThreadID = GetCurrentThreadId()
    End Sub

  5. Thanx for the great code!

    My only problem is the X for the custom message box is disabled and if the user hits ESC, they still have to make a selection and it throws a message “Code Execution has been interupted”.

    Is there any way to allow user to close/cancel the custom message box by hitting ESC?

    1. The escape issue should be fixed now.

      From MessageBox function API:
      If a message box has a Cancel button, the function returns the IDCANCEL value if either the ESC key is pressed or the Cancel button is selected.
      If the message box has no Cancel button, pressing ESC has no effect.

      The only way the close button will be enabled is if the messagebox has only one button, or has a cancel button.
      I had to make changes to the underlying buttons :

      3 Buttons = YesNoCancel,
      2 Buttons = OkCancel
      1 Button = OK

      So the only caveat is closing the dialog via escape will return the associated cancel button (button 3, button 2, button 1 respectively).

      Thanks,
      Dean

  6. This is truly excellent work, Thank You!

    Could you help me with a couple of questions ?

    1. If I call your class from a user form in Excel it allows me to switch back to the parent user form. How can I prevent it?

    2. Standard message box can be closed by pressing Esc key on the keyboard. Can I make your message box behave this way?

    Many Thanks!
    Regards
    Alex

  7. The escape issue should be fixed now.

    From MessageBox function API:
    If a message box has a Cancel button, the function returns the IDCANCEL value if either the ESC key is pressed or the Cancel button is selected.
    If the message box has no Cancel button, pressing ESC has no effect.

    The only way the close button will be enabled is if the messagebox has only one button, or has a cancel button.
    I had to make changes to the underlying buttons :

    3 Buttons = YesNoCancel,
    2 Buttons = OkCancel
    1 Button = OK

    So the only caveat is closing the dialog via escape will return the associated cancel button (button 3, button 2, button 1 respectively).

    The modal issue may take some more time to fix.
    In the meantime, you can just disable, then re-enable the parent form :

    Private Sub CommandButton1_Click()
        Dim cC As clsMsgbox
        Dim iR As Integer
        
        Me.Enabled = False
        Set cC = New clsMsgbox
        iR = cC.MessageBoxEx("Do you want to save the changes you made to whatever?", Exclamation + DefaultButton2, , "&Save", "Do&n't Save", "&Cancel")
        If iR = Button1 Then
            Debug.Print "Button1 Clicked"
        ElseIf iR = Button2 Then
            Debug.Print "Button2 Clicked"
        ElseIf iR = Button3 Then
            Debug.Print "Button3 Clicked"
        End If
        Me.Enabled = True
    End Sub
    

    Thanks,
    Dean

  8. Many Thanks for your help!

    May I make suggest an idea for your consideration ?

    You could look the captions of the custom buttons and if you find one that says “Cancel” you could use vbYesNoCancel for the three button and vbOkCancel for the two button message box.

    Without caption “Cancel” you could go for vbAbortRetryIgnore and vbYesNo as you do at the moment.

    1. Instead of checking buttons for cancel caption, I added a UseCancel property to the clsMsgbox class.

      I did this for simplicity since the cancel button has to be the second button with two buttons (vbOKCancel), and has to be the third button with 3 buttons (vbYesNoCancel).
      Also, the caption could contain ampersands for shortcuts.
      Lastly the caption could be a different language than english.

      See UnitTest2 for usage.

  9. There is a bug in the code in the class function MessageBox() when you look for the button that was clicked… the corrections is:

    If Len(Me.ButtonText1) > 0 And Len(Me.ButtonText2) > 0 And Len(Me.ButtonText3) > 0 Then
    If lR = IIf(bCancel, vbYes, vbAbort) Then
    MessageBox = Button1
    ElseIf lR = IIf(bCancel, vbNo, vbRetry) Then
    MessageBox = Button2
    ElseIf lR = IIf(bCancel, vbCancel, vbIgnore) Then
    MessageBox = Button3
    End If

  10. This is fantastic! It saved me from having do build a custom form in Access and all the extra work associated with that. A huge time saver and definitely something I will keep in my toolbox.

    You should add something in the main entry about the Application.hWndAccessApp requirement for MS Access. I found it in the comments, which was really helpful.

    Thanks for this!

    1. Glad it was useful for you. Thanks for the response!
      I modified the macro use the Windows API to get the handle to the application.
      I implemented for Access, Word and Excel.

  11. I believe there’s a bug in your clsMsgbox.MessageBox routine.

    The code that currently looks like this:

    If Len(Me.ButtonText1) > 0 And Len(Me.ButtonText2) > 0 And Len(Me.ButtonText3) > 0 Then
    If lR = IIf(bCancel, vbYes, vbAbort) Then
    MessageBox = Button1
    ElseIf lR = IIf(bCancel, vbNo, vbAbort) Then

    should have that last vbAbort as vbRetry

    Yes?

    Thanks for this also, great stuff!

  12. I still stuck in Outlook 2016!

    I get the error “Instance handle not found” in Sub UnitTest1() at iR = cC.MessageBoxEx(……

    Any ideas? I have all classes and modules

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.