Hide or disable a VBA UserForm [X] close button

Hide or Disable UserForm Close Button

While working on a project recently, I thought about hiding the [X] close button which is at the top of the VBA UserForm.  I managed to identify three options for achieving this.  If you are thinking about the same thing, then this post will give you the answers you’re looking for.

To hide, or not to hide, that is the question

Before we start looking at the three options, I want to cover the most critical question of all: should we hide a UserForm’s close button?

The Close Button

The close button is a recognized part of the Windows environment.  Pretty much every application uses a cross at the top right corner to close a window.  Therefore, based on their experience of other applications, all users already know what the cross should do.  It doesn’t matter which country the user is in or what language they speak, it is a universally understood icon to close a window.  Therefore you should be asking yourself why you want to hide the close button at all.  With this in mind,  I would say that generally the close button should not be hidden or disabled.

However, there are some circumstances where we may want to break this general rule.  One such example is a progress bar.  If the user closes a progress bar, they may not know when the macro has finished running, or how long is left.  Therefore, it might be useful to hide the close button in this scenario.

By default, the close button will unload a UserForm, but it can be adapted to have a custom close procedure.  As we can control this functionality, it may be better to control it rather than hide or disable it.

About Windows API codes

Of the three solutions, two of them rely on Windows API calls.  These are where the VBA code makes use of functions which are not part of Excel, but part of the main Windows application.  As this is complicated stuff, I will not go through it in detail here.  But the key points to note about the Windows API codes are:

  • They will not work on a Mac, only on Windows.  So if designing for Windows and Mac, you will need to identify which platform is used and adapt the code accordingly.
  • The code sections marked “Include this code at the top of the module” must be included before any other Subs or Functions are declared, and must be below the Option Explicit statement (if you have one).

3 Options for disabling/hiding a UserForm close button

If you are still intent on hiding or disabling the close button, then read on to understand the three options.

(1) The unobvious disable with a message box

This first option is the worst of the three. It does not disable or hide the close button, but prevents the user from using it to close the window.

Even though it is the worst option, it is the easiest to use and understand.  The following code can be used within the UserForm’s QueryClose event.

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)

If CloseMode = vbFormControlMenu Then

    Cancel = True
    MsgBox "Please use the Close button to close the form", vbOKOnly

End If

End Sub

If the user clicks on the close button, the following message box will appear.

VBA MsgBox

This is effectively disabling the close button, as the UserForm will not close.  But from a user’s perspective, this solution is just frustrating.  Why would there be a button which doesn’t do anything apart from telling us it doesn’t do anything?  This is why it’s not a great option.

(2) Disable the close button (Windows API)

The second option will disable the close button; it will be visible, but will be greyed-out and cannot be clicked.

The first image below shows the close button when it is enabled; the second image shows the close button when it is disabled.

Enabled and disabled close buttons

From a user’s perspective, this option is better than the first, but still not great.  What is the point of a button which cannot be clicked; it just creates confusion?

Basic code

The code below should be copied into a new standard module and must be included before any other code, but after the Option Explicit statement (if there is one).

'Include this code at the top of the module
Private Const GWL_STYLE = -16
Private Const WS_CAPTION = &HC00000
Private Const WS_SYSMENU = &H80000
Private Const SC_CLOSE = &HF060

#If VBA7 Then

    Private Declare PtrSafe Function FindWindowA _
        Lib "user32" (ByVal lpClassName As String, _
        ByVal lpWindowName As String) As Long
    Private Declare PtrSafe Function DeleteMenu _
        Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, _
        ByVal wFlags As Long) As Long
    Private Declare PtrSafe Function GetSystemMenu _
        Lib "user32" (ByVal hWnd As Long, ByVal bRevert As Long) As Long
        
#Else

    Private Declare Function FindWindowA _
        Lib "user32" (ByVal lpClassName As String, _
        ByVal lpWindowName As String) As Long
    Private Declare Function DeleteMenu _
        Lib "user32" (ByVal hMenu As Long, _
        ByVal nPosition As Long, ByVal wFlags As Long) As Long
    Public Declare Function GetSystemMenu _
        Lib "user32" (ByVal hWnd As Long, ByVal bRevert As Long) As Long
        
#End If
'Include this code in the same module as the API calls above
Public Sub CloseButtonSettings(frm As Object, show As Boolean)

Dim windowHandle As Long
Dim menuHandle As Long
windowHandle = FindWindowA(vbNullString, frm.Caption)

If show = True Then

    menuHandle = GetSystemMenu(windowHandle, 1)

