You are currently offline, waiting for your internet to reconnect

How To Disable the Close Option on Control Menu of a VB Form

This article was previously published under Q184686
SUMMARY
To modify an item in the Visual Basic Control menu (also known as theSystem menu), you need to use the SetMenuItemInfo API function. Thisarticle describes how to enable/disable or check/uncheck the Close menuitem in the Control menu.
MORE INFORMATION
If you do not want the user to close a window via the Control menu or theClose box on your Form's title bar, you can disable the Close menu item onthe Control menu. This method also disables double-clicking the Control boxand disables the Close button on the Form's title bar.

The following code sample enables/disables and checks/unchecks the Closecommand in the Visual Basic Control menu.

Example

  1. Start a new standard EXE project. Form1 is added by default.
  2. Add three CommandButtons to Form1.
  3. Add the following code to Form1:
          Option Explicit      'Menu item constants.      Private Const SC_CLOSE       As Long = &HF060&      'SetMenuItemInfo fMask constants.      Private Const MIIM_STATE     As Long = &H1&      Private Const MIIM_ID        As Long = &H2&      'SetMenuItemInfo fState constants.      Private Const MFS_GRAYED     As Long = &H3&      Private Const MFS_CHECKED    As Long = &H8&      'SendMessage constants.      Private Const WM_NCACTIVATE  As Long = &H86      'User-defined Types.      Private Type MENUITEMINFO          cbSize        As Long          fMask         As Long          fType         As Long          fState        As Long          wID           As Long          hSubMenu      As Long          hbmpChecked   As Long          hbmpUnchecked As Long          dwItemData    As Long          dwTypeData    As String          cch           As Long      End Type      'Declarations.      Private Declare Function GetSystemMenu Lib "user32" ( _          ByVal hwnd As Long, ByVal bRevert As Long) As Long      Private Declare Function GetMenuItemInfo Lib "user32" Alias _          "GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, _          ByVal b As Boolean, lpMenuItemInfo As MENUITEMINFO) As Long      Private Declare Function SetMenuItemInfo Lib "user32" Alias _          "SetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, _          ByVal bool As Boolean, lpcMenuItemInfo As MENUITEMINFO) As Long      Private Declare Function SendMessage Lib "user32" Alias _          "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _          ByVal wParam As Long, lParam As Any) As Long      'Application-specific constants and variables.      Private Const xSC_CLOSE  As Long = -10      Private Const SwapID     As Long = 1      Private Const ResetID    As Long = 2      Private hMenu  As Long      Private MII    As MENUITEMINFO      Private Sub Command1_Click()          Dim Ret As Long          Ret = SetId(SwapID)          If Ret <> 0 Then              If MII.fState = (MII.fState Or MFS_GRAYED) Then                  MII.fState = MII.fState - MFS_GRAYED              Else                  MII.fState = (MII.fState Or MFS_GRAYED)              End If              MII.fMask = MIIM_STATE              Ret = SetMenuItemInfo(hMenu, MII.wID, False, MII)              If Ret = 0 Then                  Ret = SetId(ResetID)              End If              Ret = SendMessage(Me.hwnd, WM_NCACTIVATE, True, 0)              SetButtons          End If      End Sub      Private Sub Command2_Click()          Dim Ret As Long          If MII.fState = (MII.fState Or MFS_CHECKED) Then              MII.fState = MII.fState - MFS_CHECKED          Else              MII.fState = (MII.fState Or MFS_CHECKED)          End If          MII.fMask = MIIM_STATE          Ret = SetMenuItemInfo(hMenu, MII.wID, False, MII)          SetButtons      End Sub      Private Sub Command3_Click()          Unload Me      End Sub      Private Function SetId(Action As Long) As Long          Dim MenuID As Long          Dim Ret As Long          MenuID = MII.wID          If MII.fState = (MII.fState Or MFS_GRAYED) Then              If Action = SwapID Then                  MII.wID = SC_CLOSE              Else                  MII.wID = xSC_CLOSE              End If          Else              If Action = SwapID Then                  MII.wID = xSC_CLOSE              Else                  MII.wID = SC_CLOSE              End If          End If          MII.fMask = MIIM_ID          Ret = SetMenuItemInfo(hMenu, MenuID, False, MII)          If Ret = 0 Then              MII.wID = MenuID          End If          SetId = Ret      End Function      Private Sub SetButtons()          If MII.fState = (MII.fState Or MFS_GRAYED) Then              Command1.Caption = "Enable"          Else              Command1.Caption = "Disable"          End If          If MII.fState = (MII.fState Or MFS_CHECKED) Then              Command2.Caption = "Uncheck"          Else              Command2.Caption = "Check"          End If      End Sub      Private Sub Form_Load()          Dim Ret As Long          hMenu = GetSystemMenu(Me.hwnd, 0)          MII.cbSize = Len(MII)          MII.dwTypeData = String(80, 0)          MII.cch = Len(MII.dwTypeData)          MII.fMask = MIIM_STATE          MII.wID = SC_CLOSE          Ret = GetMenuItemInfo(hMenu, MII.wID, False, MII)          SetButtons          Command3.Caption = "Exit"      End Sub						
  4. Press the F5 key to run the program.

