Visual Basic Window/Form Routines
RemoveMenu: Killing Any Form's Close Menu and 'X' Button - SDI, MDIParent or MDIChild
     
Posted:   Sunday August 15, 1999
Updated:   Monday December 26, 2011
     
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows NT4
OS restrictions:   None
Author:   VBnet - Randy Birch
     

Related:  

RemoveMenu: Killing the Form's Close Menu and 'X' Button
     
 Prerequisites
None.

While the code listed above under Related Topics serves as an excellent method to remove the Close command from a regular form, there may be times when more control is needed. For example, the Killing the From Close method simply removes the last two items from a system menu - regardless of what they are. If that code was applied to an MDI Child window, whose last two system menu items are a separator and the Next command, that code would produce undesired results.

This takes a different approach to achieve the same goal, and because it looks for the actual ID of the Close menu command before removing, will work when applied to any form - MDIParent, MDI Child or SDI form as well. The routine can be repeatedly called without removing more than the desired items.

It is important to note that VB provides intrinsic methods to prevent inadvertent application closure - namely setting Cancel  to True in the QueryUnload or Unload events of any form. This routine therefore is for applications whose integrity is crucial where the developer may need to totally prevent even activation of the shutdown.

Note, as shown in the demo, that child forms spawned from a form with the system menu altered does not inherit that change - in other words the full system menu is added to newly-created forms. If several or all Child forms require the disabling of the Close command, call the sub below in each forms Load event, or in the routine that creates the new child.

 BAS Module Code
Place the following code into the general declarations area of a bas module:

Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright 1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'windows constants
Public Const SWP_DRAWFRAME As Long = &H20
Public Const SWP_NOMOVE As Long = &H2
Public Const SWP_NOSIZE As Long = &H1
Public Const SWP_NOZORDER As Long = &H4
Public Const SWP_FLAGS = SWP_NOZORDER Or SWP_NOSIZE Or _
                         SWP_NOMOVE Or SWP_DRAWFRAME
                    
'menu flags
Public Const MF_BYCOMMAND As Long = &H0
Public Const MF_BYPOSITION As Long = &H400
Public Const MF_REMOVE As Long = &H1000

Public Const MIIM_STATE As Long = &H1
Public Const MIIM_ID As Long = &H2
Public Const MIIM_SUBMENU As Long = &H4
Public Const MIIM_CHECKMARKS As Long = &H8
Public Const MIIM_TYPE As Long = &H10
Public Const MIIM_DATA As Long = &H20
Public Const MFT_STRING As Long = &H0
Public Const MFT_RADIOCHECK As Long = &H200
Public Const MFS_DISABLED As Long = &H3

Public 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

Public Declare Function GetMenuItemInfo Lib "user32" _
    Alias "GetMenuItemInfoA" _
   (ByVal hMenu As Long, ByVal uItem As Long, _
    ByVal fByPosition As Long, lpmii As MENUITEMINFO) As Long

Public Declare Function GetMenuItemCount Lib "user32" _
   (ByVal hMenu As Long) As Long
      
Public Declare Function GetSystemMenu Lib "user32" _
   (ByVal hwnd As Long, _
    ByVal bRevert As Long) As Long
       
Public Declare Function RemoveMenu 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
          
Public Declare Function SetWindowPos Lib "user32" _
    (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, _
     ByVal x As Long, ByVal Y As Long, _
     ByVal cx As Long, ByVal cy As Long, _
     ByVal wFlags As Long) As Long
       

Public Sub MenuRemoveClose(frm As Form)

   Dim c As Long
   Dim hMenu As Long
   Dim mInfo As MENUITEMINFO
   Dim pos As Long
  
  'get the system menu handle
   hMenu = GetSystemMenu(frm.hwnd, 0)

  'loop backwards through the menu
   For c = GetMenuItemCount(hMenu) To 0 Step -1

      With mInfo
         .cbSize = Len(mInfo)
         .fMask = MIIM_TYPE Or MIIM_ID
         .fType = MFT_STRING
         .dwTypeData = Space$(256)
         .cch = Len(mInfo.dwTypeData)
      End With
         
      
     'Retrieve the current MENUITEMINFO.
     'Specifying fByPosition=True indicates
     'uItem points to an item by position.
     'Returns 1 if successful
      If GetMenuItemInfo(hMenu, c, True, mInfo) = 1 Then

        'The close command has an ID of 61536. Once
        'that has been deleted, in a MDI Child window
        'two separators would remain (in a SDI one
        'separator would remain).
        '
        'To assure that this code will cover both
        'MDI and SDI system menus, 1 is subtracted
        'from the item number (c) to remove either
        'the top separator (of the two that will
        'remain in a MDIChild), or the single SDI
        'one (that would remain if this code was
        'applied against a SDI form.)
         If (mInfo.wID = 61536) Then
         
            Call RemoveMenu(hMenu, c, _
                            MF_REMOVE Or MF_BYPOSITION)
                         
            Call RemoveMenu(hMenu, c - 1, _
                            MF_REMOVE Or MF_BYPOSITION)
            
         End If
         
      End If
      
   Next
   
  'force a redraw of the non-client
  'area of the form to cause the
  'disabled X to paint correctly
   Call SetWindowPos(frm.hwnd, 0, 0, 0, 0, 0, SWP_FLAGS)
   Call DrawMenuBar(frm.hwnd)
   
End Sub
 Form Code
Create an MDI app with a MDI parent (MDIForm1), and a single MDI Child (Form1). On the MDI Child, add two command buttons (Comand1 & Command2). Add the following code the form indicated:

Option Explicit

'MDI Parent Form (MDIForm1) Code:

Option Explicit

Private Sub MDIForm_Load()

 'position the form
  Me.Move (Screen.Width - Me.Width) \ 2, (Screen.Height - Me.Height) \ 2
  
End Sub


Private Sub MDIForm_DblClick()

   Dim f As New Form1
   f.Show

End Sub


'MDI Child Form (Form1) Code

Option Explicit

Private Sub Command1_Click()

   Call MenuRemoveClose(MDIForm1)

End Sub


Private Sub Command2_Click()

   Call MenuRemoveClose(Me)
   
End Sub
 Comments
Set the project startup form to Form1, and run.

 
 

PayPal Link
Make payments with PayPal - it's fast, free and secure!

 
 
 
 

Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy

 

Hit Counter