Else

    menuHandle = GetSystemMenu(windowHandle, 0)
    DeleteMenu menuHandle, SC_CLOSE, 0&

End If

End Sub

The code examples above create reusable functionality to enable or disable the close button.  The CloseButtonSettings subprocedure can now be called from any other module.   There are two arguments required:

  • frm – a reference to the UserForm for which the close button should be enabled/disabled
  • show – a True or False value where True = enable the close button and False = disable the close button

Disable the close button on UserForm initialize

If inserted into the UserForm’s initialize event it will disable the button when the form is created.

Private Sub UserForm_Initialize()

Call CloseButtonSettings(Me, False)

End Sub

Disable or enable the close button at any point

The close button can be enabled or disabled as and when required with the following macros:

Disable the close button

Sub DisableClose()

Call CloseButtonSettings(frmMyUserForm, False)

End Sub

Enable the close button

Sub EnableClose()

Call CloseButtonSettings(frmMyUserForm, True)

End Sub

(3) Hide system menu (Windows API)

The third option is to hide the system menu section of the window.  The System menu section includes the maximize, minimize and close buttons.  The screenshot below shows the close button is not visible.

API No close button

By hiding the system menu section, we are also removing the ability to see the minimize and maximize buttons.  By default a UserForm does not have these buttons visible (separate Windows API calls are required to enable this), therefore this is probably a good option in 99.9% of circumstances.

Basic Code

The code below should be copied into a new standard module and must be included before any other code, but after the Option Explicit statement (if there is one).

'Include this code at the top of the module
Private Const GWL_STYLE = -16
Private Const WS_CAPTION = &HC00000
Private Const WS_SYSMENU = &H80000

#If VBA7 Then

    Private Declare PtrSafe Function GetWindowLong _
        Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, _
        ByVal nIndex As Long) As Long
    Private Declare PtrSafe Function SetWindowLong _
        Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, _
        ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    Private Declare PtrSafe Function FindWindowA _
        Lib "user32" (ByVal lpClassName As String, _
        ByVal lpWindowName As String) As Long
    Private Declare PtrSafe Function DrawMenuBar _
        Lib "user32" (ByVal hWnd As Long) As Long
        
#Else

    Private Declare Function GetWindowLong _
        Lib "user32" Alias "GetWindowLongA" ( _
        ByVal hWnd As Long, ByVal nIndex 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 Declare Function FindWindowA _ 
        Lib "user32" (ByVal lpClassName As String, _
        ByVal lpWindowName As String) As Long
    Private Declare Function DrawMenuBar _
        Lib "user32" (ByVal hWnd As Long) As Long
  
#End If
'Include this code in the same module as the API calls above
Public Sub SystemButtonSettings(frm As Object, show As Boolean)
Dim windowStyle As Long
Dim windowHandle As Long

windowHandle = FindWindowA(vbNullString, frm.Caption)
windowStyle = GetWindowLong(windowHandle, GWL_STYLE)

If show = False Then

    SetWindowLong windowHandle, GWL_STYLE, (windowStyle And Not WS_SYSMENU)

Else

    SetWindowLong windowHandle, GWL_STYLE, (windowStyle + WS_SYSMENU)

End If

DrawMenuBar(windowHandle)

End Sub

These codes create reusable functionality to show or hide the buttons.  The SystemButtonSettings subprocedure can be called from any other module.   There are two arguments required

  • frm – a reference to the UserForm for which the close button should be shown/hidden
  • show – a True or False value where True = show the system menu and False = hide the system menu

Hide the system menu buttons on UserForm initialize

If inserted into the UserForm’s initialize event it will disable the button when the form is created.

Private Sub UserForm_Initialize()

Call SystemButtonSettings(Me, False)

End Sub

Show or hide the close button at any point

The close button can be shown or hidden as and when required using the following macros.

Hide the close button

Sub HideClose()

Call SystemButtonSettings(frmMyUserForm, False)

End Sub

Show the close button

Sub ShowClose()

Call SystemButtonSettings(frmMyUserForm, True)

End Sub

Download the example file

Want to see these examples working?  Then download the example file.

3 thoughts on “Hide or disable a VBA UserForm [X] close button

  1. Excel Off The Grid says:

    One reader asked me about using the API code Access. It appears the Access UserForm has a hWnd property which contains the Window Handle.

    So to make it work, change this:

    windowHandle = FindWinowA(vbNullString, frm.Caption) 
    

    For this:

    windowHandle = frm.hWnd
    

Leave a Reply

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