Results 1 to 4 of 4

Thread: Classic VB - How can I Hide/Unhide the Form's "X" Button

  1. #1

    Thread Starter
    Former Admin/Moderator MartinLiss's Avatar
    Join Date
    Sep 1999
    Location
    San Jose, CA
    Posts
    33,427

    Classic VB - How can I Hide/Unhide the Form's "X" Button

    Credit for the Hide/Unhide code goes to crptcblade.

    VB Code:
    1. Public Declare Function GetSystemMenu Lib "user32" (ByVal hwnd  _
    2. As Long, ByVal bRevert As Long) As Long
    3. Public Declare Function RemoveMenu Lib "user32" (ByVal hMenu _
    4.  As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
    5. Public Declare Function DrawMenuBar Lib "user32" (ByVal hwnd  _
    6. As Long) As Long
    7.  
    8. Private Const MF_BYCOMMAND = &H0&
    9. Private Const SC_CLOSE = &HF060&
    10.  
    11. Public Sub SetXState(frm As Form, blnState As Boolean)
    12.     Dim hMenu As Long
    13.  
    14.     hMenu = GetSystemMenu(frm.hwnd, blnState)
    15.     Call RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND)
    16.     Call DrawMenuBar(frm.hwnd)
    17.  
    18. End Sub

    Example of Usage:
    VB Code:
    1. Private Sub Command1_Click()
    2.     If opt(0).Value = True Then
    3.         SetXState Me, True   'enable the X button
    4.     ElseIf opt(1).Value = True Then
    5.         SetXState Me, False  'disable the X button
    6.     End If
    7. End Sub

    You can however avoid all that and just do this
    VB Code:
    1. Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
    2.     If UnloadMode = vbFormControlMenu Then
    3.         cmdExit = True ' Change cmdExit to the name of your exit command button
    4.                        ' and the code behind that button will be executed
    5.     End If
    6. End Sub
    Last edited by si_the_geek; Nov 1st, 2005 at 04:30 PM.

  2. #2
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,929

    Re: Classic VB - How can I Hide/Unhide the Form's "X" Button

    An alternative method is to disable both the close button, and the close menu option from the system menu.

    To do that you can use this code: (originally posted by Hack)
    VB Code:
    1. Private Const SC_CLOSE As Long = &HF060&
    2. Private Const MIIM_STATE As Long = &H1&
    3. Private Const MIIM_ID As Long = &H2&
    4. Private Const MFS_GRAYED As Long = &H3&
    5. Private Const WM_NCACTIVATE As Long = &H86
    6.  
    7. Private Type MENUITEMINFO
    8.     cbSize As Long
    9.     fMask As Long
    10.     fType As Long
    11.     fState As Long
    12.     wID As Long
    13.     hSubMenu As Long
    14.     hbmpChecked As Long
    15.     hbmpUnchecked As Long
    16.     dwItemData As Long
    17.     dwTypeData As String
    18.     cch As Long
    19. End Type
    20.  
    21. Private Declare Function GetSystemMenu Lib "user32" ( _
    22.     ByVal hWnd As Long, ByVal bRevert As Long) As Long
    23.  
    24. Private Declare Function GetMenuItemInfo Lib "user32" Alias _
    25.     "GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, _
    26.     ByVal b As Boolean, lpMenuItemInfo As MENUITEMINFO) As Long
    27.  
    28. Private Declare Function SetMenuItemInfo Lib "user32" Alias _
    29.     "SetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, _
    30.     ByVal bool As Boolean, lpcMenuItemInfo As MENUITEMINFO) As Long
    31.  
    32. Private Declare Function SendMessage Lib "user32" Alias _
    33.     "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, _
    34.     ByVal wParam As Long, lParam As Any) As Long
    35.  
    36. Private Declare Function IsWindow Lib "user32" _
    37.     (ByVal hWnd As Long) As Long
    38.  
    39. ' Enables / Disables the close button on the titlebar and in the system menu
    40. ' of the form window passed.
    41. ' Return Values:
    42. '
    43. '    0  Close button state changed succesfully / nothing to do.
    44. '   -1  Invalid Window Handle (hWnd argument) Passed to the function
    45. '   -2  Failed to switch command ID of Close menu item in system menu
    46. '   -3  Failed to switch enabled state of Close menu item in system menu
    47.  
    48. Public Function EnableCloseButton(ByVal hWnd As Long, Enable As Boolean)
    49. As Integer
    50.     Const xSC_CLOSE As Long = -10
    51.     ' Check that the window handle passed is valid    
    52.     EnableCloseButton = -1
    53.     If IsWindow(hWnd) = 0 Then Exit Function
    54.     ' Retrieve a handle to the window's system menu    
    55.     Dim hMenu As Long
    56.     hMenu = GetSystemMenu(hWnd, 0)    
    57.     ' Retrieve the menu item information for the close menu item/button    
    58.     Dim MII As MENUITEMINFO
    59.     MII.cbSize = Len(MII)
    60.     MII.dwTypeData = String(80, 0)
    61.     MII.cch = Len(MII.dwTypeData)
    62.     MII.fMask = MIIM_STATE
    63.    
    64.     If Enable Then
    65.         MII.wID = xSC_CLOSE
    66.     Else
    67.         MII.wID = SC_CLOSE
    68.     End If
    69.         EnableCloseButton = -0
    70.     If GetMenuItemInfo(hMenu, MII.wID, False, MII) = 0 Then Exit Function
    71.     ' Switch the ID of the menu item so that VB can not undo the action itself    
    72.     Dim lngMenuID As Long
    73.     lngMenuID = MII.wID
    74.    
    75.     If Enable Then
    76.         MII.wID = SC_CLOSE
    77.     Else
    78.         MII.wID = xSC_CLOSE
    79.     End If
    80.         MII.fMask = MIIM_ID
    81.     EnableCloseButton = -2
    82.     If SetMenuItemInfo(hMenu, lngMenuID, False, MII) = 0 Then Exit Function
    83.     ' Set the enabled / disabled state of the menu item    
    84.     If Enable Then
    85.         MII.fState = (MII.fState Or MFS_GRAYED)
    86.         MII.fState = MII.fState - MFS_GRAYED
    87.     Else
    88.         MII.fState = (MII.fState Or MFS_GRAYED)
    89.     End If
    90.     MII.fMask = MIIM_STATE
    91.     EnableCloseButton = -3
    92.     If SetMenuItemInfo(hMenu, MII.wID, False, MII) = 0 Then Exit Function
    93.     SendMessage hWnd, WM_NCACTIVATE, True, 0    
    94.     EnableCloseButton = 0    
    95. End Function
    Usage:
    VB Code:
    1. Private Sub Form_Load()
    2.         'enabled
    3.         EnableCloseButton Me.hWnd, True
    4. End Sub
    5.  
    6. Private Sub Command1_Click()
    7.       'disabled
    8.        EnableCloseButton Me.hWnd, False
    9. End Sub

  3. #3
    Giants World Champs!!!! Mark Gambo's Avatar
    Join Date
    Sep 2003
    Location
    Colorado
    Posts
    2,965

    Re: Classic VB - How can I Hide/Unhide the Form's "X" Button

    A simpler way is to just catch the form close event:
    VB Code:
    1. Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
    2.     If UnloadMode = vbFormControlMenu Or UnloadMode = 1 Then
    3.         'the X has been clicked or the user has pressed Alt+F4
    4.         Cancel = True
    5.     End If
    6. End Sub
    Last edited by si_the_geek; Dec 1st, 2005 at 07:07 PM.

  4. #4
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Classic VB - How can I Hide/Unhide the Form's "X" Button

    This will toggle system menu items. See comments in code
    Code:
    Option Explicit
    Private Declare Function GetSystemMenu Lib "user32.dll" (ByVal hWnd As Long, ByVal bRevert As Long) As Long 'used in clsMenubar and clsButtons
    Private Declare Function GetMenuItemInfo Lib "user32" Alias "GetMenuItemInfoA" (ByVal hMenu As Long, ByVal pID As Long, ByVal byPos As Long, lpMenuItemInfo As Any) As Long
    Private Declare Function SetMenuItemInfo Lib "user32.dll" Alias "SetMenuItemInfoA" (ByVal hMenu As Long, ByVal pID As Long, ByVal byPos As Long, lpcMenuItemInfo As Any) As Long
    Private Declare Function DrawMenuBar Lib "user32.dll" (ByVal hWnd As Long) As Long
    Private Declare Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long 'also used in CustomWindow
    Private Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long 'also used in CustomWindow
    Private Type MENUITEMINFO        ' used to retrieve/store menu items
         cbSize As Long              ' this structure is used with all O/S
         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 Long 'String
         cch As Long
         hBmpData As Long
    End Type
     Private Enum SystemMenuIdEnum
        SC_CLOSE = &HF060&          ' Close menu item & X button
        SC_MAXIMIZE = &HF030&       ' Minimize menu item & button
        SC_MINIMIZE = &HF020&       ' Maximize menu item & button
        SC_MOVE = &HF010&           ' Move menu item & prevent dragging window
        SC_SIZE = &HF000&           ' Size menu item & prevent sizing via borders
       'SC_RESTORE = &HF120&        ' shouldn't need to toggle this, doesn't prevent restore after maximizing/minmizing
    End Enum
    Private Const MIIM_STATE As Long = 1
    Private Const MFS_DISABLED As Long = 3
    
    Private Sub EnableSysMenuItem(ByVal hWnd As Long, ByVal MenuID As SystemMenuIdEnum, ByVal Enable As Boolean)
    
        ' Conflicts with these form properties:
        '   ControlBox = False & not borderless else no system menu exists
        '   MinButton = True else no minimize menu item to toggle
        '   MaxButton = True else no maximize menu item to toggle
        '   Movable = True else toggling has no effect
        '   BorderStyle is not a fixed-style else no size menu item to toggle
        ' Toggling menu items may not prevent manipulation via SendMessage WM_SYSCOMMAND
       
        ' Alt+F4 needs handling if toggling Close menu item else Alt+F4 is always active
        ' Sample code shown below can be replaced by subclassing
        ' -------------------------------------------------------------------------------
        '   Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
        '       If UnloadMode = vbFormControlMenu Then
        '           If IsSysMenuItemEnabled(Me.hWnd, SC_CLOSE) = False Then Cancel = 1
        '       End If
        '   End Sub
        ' -------------------------------------------------------------------------------
       
        Dim hMenu As Long, MII As MENUITEMINFO
        Dim lID As Long, lStyle As Long
        Const MIIM_ID As Long = 2
        Const GWL_STYLE As Long = -16
        Const WS_MAXIMIZEBOX As Long = &H10000
        Const WS_MINIMIZEBOX As Long = &H20000
        Const DISABLE_MASK As Long = &HEFFF&
       
        Select Case MenuID
        Case SC_CLOSE, SC_MOVE, SC_SIZE
        Case SC_MAXIMIZE: lStyle = WS_MAXIMIZEBOX
        Case SC_MINIMIZE: lStyle = WS_MINIMIZEBOX
       'Case SC_RESTORE                             ' un-rem if toggling this
        Case Else: Exit Sub
        End Select
       
        hMenu = GetSystemMenu(hWnd, 0)              ' get system menu handle
        If hMenu = 0 Then Exit Sub                  ' no system menu to manipulate
       
        MII.cbSize = Len(MII)
        MII.fMask = MIIM_ID Or MIIM_STATE
        If Enable = True Then
            lID = MenuID And DISABLE_MASK           ' look for disabled item to re-enable
            MII.fState = 0                          ' set new state & restore old ID
            MII.wID = MenuID
        Else
            lID = MenuID                            ' look for enabled item to disable
            MII.fState = MFS_DISABLED               ' set new state
            If MenuID = SC_CLOSE Then
                MII.fMask = MIIM_STATE              ' set only state, then ID later else X button not grayed out
            Else                                    ' otherwise, set both state & new ID at same time
                MII.wID = MenuID And DISABLE_MASK
            End If
        End If
        If SetMenuItemInfo(hMenu, lID, 0, MII) <> 0 Then
            If lID = SC_CLOSE Then                  ' if disabling X button, change its ID now
                MII.wID = MenuID And DISABLE_MASK
                MII.fMask = MIIM_ID
                SetMenuItemInfo hMenu, MenuID, 0, MII
            ElseIf lStyle <> 0 Then                 ' enable/disable the min/max titlebar graphics as needed
                If Enable = True Then
                    lStyle = GetWindowLong(hWnd, GWL_STYLE) Or lStyle
                Else                                ' if both are disabled, they are removed from titlebar
                    lStyle = GetWindowLong(hWnd, GWL_STYLE) And Not lStyle
                End If
                SetWindowLong hWnd, GWL_STYLE, lStyle
            End If
            DrawMenuBar hWnd                        ' per MSDN always call after calling SetMenuItemInfo
        End If
    
    End Sub
    
    Private Function IsSysMenuItemEnabled(ByVal hWnd As Long, ByVal MenuID As SystemMenuIdEnum) As Boolean
    
        Dim hMenu As Long, MII As MENUITEMINFO
       
        hMenu = GetSystemMenu(hWnd, 0)              ' get system menu handle
        If hMenu <> 0 Then                          ' simply look for passed menu item
            MII.cbSize = Len(MII)                   ' if not there, then custom-disabled else never existed
            MII.fMask = MIIM_STATE                  ' if is there, check its enabled state
            If GetMenuItemInfo(hMenu, MenuID, 0, MII) <> 0 Then
                IsSysMenuItemEnabled = ((MII.fState And MFS_DISABLED) <> MFS_DISABLED)
            End If
        End If
    
    End Function
    Edited: Reason for the DISABLE_MASK? We don't want the disabled menu ID to be a system ID. And if using any value >= &HF000&, Windows sends a WM_SYSCOMMAND message. By ANDing it with the mask, we change the ID so we can find it later to re-enable and also drop it from a system ID to a non-system ID. So, if adding your own custom menu items to the system menu, do not use an ID that begins with &HE in the 2nd byte to be safe, i.e., IDs between 57344 and 61439 (&HE000& thru &HEFFF&) inclusively.
    Last edited by LaVolpe; May 7th, 2020 at 08:57 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width