Introduction
In a VBA UserForm, you might want to force users to use specific buttons (like “Submit” or “Cancel”) to exit, rather than clicking the “Close” button (the “X” at the top right). This ensures that the form is not closed accidentally and that all necessary processes are completed.
You can achieve this by calling Windows API functions directly. This article explains an advanced technique to remove the “Close” option from the UserForm’s system menu, which effectively disables and grays out the “X” button.
VBA Sample Code to Disable the “Close” Button
This macro consists of API declarations in a Standard Module and an event procedure in the UserForm code.
Step 1: API Declarations in a Standard Module
Copy the following code into a Standard Module (e.g., Module1). It supports both 64-bit and 32-bit Office.
'--- Standard Module (e.g., Module1) ---
' Compatible with both 64-bit and 32-bit systems
#If VBA7 Then
Public Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Public Declare PtrSafe Function GetSystemMenu Lib "user32" (ByVal hwnd As LongPtr, ByVal bRevert As Long) As LongPtr
Public Declare PtrSafe Function DeleteMenu Lib "user32" (ByVal hMenu As LongPtr, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Public Declare PtrSafe Function DrawMenuBar Lib "user32" (ByVal hwnd As LongPtr) As Long
#Else
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, ByVal bRevert As Long) As Long
Public Declare Function DeleteMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Public Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
#End If
' Constants used for DeleteMenu
Public Const SC_CLOSE As Long = &HF060
Public Const MF_BYCOMMAND As Long = &H0
Step 2: UserForm Event Procedure
Write this code directly in the UserForm’s code module. Note that we use the Activate event instead of Initialize. This is because the window handle might not be fully available until the form is activated.
UserForm Code (MainForm)
' Event executed when the form becomes active
Private Sub UserForm_Activate()
Dim formHandle As LongPtr
Dim menuHandle As LongPtr
' 1. Get the Window Handle of this UserForm using FindWindow
' Class Name is always "ThunderDFrame" for UserForms.
' Window Name is the form's Caption.
formHandle = FindWindow("ThunderDFrame", Me.Caption)
' 2. Get the handle of the form's system menu
menuHandle = GetSystemMenu(formHandle, 0&)
' 3. Remove the "Close" command from the menu
DeleteMenu menuHandle, SC_CLOSE, MF_BYCOMMAND
' 4. Redraw the menu bar to apply changes
DrawMenuBar formHandle
End Sub
Code Explanation
UserForm_Activate() Event
This event runs the moment the form is displayed and becomes active. Operations that require the window to exist (like getting a Window Handle) are safer in the Activate event than in Initialize.
formHandle = FindWindow(“ThunderDFrame”, Me.Caption)
FindWindow: An API function that finds a window matching specific criteria."ThunderDFrame": The specific Class Name for VBA UserForm windows. This string is fixed.Me.Caption: The text in the form’s title bar. We pass this so the API can find the correct window.
API Sequence
GetSystemMenu: Retrieves the system menu of the form.DeleteMenu: Deletes the “Close” command (SC_CLOSE) from that menu.DrawMenuBar: Refreshes the window to reflect the changes visually (graying out the X).
How to Restore?
The “Close” button will automatically reset to normal the next time the form is loaded (after being Unloaded). If you need to restore it while the form is still open, you would need to run GetSystemMenu formHandle, 1&.
Summary
In this article, we covered an advanced technique to disable the UserForm’s “Close” button (X) using Windows API.
- Get the UserForm’s window handle using
FindWindow("ThunderDFrame", Me.Caption). - It is safer to run this in the
UserForm_Activateevent. - Call the APIs in this order:
GetSystemMenu→DeleteMenu→DrawMenuBar.
This is very effective when you need to strictly control the user’s workflow. However, use it carefully, as preventing a window from closing can sometimes confuse users.
