|
-
May 6th, 2020, 09:53 AM
#4
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.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|