Additional Notes

Visual Basic handles enabling and disabling the standard Control menuitems, including Restore, Size, Move, Minimize, and Maximize (the Closemenu is always enabled). Generally, Visual Basic enables/disables the menuitems depending on the window's state (minimized, maximized, or normal) byreferencing these menu items by their menu item IDs.

As a result, if we merely add or remove MFS_GRAYED from a menu's fState,Visual Basic immediately resets it. The workaround is to change the menuitem's ID (which also renders the item inoperable).

Using this workaround, we can effectively disable a menu item that VisualBasic intends to be enabled, but we cannot enable a menu item Visual Basicintends to be disabled (the menu item must have its regular ID to beoperable).

Enabling a menu item that Visual Basic intends to be disabled requiresremoving the item and replacing it with a menu item of our own (this is notcovered in this article).

When the Close menu item is enabled or disabled, the Close box on the titlebar should also be normal or grayed, respectively. Sending the messageWM_NCACTIVATE (nonclient activate) notifies the window to refresh its titlebar so the Close box is updated to appear normal or grayed.

Additional Constants

   'Menu item constants       Const SC_SIZE         As Long = &HF000&       Const SC_SEPARATOR    As Long = &HF00F&       Const SC_MOVE         As Long = &HF010&       Const SC_MINIMIZE     As Long = &HF020&       Const SC_MAXIMIZE     As Long = &HF030&       Const SC_CLOSE        As Long = &HF060&       Const SC_RESTORE      As Long = &HF120&   'SetMenuItemInfo fMask Constants       Const MIIM_STATE      As Long = &H1&       Const MIIM_ID         As Long = &H2&       Const MIIM_SUBMENU    As Long = &H4&       Const MIIM_CHECKMARKS As Long = &H8&       Const MIIM_TYPE       As Long = &H10&       Const MIIM_DATA       As Long = &H20&				


Related APIs

SetMenuDefaultItem -- You must disable Close to use this in Visual Basic
HiliteMenuItem
REFERENCES
For the 16-bit equivalent, please see the following article in theMicrosoft Knowledge Base:
82876 : How to Disable Close Command in VB Control Menu (System Menu)
kbVBp500 kbVBp400 kbSDKWin32 kbAPI kbMenu kbVBp kbDSupport kbDSD kbVBp600
Properties

Article ID: 184686 - Last Review: 07/01/2004 16:30:00 - Revision: 3.1

  • Microsoft Visual Basic 5.0 Learning Edition
  • Microsoft Visual Basic 6.0 Learning Edition
  • Microsoft Visual Basic 5.0 Professional Edition
  • Microsoft Visual Basic 6.0 Professional Edition
  • Microsoft Visual Basic 5.0 Enterprise Edition
  • Microsoft Visual Basic 6.0 Enterprise Edition
  • Microsoft Visual Basic 4.0 Standard Edition
  • Microsoft Visual Basic 4.0 Professional Edition
  • Microsoft Visual Basic 4.0 32-Bit Enterprise Edition
  • kbhowto kbgrpdsvb KB184686
Feedback