PiToLoKo

SystemMenuManager written in VB.NET

Feb 20th, 2014
276
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VB.NET 56.40 KB | None | 0 0
  1.  
  2. ' ***********************************************************************
  3. ' Author   : Elektro
  4. ' Modified : 11-20-2013
  5. ' ***********************************************************************
  6. ' <copyright file="SystemMenuManager.vb" company="Elektro Studios">
  7. '     Copyright (c) Elektro Studios. All rights reserved.
  8. ' </copyright>
  9. ' ***********************************************************************er
  10.  
  11. #Region " Usage Examples "
  12.  
  13. ' Public Class Form1
  14.  
  15. ' Private WithEvents SystemMenu As New SystemMenuManager(Me)
  16.  
  17. ' Private Shadows Sub Shown() Handles MyBase.Shown
  18.  
  19. '' Disable the menu
  20. ' SystemMenu.DisableMenu()
  21.  
  22. '' Enable the menu
  23. ' SystemMenu.EnableMenu()
  24.  
  25. '' Gets the total amount of menu items.
  26. ' MsgBox(SystemMenu.GetItemCount())
  27.  
  28. '' Sets the menu background color.
  29. ' SystemMenu.SetMenuBackColor(Color.Teal)
  30.  
  31. '' Sets the menu style.
  32. ' SystemMenu.SetMenuStyle(SystemMenuManager.MenuStyle.AUTODISMIS)
  33.  
  34. '' Sets the state of the Close button and menu item.
  35. ' SystemMenu.SetItemState(SystemMenuManager.Item.Close, SystemMenuManager.ItemState.Disabled)
  36.  
  37. '' Sets the Bitmap image of the Move menu item.
  38. ' SystemMenu.SetItemBitmap(SystemMenuManager.Item.Move, New Bitmap("C:\File.png"))
  39.  
  40. '' Gets the Bitmap image of the Move menu item.
  41. ' Dim bmp As Bitmap = SystemMenu.GetItemBitmap(SystemMenuManager.Item.Move)
  42.  
  43. '' Removes the Bitmap image of the Move menu item.
  44. ' SystemMenu.RemoveItemBitmap(SystemMenuManager.Item.Move)
  45.  
  46. '' Adds a separator at the bottom.
  47. ' SystemMenu.AddSeparator(SystemMenuManager.DefaultPositions.Last)
  48.  
  49. '' Adds an item at the bottom.
  50. ' SystemMenu.AddItem("Hello World!", 666, SystemMenuManager.DefaultPositions.Last)
  51.  
  52. '' Gets the ID of an item.
  53. ' MsgBox(SystemMenu.GetItemState(SystemMenuManager.Item.Move).ToString)
  54.  
  55. '' Gets the text of an item.
  56. ' MsgBox(SystemMenu.GetItemText(SystemMenuManager.Item.Move))
  57.  
  58. '' Gets the state of an item.
  59. ' MsgBox(SystemMenu.GetItemState(SystemMenuManager.Item.Move).ToString)
  60.  
  61. '' Sets the text of an item.
  62. ' SystemMenu.SetItemText(SystemMenuManager.Item.Move, "Muéveme")
  63.  
  64. '' Checks if a handle is a menu handle.
  65. ' MsgBox(SystemMenu.IsMenuHandle(IntPtr.Zero))
  66.  
  67. '' Disable all the menu items.
  68. ' SystemMenu.DisableAllItems()
  69.  
  70. '' Re-enable all the menu items.
  71. ' SystemMenu.EnableAllItems()
  72.  
  73. '' Remove all the menu items.
  74. ' SystemMenu.RemoveAllItems()
  75.  
  76. '' Restore the menu to defaults.
  77. ' SystemMenu.Restore_Menu()
  78.  
  79. '' Dispose the SystemMenuManager Object.
  80. ' SystemMenu.Dispose()
  81.  
  82. 'End Sub
  83.  
  84. ' ' SystemMenu [MenuItemClicked]
  85. 'Private Sub SystemMenu_MenuItemClicked(
  86. '        ByVal MenuHandle As IntPtr,
  87. '        ByVal e As SystemMenuManager.ItemClickedEventArgs
  88. ') Handles SystemMenu.ItemClicked
  89.  
  90. '    Dim sr As New System.Text.StringBuilder
  91.  
  92. '    sr.AppendLine(String.Format("Item ID   : {0}", CStr(e.ID)))
  93. '    sr.AppendLine(String.Format("Item Text : {0}", e.Text))
  94. '    sr.AppendLine(String.Format("Item Type : {0}", e.Type.ToString))
  95. '    sr.AppendLine(String.Format("Item State: {0}", e.State.ToString))
  96.  
  97. '    MessageBox.Show(sr.ToString, "SystemMenuManager", MessageBoxButtons.OK, MessageBoxIcon.Information)
  98.  
  99. ' End Sub
  100.  
  101. ' End Class
  102.  
  103. #End Region
  104.  
  105. #Region " SystemMenu Manager "
  106.  
  107. Public Class SystemMenuManager
  108.     Inherits NativeWindow
  109.     Implements IDisposable
  110.  
  111.     ' ----------------------------
  112.     ' MSDN documentation Reference
  113.     ' ----------------------------
  114.     ' Menu Functions: http://msdn.microsoft.com/en-us/library/windows/desktop/ff468865%28v=vs.85%29.aspx
  115.     ' MenuItemInfo  : http://msdn.microsoft.com/en-us/library/windows/desktop/ms647578%28v=vs.85%29.aspx
  116.     ' MenuInfo      : http://msdn.microsoft.com/en-us/library/windows/desktop/ms647575%28v=vs.85%29.aspx
  117.  
  118. #Region " Variables "
  119.  
  120.     ''' <summary>
  121.     ''' The form for which the system menu will be managed.
  122.     ''' </summary>
  123.     Private WithEvents form As Form = Nothing
  124.  
  125.     ''' <summary>
  126.     ''' The handle of the form's system menu.
  127.     ''' </summary>
  128.     Private MenuHandle As IntPtr = IntPtr.Zero
  129.  
  130.     ''' <summary>
  131.     ''' Stores a MenuInfo structure.
  132.     ''' </summary>
  133.     Private mi As New MenuInfo
  134.  
  135.     ''' <summary>
  136.     ''' Stores a menuiteminfo structure.
  137.     ''' </summary>
  138.     Private mii As New MenuItemInfo
  139.  
  140.     ''' <summary>
  141.     ''' Indicates if the system menu should be enabled or disabled.
  142.     ''' </summary>
  143.     Private Property IsMenuEnabled As Boolean = True
  144.  
  145.     ''' <summary>
  146.     ''' Stores a menu item Text.
  147.     ''' </summary>
  148.     Private ItemText As New System.Text.StringBuilder With {.Capacity = 260}
  149.  
  150.     ''' <summary>
  151.     ''' Brush used to paint the menu background.
  152.     ''' </summary>
  153.     Private MenuBrush As IntPtr = IntPtr.Zero
  154.  
  155.     ''' <summary>
  156.     ''' Stores the ItemClickedEventArgs members.
  157.     ''' </summary>
  158.     Private ItemClickedArgs As New ItemClickedEventArgs
  159.  
  160.     ''' <summary>
  161.     ''' The State of the Close item.
  162.     ''' </summary>
  163.     Private CloseItem_State As ItemState = ItemState.Enabled
  164.  
  165.     ''' <summary>
  166.     ''' Stores the current state of each MenuItem.
  167.     ''' </summary>
  168.     Private ItemStates As New Dictionary(Of Item, ItemState) From
  169.         {
  170.           {Item.Close, Nothing},
  171.           {Item.Move, Nothing},
  172.           {Item.Maximize, Nothing},
  173.           {Item.Minimize, Nothing},
  174.           {Item.Restore, Nothing},
  175.           {Item.Size, Nothing}
  176.         }
  177.  
  178.     ''' <summary>
  179.     ''' Stores the Bitmap image of each MenuItem.
  180.     ''' </summary>
  181.     Private ItemBitmaps As New Dictionary(Of Item, Bitmap) From
  182.         {
  183.           {Item.Close, Nothing},
  184.           {Item.Move, Nothing},
  185.           {Item.Maximize, Nothing},
  186.           {Item.Minimize, Nothing},
  187.           {Item.Restore, Nothing},
  188.           {Item.Size, Nothing}
  189.         }
  190.  
  191.     ''' <summary>
  192.     ''' Stores the current state of each MenuItem specified by position.
  193.     ''' </summary>
  194.     Private PositionItemStates As New Dictionary(Of Integer, ItemState)
  195.  
  196.     ''' <summary>
  197.     ''' Stores the Bitmap image of each MenuItem specified by position.
  198.     ''' </summary>
  199.     Private PositionItemBitmaps As New Dictionary(Of Integer, Bitmap)
  200.  
  201. #End Region ' Variables
  202.  
  203. #Region " Events "
  204.  
  205.     ''' <summary>
  206.     ''' Event raised when a menu item is clicked.
  207.     ''' </summary>
  208.     Public Event ItemClicked As EventHandler(Of ItemClickedEventArgs)
  209.     Public Class ItemClickedEventArgs : Inherits EventArgs
  210.         ''' <summary>
  211.         ''' Item Identifier.
  212.         ''' </summary>
  213.         Public Property ID As Integer
  214.         ''' <summary>
  215.         ''' Item Text.
  216.         ''' </summary>
  217.         Public Property Text As String
  218.         ''' <summary>
  219.         ''' Item State.
  220.         ''' </summary>
  221.         Public Property State As ItemState
  222.         ''' <summary>
  223.         ''' Item Type.
  224.         ''' </summary>
  225.         Public Property Type As ItemType
  226.     End Class
  227.  
  228. #End Region ' Events
  229.  
  230. #Region " Enumerations "
  231.  
  232.     ''' <summary>
  233.     ''' The menu Position ttype.
  234.     ''' </summary>
  235.     Public Enum ItemPosition As Integer
  236.  
  237.         ''' <summary>
  238.         ''' The menu item is specified by command.
  239.         ''' </summary>
  240.         ByCommand = &H0
  241.  
  242.         ''' <summary>
  243.         ''' The menu item is specified by position.
  244.         ''' </summary>
  245.         ByPosition = &H410
  246.  
  247.     End Enum
  248.  
  249.     ''' <summary>
  250.     ''' The Menu Items.
  251.     ''' </summary>
  252.     Public Enum Item As Integer
  253.  
  254.         ''' <summary>
  255.         ''' Closes the window.
  256.         ''' </summary>
  257.         Close = &HF060
  258.  
  259.         ''' <summary>
  260.         ''' Moves the window.
  261.         ''' </summary>
  262.         Move = &HF010
  263.  
  264.         ''' <summary>
  265.         ''' Maximizes the window.
  266.         ''' </summary>
  267.         Maximize = &HF030
  268.  
  269.         ''' <summary>
  270.         ''' Minimizes the window.
  271.         ''' </summary>
  272.         Minimize = &HF020
  273.  
  274.         ''' <summary>
  275.         ''' Restores the window to its normal position and size.
  276.         ''' </summary>
  277.         Restore = &HF120
  278.  
  279.         ''' <summary>
  280.         ''' Sizes the window.
  281.         ''' </summary>
  282.         Size = &HF000
  283.  
  284.     End Enum
  285.  
  286.     ''' <summary>
  287.     ''' The states that a menu item can have.
  288.     ''' </summary>
  289.     Public Enum ItemState As Integer
  290.  
  291.         ''' <summary>
  292.         ''' The menu item is present and can be selected.
  293.         ''' </summary>
  294.         ''' <remarks>
  295.         ''' This is the default state.
  296.         ''' </remarks>
  297.         Enabled = &H0
  298.  
  299.         ''' <summary>
  300.         ''' The menu item is present but greyed-out and cannot be selected.
  301.         ''' </summary>
  302.         Grayed = &H1
  303.  
  304.         ''' <summary>
  305.         ''' The menu item is present but can not be selected.
  306.         ''' </summary>
  307.         Disabled = &H2
  308.  
  309.         ''' <summary>
  310.         ''' The menu item is not present.
  311.         ''' </summary>
  312.         Removed = -1
  313.  
  314.     End Enum
  315.  
  316.     ''' <summary>
  317.     ''' Predefined menu item positions.
  318.     ''' </summary>
  319.     Public Enum DefaultPositions As Short
  320.  
  321.         ''' <summary>
  322.         ''' Top position.
  323.         ''' </summary>
  324.         First = 0
  325.  
  326.         ''' <summary>
  327.         ''' Second position.
  328.         ''' </summary>
  329.         Second = 1
  330.  
  331.         ''' <summary>
  332.         ''' Third position.
  333.         ''' </summary>
  334.         Third = 2
  335.  
  336.         ''' <summary>
  337.         ''' Middle position.
  338.         ''' </summary>
  339.         Middle = 3
  340.  
  341.         ''' <summary>
  342.         ''' Penultimate position.
  343.         ''' </summary>
  344.         Penultimate = 4
  345.  
  346.         ''' <summary>
  347.         ''' Bottom position.
  348.         ''' </summary>
  349.         Last = 5
  350.  
  351.     End Enum
  352.  
  353.     ''' <summary>
  354.     ''' Mask type of the MenuItemInfo structure.
  355.     ''' </summary>
  356.     Public Enum ItemMask As Integer
  357.  
  358.         ''' <summary>
  359.         ''' Retrieves or sets the "hbmpItem" member.
  360.         ''' </summary>
  361.         BITMAP = &H80
  362.  
  363.         ''' <summary>
  364.         ''' Retrieves or sets the "hbmpChecked" and "hbmpUnchecked" members.
  365.         ''' </summary>
  366.         CHECKMARKS = &H8
  367.  
  368.         ''' <summary>
  369.         ''' Retrieves or sets the "dwItemData" member.
  370.         ''' </summary>
  371.         DATA = &H20
  372.  
  373.         ''' <summary>
  374.         ''' Retrieves or sets the "fType" member.
  375.         ''' </summary>
  376.         FTYPE = &H100
  377.  
  378.         ''' <summary>
  379.         ''' Retrieves or sets the "wID" member.
  380.         ''' </summary>
  381.         ID = &H2
  382.  
  383.         ''' <summary>
  384.         ''' Retrieves or sets the "fState" member.
  385.         ''' </summary>
  386.         STATE = &H1
  387.  
  388.         ''' <summary>
  389.         ''' Retrieves or sets the "dwTypeData" member.
  390.         ''' </summary>
  391.         TEXT = &H40
  392.  
  393.         ''' <summary>
  394.         ''' Retrieves or sets the "hSubMenu" member.
  395.         ''' </summary>
  396.         SUBMENU = &H4
  397.  
  398.         ''' <summary>
  399.         ''' Retrieves or sets the "fType" and "dwTypeData" members.
  400.         ''' "ItemMask.TYPE" is replaced by "ItemMask.BITMAP", "ItemMask.FTYPE", and "ItemMask.TEXT".
  401.         ''' </summary>
  402.         TYPE = &H10
  403.  
  404.     End Enum
  405.  
  406.     ''' <summary>
  407.     ''' Item Type of the MenuItemInfo structure.
  408.     ''' </summary>
  409.     Public Enum ItemType As Long
  410.  
  411.         ''' <summary>
  412.         ''' Displays the menu item using a bitmap.
  413.         ''' The low-order word of the dwTypeData member is the bitmap handle, and the cch member is ignored.
  414.         ''' "ItemType.BITMAP" is replaced by "ItemMask.BITMAP" and "hbmpItem".
  415.         ''' </summary>
  416.         BITMAP = &H4L
  417.  
  418.         ''' <summary>
  419.         ''' Displays selected menu items using a radio-button mark instead of a check mark if the hbmpChecked member is NULL.
  420.         ''' </summary>
  421.         RADIOCHECK = &H200L
  422.  
  423.         ''' <summary>
  424.         ''' Specifies that the menu item is a separator.
  425.         ''' A menu item separator appears as a horizontal dividing line.
  426.         ''' The dwTypeData and cch members are ignored.
  427.         ''' This value is valid only in a drop-down menu, submenu, or shortcut menu.
  428.         ''' </summary>
  429.         SEPARATOR = &H800L
  430.  
  431.         ''' <summary>
  432.         ''' Displays the menu item using a text string.
  433.         ''' The dwTypeData member is the pointer to a null-terminated string,
  434.         ''' and the cch member is the length of the string.
  435.         ''' "ItemType.TEXT" is replaced by "ItemMask.TEXT".
  436.         ''' </summary>
  437.         TEXT = &H0L
  438.  
  439.         ''' <summary>
  440.         ''' Right-justifies the menu item and any subsequent items.
  441.         ''' This value is valid only if the menu item is in a menu bar.
  442.         ''' </summary>
  443.         RIGHTJUSTIFY = &H4000L
  444.  
  445.         ''' <summary>
  446.         ''' Specifies that menus cascade right-to-left (the default is left-to-right).
  447.         ''' This is used to support right-to-left languages, such as Arabic and Hebrew.
  448.         ''' </summary>
  449.         RIGHTORDER = &H2000L
  450.  
  451.         ''' <summary>
  452.         ''' Places the menu item on a new line (for a menu bar),
  453.         ''' or in a new column (for a drop-down menu, submenu, or shortcut menu).
  454.         ''' For a drop-down menu, submenu, or shortcut menu, a vertical line separates the new column from the old.
  455.         ''' </summary>
  456.         MENUBARBREAK = &H20L
  457.  
  458.         ''' <summary>
  459.         ''' Places the menu item on a new line (for a menu bar),
  460.         ''' or in a new column (for a drop-down menu, submenu, or shortcut menu).
  461.         ''' For a drop-down menu, submenu, or shortcut menu, the columns are not separated by a vertical line.
  462.         ''' </summary>
  463.         MENUBREAK = &H40L
  464.  
  465.         ''' <summary>
  466.         ''' Assigns responsibility for drawing the menu item to the window that owns the menu.
  467.         ''' The window receives a "WM_MEASUREITEM" message before the menu is displayed for the first time,
  468.         ''' and a "WM_DRAWITEM" message whenever the appearance of the menu item must be updated.
  469.         ''' If this value is specified, the dwTypeData member contains an application-defined value.
  470.         ''' </summary>
  471.         OWNERDRAW = &H100L
  472.  
  473.     End Enum
  474.  
  475.     ''' <summary>
  476.     ''' Mask type of the MenuInfo structure.
  477.     ''' Indicates the members to be retrieved or set (except for "MenuMask.APPLYTOSUBMENUS").
  478.     ''' This member can be one or more of the following values.
  479.     ''' </summary>
  480.     Public Enum MenuMask As Integer
  481.  
  482.         ''' <summary>
  483.         ''' Settings apply to the menu and all of its submenus.
  484.         ''' "SetMenuInfo" API function uses this flag and "GetMenuInfo" API function ignores this flag.
  485.         ''' </summary>
  486.         APPLYTOSUBMENUS = &H80000000
  487.  
  488.         ''' <summary>
  489.         ''' Retrieves or sets the hbrBack member.
  490.         ''' </summary>
  491.         BACKGROUND = &H2
  492.  
  493.         ''' <summary>
  494.         ''' Retrieves or sets the dwContextHelpID member.
  495.         ''' </summary>
  496.         HELPID = &H4
  497.  
  498.         ''' <summary>
  499.         ''' Retrieves or sets the cyMax member.
  500.         ''' </summary>
  501.         MAXHEIGHT = &H1
  502.  
  503.         ''' <summary>
  504.         ''' Retrieves or sets the dwMenuData member.
  505.         ''' </summary>
  506.         MENUDATA = &H8
  507.  
  508.         ''' <summary>
  509.         ''' Retrieves or sets the dwStyle member.
  510.         ''' </summary>
  511.         STYLE = &H10
  512.  
  513.     End Enum
  514.  
  515.     ''' <summary>
  516.     ''' The menu style.
  517.     ''' This member can be one or more of the following values.
  518.     ''' </summary>
  519.     Public Enum MenuStyle As Integer
  520.  
  521.         ''' <summary>
  522.         ''' Menu automatically ends when mouse is outside the menu for approximately 10 seconds..
  523.         ''' </summary>
  524.         AUTODISMIS = &H10000000
  525.  
  526.         ''' <summary>
  527.         ''' The same space is reserved for the check mark and the bitmap.
  528.         ''' If the check mark is drawn, the bitmap is not.
  529.         ''' All checkmarks and bitmaps are aligned.
  530.         ''' Used for menus where some items use checkmarks and some use bitmaps.
  531.         ''' </summary>
  532.         CHECKORBMP = &H4000000
  533.  
  534.         ''' <summary>
  535.         ''' Menu items are OLE drop targets or drag sources.
  536.         ''' Menu owner receives "WM_MENUDRAG" and "WM_MENUGETOBJECT" messages.
  537.         ''' </summary>
  538.         DRAGDROP = &H20000000
  539.  
  540.         ''' <summary>
  541.         ''' Menu is modeless; that is,
  542.         ''' there is no menu modal message loop while the menu is active.
  543.         ''' </summary>
  544.         MODELESS = &H40000000
  545.  
  546.         ''' <summary>
  547.         ''' No space is reserved to the left of an item for a check mark.
  548.         ''' The item can still be selected, but the check mark will not appear next to the item.
  549.         ''' </summary>
  550.         NOCHECK = &H80000000
  551.  
  552.         ''' <summary>
  553.         ''' Menu owner receives a "WM_MENUCOMMAND" message,
  554.         ''' instead of a "WM_COMMAND" message, when the user makes a selection.
  555.         ''' "MenuStyle.NOTIFYBYPOS" is a menu header style and has no effect when applied to individual sub menus.
  556.         ''' </summary>
  557.         NOTIFYBYPOS = &H8000000
  558.  
  559.     End Enum
  560.  
  561. #End Region ' Enumerations
  562.  
  563. #Region " APIs "
  564.  
  565.     '''' <summary>
  566.     '''' Creates an empty menu.
  567.     '''' </summary>
  568.     ' <Runtime.InteropServices.
  569.     ' DllImport("user32.dll")>
  570.     ' Private Shared Function CreateMenu() As IntPtr
  571.     ' End Function
  572.  
  573.     '''' <summary>
  574.     '''' Assigns a new menu to the specified window.
  575.     '''' </summary>
  576.     '<DllImport("user32.dll")> _
  577.     'Public Shared Function SetMenu(
  578.     '       ByVal hWnd As IntPtr,
  579.     '       ByVal hMenu As IntPtr
  580.     ') As Boolean
  581.     'End Function
  582.  
  583.     ''' <summary>
  584.     ''' Gets the handle of the form's system menu.
  585.     ''' </summary>
  586.     ''' <param name="hWnd">
  587.     ''' The handle of the form for which to get the system menu.
  588.     ''' </param>
  589.     ''' <param name="bRevert">
  590.     ''' Indicates whether the menu should be reset to its original state.
  591.     ''' </param>
  592.     ''' <returns>
  593.     ''' The handle of the system menu of the specified form.
  594.     ''' </returns>
  595.     <Runtime.InteropServices.
  596.     DllImport("user32.dll")>
  597.     Private Shared Function GetSystemMenu(
  598.             ByVal hWnd As IntPtr,
  599.             ByVal bRevert As Integer
  600.     ) As IntPtr
  601.     End Function
  602.  
  603.     ''' <summary>
  604.     ''' Sets the state of the specified menu item.
  605.     ''' </summary>
  606.     ''' <returns>
  607.     ''' The previous state of the menu item if it exists, -1 otherwise.
  608.     ''' </returns>
  609.     <Runtime.InteropServices.
  610.     DllImport("user32.dll")>
  611.     Private Shared Function EnableMenuItem(
  612.             ByVal hMenu As IntPtr,
  613.             ByVal wIDEnableItem As UInteger,
  614.             ByVal wEnable As UInteger
  615.     ) As IntPtr
  616.     End Function
  617.  
  618.     ''' <summary>
  619.     ''' Determines the number of items in the specified menu.
  620.     ''' </summary>
  621.     <Runtime.InteropServices.
  622.     DllImport("user32.dll")>
  623.     Private Shared Function GetMenuItemCount(
  624.             ByVal hMenu As IntPtr
  625.     ) As Integer
  626.     End Function
  627.  
  628.     ''' <summary>
  629.     ''' Associates the specified bitmap with a menu item.
  630.     ''' Whether the menu item is selected or clear,
  631.     ''' the system displays the appropriate bitmap next to the menu item.
  632.     ''' </summary>
  633.     <Runtime.InteropServices.
  634.     DllImport("user32.dll")>
  635.     Private Shared Function SetMenuItemBitmaps(
  636.             ByVal hMenu As IntPtr,
  637.             ByVal uPosition As UInteger,
  638.             ByVal uFlags As UInteger,
  639.             ByVal hBitmapUnchecked As IntPtr,
  640.             ByVal hBitmapChecked As IntPtr
  641.     ) As Boolean
  642.     End Function
  643.  
  644.     ''' <summary>
  645.     ''' Destroys the specified menu and frees any memory that the menu occupies.
  646.     ''' </summary>
  647.     <Runtime.InteropServices.
  648.     DllImport("user32.dll")>
  649.     Private Shared Function DestroyMenu(
  650.             ByVal hMenu As IntPtr
  651.     ) As Boolean
  652.     End Function
  653.  
  654.     ''' <summary>
  655.     ''' Determines whether a handle is a menu handle.
  656.     ''' </summary>
  657.     <Runtime.InteropServices.
  658.     DllImport("user32.dll")>
  659.     Private Shared Function IsMenu(
  660.             ByVal hMenu As IntPtr
  661.     ) As Boolean
  662.     End Function
  663.  
  664.     ''' <summary>
  665.     ''' Insert a menu item into an existing menu.
  666.     ''' </summary>
  667.     <Runtime.InteropServices.
  668.     DllImport("user32.dll",
  669.     SetLastError:=True,
  670.     CharSet:=Runtime.InteropServices.CharSet.Auto)>
  671.     Friend Shared Function InsertMenuItem(
  672.            ByVal hMenu As IntPtr, ByVal uItem As Integer,
  673.            ByVal fByPosition As Boolean,
  674.            ByRef lpmii As MenuItemInfo
  675.     ) As Boolean
  676.     End Function
  677.  
  678.     ''' <summary>
  679.     ''' Deletes the specified menu item.
  680.     ''' </summary>
  681.     ''' <returns>
  682.     ''' Non-zero if the function succeeds,
  683.     ''' zero otherwise.
  684.     ''' </returns>
  685.     <Runtime.InteropServices.
  686.     DllImport("user32.dll")>
  687.     Private Shared Function DeleteMenu(
  688.             ByVal hMenu As IntPtr,
  689.             ByVal uPosition As UInteger,
  690.             ByVal uFlags As UInteger
  691.     ) As Boolean
  692.     End Function
  693.  
  694.     ''' <summary>
  695.     ''' Ends the calling thread's active menu
  696.     ''' </summary>
  697.     <Runtime.InteropServices.
  698.     DllImport("user32.dll")>
  699.     Private Shared Function EndMenu() As Boolean
  700.     End Function
  701.  
  702.     ''' <summary>
  703.     ''' Gets the ID of a menu item.
  704.     ''' </summary>
  705.     <Runtime.InteropServices.
  706.     DllImport("user32.dll")>
  707.     Public Shared Function GetMenuItemID(
  708.             ByVal hMenu As IntPtr,
  709.             ByVal nPos As Integer
  710.     ) As Integer
  711.     End Function
  712.  
  713.     ''' <summary>
  714.     ''' Gets the text of a menu item.
  715.     ''' </summary>
  716.     <Runtime.InteropServices.
  717.     DllImport("user32.dll")>
  718.     Private Shared Function GetMenuString(
  719.             ByVal hMenu As IntPtr,
  720.             ByVal uIDItem As UInteger,
  721.             <Runtime.InteropServices.Out,
  722.             Runtime.InteropServices.MarshalAs(
  723.             Runtime.InteropServices.UnmanagedType.LPStr)>
  724.             ByVal lpString As System.Text.StringBuilder,
  725.             ByVal nMaxCount As Integer,
  726.             ByVal uFlag As UInteger
  727.     ) As Integer
  728.     End Function
  729.  
  730.     ''' <summary>
  731.     ''' Gets the State of a menu item.
  732.     ''' </summary>
  733.     <Runtime.InteropServices.
  734.     DllImport("user32.dll")>
  735.     Private Shared Function GetMenuState(
  736.             ByVal hMenu As IntPtr,
  737.             ByVal uId As UInteger,
  738.             ByVal uFlags As UInteger
  739.     ) As UInteger
  740.     End Function
  741.  
  742.     ''' <summary>
  743.     ''' Gets the handle of the form's system menu.
  744.     ''' </summary>
  745.     ''' <param name="hMenu">
  746.     ''' The handle to the menu that contains the menu item.
  747.     ''' </param>
  748.     ''' <param name="uItem">
  749.     ''' The identifier or position of the menu item to get information about.
  750.     ''' The meaning of this parameter depends on the value of fByPosition.
  751.     ''' </param>
  752.     ''' <param name="fByPosition">
  753.     ''' The meaning of uItem.
  754.     ''' If this parameter is FALSE, uItem is a menu item identifier,
  755.     ''' If this parameter is TRUE, it is a menu item position.
  756.     ''' </param>
  757.     ''' <param name="lpmii">
  758.     ''' A pointer to a MenuItemInfo structure that specifies the information to retrieve.
  759.     ''' Note that you must set the cbSize member to sizeof(MENUITEMINFO) before calling this function.
  760.     ''' </param>
  761.     <Runtime.InteropServices.
  762.     DllImport("user32.dll",
  763.     CharSet:=Runtime.InteropServices.CharSet.Auto)> _
  764.     Private Shared Function GetMenuItemInfo(
  765.             ByVal hMenu As IntPtr,
  766.             ByVal uItem As UInteger,
  767.             ByVal fByPosition As Boolean,
  768.             ByRef lpmii As MenuItemInfo
  769.     ) As Boolean
  770.     End Function
  771.  
  772.     ''' <summary>
  773.     ''' Sets information for a specified menu..
  774.     ''' </summary>
  775.     ''' <param name="hMenu">
  776.     ''' The handle to the menu that contains the menu item.
  777.     ''' </param>
  778.     ''' <param name="lpcmi">
  779.     ''' A pointer to a MENUINFO structure that specifies the information to retrieve.
  780.     ''' </param>
  781.     <Runtime.InteropServices.
  782.     DllImport("user32.dll")>
  783.     Private Shared Function SetMenuInfo(
  784.             ByVal hmenu As IntPtr,
  785.             <Runtime.InteropServices.[In]>
  786.             ByRef lpcmi As MenuInfo
  787.     ) As Boolean
  788.     End Function
  789.  
  790.     ''' <summary>
  791.     ''' Creates a logical brush that has the specified solid color.
  792.     ''' A solid brush is a bitmap that the system uses to paint the interiors of filled shapes.
  793.     ''' After an application creates a brush by calling CreateSolidBrush,
  794.     ''' it can select that brush into any device context by calling the "SelectObject" API function.
  795.     ''' When you no longer need the brush, call the "DeleteObject" API function to delete it.
  796.     ''' </summary>
  797.     <Runtime.InteropServices.
  798.     DllImport("gdi32.dll")>
  799.     Private Shared Function CreateSolidBrush(
  800.             ByVal crColor As UInteger
  801.     ) As IntPtr
  802.     End Function
  803.  
  804.     ' ''' <summary>
  805.     ' ''' Selects an object into a specified device context.
  806.     ' ''' The new object replaces the previous object of the same type.
  807.     ' ''' </summary>
  808.     '<Runtime.InteropServices.
  809.     'DllImport("gdi32.dll")>
  810.     'Public Shared Function SelectObject(
  811.     '       ByVal hdc As IntPtr,
  812.     '       ByVal hObject As IntPtr
  813.     ') As IntPtr
  814.     'End Function
  815.  
  816.     ''' <summary>
  817.     ''' Deletes a logical pen, brush, font, bitmap, region, or palette,
  818.     ''' freeing all system resources associated with the object.
  819.     ''' After the object is deleted, the specified handle is no longer valid.
  820.     ''' </summary>
  821.     <Runtime.InteropServices.
  822.     DllImport("gdi32.dll")>
  823.     Private Shared Function DeleteObject(
  824.             ByVal hObject As IntPtr
  825.     ) As <Runtime.InteropServices.MarshalAs(
  826.           Runtime.InteropServices.UnmanagedType.Bool)> Boolean
  827.     End Function
  828.  
  829.     ''' <summary>
  830.     ''' Changes information about a menu item.
  831.     ''' </summary>
  832.     ''' <param name="hMenu ">
  833.     ''' A handle to the menu that contains the menu item.
  834.     ''' </param>
  835.     ''' <param name="uItem">
  836.     ''' The identifier or position of the menu item to change.
  837.     ''' The meaning of this parameter depends on the value of fByPosition.
  838.     ''' </param>
  839.     ''' <param name="fByPosition">
  840.     ''' The meaning of "uItem".
  841.     ''' If this parameter is set to "FALSE", "uItem" is a menu item identifier.
  842.     ''' Otherwise, it is a menu item position.
  843.     ''' </param>
  844.     ''' <param name="lpmii">
  845.     ''' A pointer to a MenuItemInfo structure that contains information about the menu item,
  846.     ''' and specifies which menu item attributes to change.
  847.     ''' </param>
  848.     <Runtime.InteropServices.
  849.     DllImport("user32.dll",
  850.     SetLastError:=True,
  851.     CharSet:=Runtime.InteropServices.CharSet.Auto)>
  852.     Private Shared Function SetMenuItemInfo(
  853.             ByVal hMenu As IntPtr,
  854.             ByVal uItem As UInteger,
  855.             ByVal fByPosition As Boolean,
  856.             <Runtime.InteropServices.[In]>
  857.             ByRef lpmii As MenuItemInfo
  858.     ) As Boolean
  859.     End Function
  860.  
  861. #End Region ' APIs
  862.  
  863. #Region " Structures "
  864.  
  865.     ''' <summary>
  866.     ''' MenuItemInfo Structure,
  867.     ''' Contains information about a menu,
  868.     ''' Is used to set menu information.
  869.     ''' </summary>
  870.     <Runtime.InteropServices.
  871.     StructLayout(Runtime.InteropServices.LayoutKind.Sequential,
  872.     CharSet:=Runtime.InteropServices.CharSet.Auto)>
  873.     Public Structure MenuInfo
  874.  
  875.         ''' <summary>
  876.         ''' The size of the structure, in bytes.
  877.         ''' The caller must set this member to sizeof(MenuInfo).
  878.         ''' </summary>
  879.         Public cbSize As UInteger
  880.  
  881.         ''' <summary>
  882.         ''' Indicates the members to be retrieved or set (except for "MenuMask.APPLYTOSUBMENUS").
  883.         ''' This member can be one or more of the "MenuMask" Enum values.
  884.         ''' </summary>
  885.         Public fMask As UInteger
  886.  
  887.         ''' <summary>
  888.         ''' The menu style.
  889.         ''' This member can be one or more of the following values.
  890.         ''' </summary>
  891.         Public dwStyle As UInteger
  892.  
  893.         ''' <summary>
  894.         ''' The maximum height of the menu in pixels.
  895.         ''' When the menu items exceed the space available, scroll bars are automatically used.
  896.         ''' The default (0) is the screen height.
  897.         ''' </summary>
  898.         Public cyMax As UInteger
  899.  
  900.         ''' <summary>
  901.         ''' A handle to the brush to be used for the menu's background.
  902.         ''' </summary>
  903.         Public hbrBack As IntPtr
  904.  
  905.         ''' <summary>
  906.         ''' The context help identifier.
  907.         ''' This is the same value used in the "GetMenuContextHelpId" and "SetMenuContextHelpId" API functions.
  908.         ''' </summary>
  909.         Public dwContextHelpID As UInteger
  910.  
  911.         ''' <summary>
  912.         ''' An application-defined value.
  913.         ''' </summary>
  914.         Public dwMenuData As UIntPtr
  915.  
  916.     End Structure
  917.  
  918.     ''' <summary>
  919.     ''' MenuItemInfo Structure,
  920.     ''' Contains information about a menu item,
  921.     ''' Is used to set a menu item info,
  922.     ''' to add a new item or to get an existing item.
  923.     ''' </summary>
  924.     <Runtime.InteropServices.
  925.     StructLayout(Runtime.InteropServices.LayoutKind.Sequential,
  926.     CharSet:=Runtime.InteropServices.CharSet.Auto)>
  927.     Public Structure MenuItemInfo
  928.  
  929.         ''' <summary>
  930.         ''' The size of the structure, in bytes.
  931.         ''' The caller must set this member to sizeof(MenuItemInfo).
  932.         ''' </summary>
  933.         Public cbSize As Integer
  934.  
  935.         ''' <summary>
  936.         ''' Indicates the members to be retrieved or set.
  937.         ''' This member can be one or more of the "ItemMask" Enum values.
  938.         ''' </summary>
  939.         Public fMask As Integer
  940.  
  941.         ''' <summary>
  942.         ''' The menu item type.
  943.         ''' This member can be one or more of the "ItemType" Enum values.
  944.         ''' The "ItemType.BITMAP", "ItemType.SEPARATOR", and "ItemType.MFT_STRING" values cannot be combined with one another.
  945.         ''' Set "fMask" member to "ItemMask.TYPE" to use "fType" member.
  946.         ''' "fType" is used only if "fMask" has a value of "ItemMask.TYPE".
  947.         ''' </summary>
  948.         Public fType As Integer
  949.  
  950.         ''' <summary>
  951.         ''' The menu item state.
  952.         ''' This member can be one or more of the "ItemState" Enum values.
  953.         ''' Set fMask to "ItemMask.STATE" to use "fState".
  954.         ''' </summary>
  955.         Public fState As Integer
  956.  
  957.         ''' <summary>
  958.         ''' An application-defined value that identifies the menu item.
  959.         ''' Set "fMask" to "ItemMask.ID" to use "wID".
  960.         ''' </summary>
  961.         Public wID As Integer
  962.  
  963.         ''' <summary>
  964.         ''' A handle to the drop-down menu or submenu associated with the menu item.
  965.         ''' If the menu item is not an item that opens a drop-down menu or submenu, this member is NULL.
  966.         ''' Set "fMask" to "ItemMask.SUBMENU" to use "hSubMenu".
  967.         ''' </summary>
  968.         Public hSubMenu As IntPtr
  969.  
  970.         ''' <summary>
  971.         ''' A handle to the bitmap to display next to the item if it is selected.
  972.         ''' If this member is NULL, a default bitmap is used.
  973.         ''' If the "ItemType.RADIOCHECK" type value is specified, the default bitmap is a bullet,
  974.         ''' Otherwise it is a check mark.
  975.         ''' Set "fMask" to "ItemMask.CHECKMARKS" to use "hbmpChecked".
  976.         ''' </summary>
  977.         Public hbmpChecked As IntPtr
  978.  
  979.         ''' <summary>
  980.         ''' A handle to the bitmap to display next to the item if it is not selected.
  981.         ''' If this member is NULL, no bitmap is used.
  982.         ''' Set "fMask" to "ItemMask.CHECKMARKS" to use "hbmpUnchecked".
  983.         ''' </summary>
  984.         Public hbmpUnchecked As IntPtr
  985.  
  986.         ''' <summary>
  987.         ''' An application-defined value associated with the menu item.
  988.         ''' Set "fMask" to "ItemMask.DATA" to use "dwItemData".
  989.         ''' </summary>
  990.         Public dwItemData As IntPtr
  991.  
  992.         ''' <summary>
  993.         ''' The contents of the menu item.
  994.         ''' The meaning of this member depends on the value of fType,
  995.         ''' and is used only if the "ItemMask.TYPE" flag is set in the "fMask" member.
  996.         ''' </summary>
  997.         Public dwTypeData As String
  998.  
  999.         ''' <summary>
  1000.         ''' The length of the menu item text, in characters,
  1001.         ''' when information is received about a menu item of the "ItemType.TEXT" type.
  1002.         ''' However, "cch" is used only if the "ItemMask.TYPE" flag is set in the "fMask" member and is zero otherwise.
  1003.         ''' Also, "cch" is ignored when the content of a menu item is set by calling "SetMenuItemInfo" API function.
  1004.         ''' The "cch" member is used when the "ItemMask.TEXT" flag is set in the "fMask" member.
  1005.         ''' </summary>
  1006.         Public cch As Integer
  1007.  
  1008.         ''' <summary>
  1009.         ''' A handle to the bitmap to be displayed.
  1010.         ''' It is used when the "ItemMask.BITMAP" flag is set in the "fMask" member.
  1011.         ''' </summary>
  1012.         Public hbmpItem As IntPtr
  1013.  
  1014.     End Structure
  1015.  
  1016. #End Region ' Structures
  1017.  
  1018. #Region " Constructor "
  1019.  
  1020.     ''' <summary>
  1021.     ''' Creates a new SystemMenuManager object for the specified form
  1022.     ''' </summary>
  1023.     ''' <param name="form">
  1024.     ''' The form for which to manage the system menu.
  1025.     ''' </param>
  1026.     Public Sub New(ByVal form As Form)
  1027.  
  1028.         ' Set the Formulary.
  1029.         Me.form = form
  1030.  
  1031.         ' Set the handle of the form's system menu.
  1032.         MenuHandle = GetSystemMenu(form.Handle, False)
  1033.  
  1034.         ' Assign the form handle.
  1035.         SetFormHandle()
  1036.  
  1037.     End Sub
  1038.  
  1039. #End Region ' New Constructor
  1040.  
  1041. #Region " Public Methods "
  1042.  
  1043.     ''' <summary>
  1044.     ''' Set an state for a menu item.
  1045.     ''' </summary>
  1046.     ''' <param name="item">
  1047.     ''' The system menu item.
  1048.     ''' </param>
  1049.     ''' <param name="state">
  1050.     ''' The new state for the item.
  1051.     ''' </param>
  1052.     Public Function SetItemState(ByVal item As Item,
  1053.                                  ByVal state As ItemState) As Boolean
  1054.  
  1055.         DisposedCheck()
  1056.  
  1057.         ItemStates(item) = state
  1058.  
  1059.         If item = item.Close Then
  1060.             CloseItem_State = state
  1061.         End If
  1062.  
  1063.         If state = ItemState.Removed Then
  1064.             Return DeleteMenu(MenuHandle, item, ItemPosition.ByCommand Or 0)
  1065.         Else
  1066.             Return EnableMenuItem(MenuHandle, item, ItemPosition.ByCommand Or state)
  1067.         End If
  1068.  
  1069.     End Function
  1070.  
  1071.     ''' <summary>
  1072.     ''' Set an state for a menu item at given position.
  1073.     ''' </summary>
  1074.     ''' <param name="position">
  1075.     ''' The menu item position.
  1076.     ''' </param>
  1077.     ''' <param name="state">
  1078.     ''' The new state for the item.
  1079.     ''' </param>
  1080.     Public Function SetItemState(ByVal position As Integer,
  1081.                                  ByVal state As ItemState) As Boolean
  1082.  
  1083.         DisposedCheck()
  1084.  
  1085.         Try
  1086.             PositionItemStates.Add(position, state)
  1087.         Catch ' ex As ArgumentException
  1088.             PositionItemStates(position) = state
  1089.         End Try
  1090.  
  1091.         If state = ItemState.Removed Then
  1092.             Return DeleteMenu(MenuHandle, position, ItemPosition.ByPosition Or 0)
  1093.         Else
  1094.             Return EnableMenuItem(MenuHandle, position, ItemPosition.ByPosition Or state)
  1095.         End If
  1096.  
  1097.     End Function
  1098.  
  1099.     ''' <summary>
  1100.     ''' Set a custom Bitmap image for a MenuItem.
  1101.     ''' </summary>
  1102.     ''' <param name="item">
  1103.     ''' The menu item.
  1104.     ''' </param>
  1105.     Public Function SetItemBitmap(ByVal item As Item,
  1106.                                   ByVal bmp As Bitmap) As Boolean
  1107.  
  1108.         DisposedCheck()
  1109.  
  1110.         ItemBitmaps(item) = bmp
  1111.  
  1112.         Return SetMenuItemBitmaps(MenuHandle,
  1113.                                   item,
  1114.                                   ItemPosition.ByCommand,
  1115.                                   bmp.GetHbitmap,
  1116.                                   bmp.GetHbitmap)
  1117.  
  1118.     End Function
  1119.  
  1120.     ''' <summary>
  1121.     ''' Set a custom Bitmap image for a MenuItem at given position.
  1122.     ''' </summary>
  1123.     ''' <param name="position">
  1124.     ''' The menu item position.
  1125.     ''' </param>
  1126.     Public Function SetItemBitmap(ByVal position As Integer,
  1127.                                   ByVal bmp As Bitmap) As Boolean
  1128.  
  1129.         DisposedCheck()
  1130.  
  1131.         Try
  1132.             PositionItemBitmaps.Add(position, bmp)
  1133.         Catch ' ex As System.ArgumentException
  1134.             PositionItemBitmaps(position) = bmp
  1135.         End Try
  1136.  
  1137.         Return SetMenuItemBitmaps(MenuHandle,
  1138.                                   position,
  1139.                                   ItemPosition.ByPosition,
  1140.                                   bmp.GetHbitmap,
  1141.                                   bmp.GetHbitmap)
  1142.  
  1143.     End Function
  1144.  
  1145.     ''' <summary>
  1146.     ''' Returns the custom Bitmap image used by a MenuItem.
  1147.     ''' </summary>
  1148.     ''' <param name="item">
  1149.     ''' The menu item.
  1150.     ''' </param>
  1151.     Public Function GetItemBitmap(ByVal item As Item) As Bitmap
  1152.  
  1153.         DisposedCheck()
  1154.  
  1155.         Return ItemBitmaps(item)
  1156.  
  1157.     End Function
  1158.  
  1159.     ''' <summary>
  1160.     ''' Returns the custom Bitmap image used by a MenuItem at given position.
  1161.     ''' </summary>
  1162.     ''' <param name="position">
  1163.     ''' The menu item position.
  1164.     ''' </param>
  1165.     Public Function GetItemBitmap(ByVal position As Integer) As Bitmap
  1166.  
  1167.         DisposedCheck()
  1168.  
  1169.         Return If(Not PositionItemBitmaps.FirstOrDefault(Function(item) item.Key = position).Key = Nothing,
  1170.                   PositionItemBitmaps(position),
  1171.                   Nothing)
  1172.  
  1173.     End Function
  1174.  
  1175.     ''' <summary>
  1176.     ''' Removes the custom Bitmap image used by a MenuItem.
  1177.     ''' </summary>
  1178.     ''' <param name="item">
  1179.     ''' The menu item.
  1180.     ''' </param>
  1181.     Public Function RemoveItemBitmap(ByVal item As Item) As Boolean
  1182.  
  1183.         DisposedCheck()
  1184.  
  1185.         ItemBitmaps(item) = Nothing
  1186.  
  1187.         Return SetMenuItemBitmaps(MenuHandle,
  1188.                                   item,
  1189.                                   ItemPosition.ByCommand,
  1190.                                   Nothing,
  1191.                                   Nothing)
  1192.  
  1193.     End Function
  1194.  
  1195.     ''' <summary>
  1196.     ''' Removes the custom Bitmap image used by a MenuItem at given position.
  1197.     ''' </summary>
  1198.     ''' <param name="position">
  1199.     ''' The menu item position.
  1200.     ''' </param>
  1201.     Public Function RemoveItemBitmap(ByVal position As Integer) As Boolean
  1202.  
  1203.         DisposedCheck()
  1204.  
  1205.         If Not PositionItemBitmaps.FirstOrDefault(Function(item) item.Key = position).Key = Nothing Then
  1206.             PositionItemBitmaps(position) = Nothing
  1207.         End If
  1208.  
  1209.         Return SetMenuItemBitmaps(MenuHandle,
  1210.                                   position,
  1211.                                   ItemPosition.ByPosition,
  1212.                                   Nothing,
  1213.                                   Nothing)
  1214.  
  1215.     End Function
  1216.  
  1217.     ''' <summary>
  1218.     ''' Gets the amount of menu items.
  1219.     ''' </summary>
  1220.     Public Function GetItemCount() As Integer
  1221.  
  1222.         DisposedCheck()
  1223.  
  1224.         Return GetMenuItemCount(MenuHandle) ' - 1
  1225.  
  1226.     End Function
  1227.  
  1228.     ''' <summary>
  1229.     ''' Enables all the menu items.
  1230.     ''' </summary>
  1231.     Public Sub EnableAllItems()
  1232.  
  1233.         DisposedCheck()
  1234.  
  1235.         For i As Integer = 0 To GetItemCount() - 1
  1236.             SetItemState(i, ItemState.Enabled)
  1237.         Next i
  1238.  
  1239.     End Sub
  1240.  
  1241.     ''' <summary>
  1242.     ''' Disables all the menu items.
  1243.     ''' </summary>
  1244.     Public Sub DisableAllItems()
  1245.  
  1246.         DisposedCheck()
  1247.  
  1248.         For i As Integer = 0 To GetItemCount() - 1
  1249.             SetItemState(i, ItemState.Disabled)
  1250.         Next i
  1251.  
  1252.     End Sub
  1253.  
  1254.     ''' <summary>
  1255.     ''' Removes all the menu items.
  1256.     ''' </summary>
  1257.     Public Sub RemoveAllItems()
  1258.  
  1259.         DisposedCheck()
  1260.  
  1261.         Do Until Not CBool(GetItemCount())
  1262.             DeleteMenu(MenuHandle, 0, ItemPosition.ByPosition Or 0)
  1263.         Loop
  1264.  
  1265.     End Sub
  1266.  
  1267.     ''' <summary>
  1268.     ''' Restores the menu to defaults.
  1269.     ''' </summary>
  1270.     Public Sub Restore_Menu()
  1271.  
  1272.         DisposedCheck()
  1273.  
  1274.         CloseItem_State = ItemState.Enabled
  1275.         Me.MenuHandle = GetSystemMenu(Me.form.Handle, True)
  1276.  
  1277.     End Sub
  1278.  
  1279.     ''' <summary>
  1280.     ''' Add a separator at default position.
  1281.     ''' </summary>
  1282.     ''' <param name="position">
  1283.     ''' The position where the item will be added.
  1284.     ''' </param>
  1285.     ''' <returns>
  1286.     ''' True if the operation was successful, otherwise False.
  1287.     ''' </returns>
  1288.     Public Function AddSeparator(ByVal position As DefaultPositions) As Boolean
  1289.  
  1290.         DisposedCheck()
  1291.  
  1292.         mii = New MenuItemInfo
  1293.  
  1294.         With mii
  1295.             .cbSize = Runtime.InteropServices.Marshal.SizeOf(GetType(MenuItemInfo))
  1296.             .fMask = ItemMask.ID Or ItemMask.TYPE
  1297.             .fType = ItemType.SEPARATOR
  1298.             .wID = -1
  1299.         End With
  1300.  
  1301.         Return InsertMenuItem(MenuHandle, GetPosition(position), True, mii)
  1302.  
  1303.     End Function
  1304.  
  1305.     ''' <summary>
  1306.     ''' Add a separator at given position.
  1307.     ''' </summary>
  1308.     ''' <param name="position">
  1309.     ''' The position where the item will be added.
  1310.     ''' </param>
  1311.     ''' <returns>
  1312.     ''' True if the operation was successful, otherwise False.
  1313.     ''' </returns>
  1314.     Public Function AddSeparator(ByVal position As Integer) As Boolean
  1315.  
  1316.         DisposedCheck()
  1317.  
  1318.         mii = New MenuItemInfo
  1319.  
  1320.         With mii
  1321.             .cbSize = Runtime.InteropServices.Marshal.SizeOf(GetType(MenuItemInfo))
  1322.             .fMask = ItemMask.ID Or ItemMask.TYPE
  1323.             .fType = ItemType.SEPARATOR
  1324.             .wID = -1
  1325.         End With
  1326.  
  1327.         Return InsertMenuItem(MenuHandle, position, True, mii)
  1328.  
  1329.     End Function
  1330.  
  1331.     ''' <summary>
  1332.     ''' Add an Item at default position.
  1333.     ''' </summary>
  1334.     ''' <param name="Label">
  1335.     ''' The text of the item.
  1336.     ''' </param>
  1337.     ''' <param name="ID">
  1338.     ''' A Identifier to interact with this item when is clicked.
  1339.     ''' </param>
  1340.     ''' <param name="position">
  1341.     ''' The position where the item will be added.
  1342.     ''' </param>
  1343.     ''' <param name="ImageChecked">
  1344.     ''' Image displayed when Item is selected.
  1345.     ''' </param>
  1346.     ''' <param name="ImageUnchecked">
  1347.     ''' Image displayed when Item is not selected.
  1348.     ''' </param>
  1349.     ''' <returns>
  1350.     ''' True if the operation was successful, otherwise False.
  1351.     ''' </returns>
  1352.     Public Function AddItem(ByVal Label As String,
  1353.                        ByVal ID As Integer,
  1354.                        ByVal Position As DefaultPositions,
  1355.                        Optional ByVal ImageChecked As Bitmap = Nothing,
  1356.                        Optional ByVal ImageUnchecked As Bitmap = Nothing) As Boolean
  1357.  
  1358.         DisposedCheck()
  1359.  
  1360.         mii = New MenuItemInfo
  1361.  
  1362.         With mii
  1363.             .cbSize = Runtime.InteropServices.Marshal.SizeOf(GetType(MenuItemInfo))
  1364.             .fMask = ItemMask.STATE Or ItemMask.ID Or ItemMask.TYPE Or ItemMask.CHECKMARKS
  1365.             .fType = ItemType.TEXT
  1366.             .fState = ItemState.Enabled
  1367.             .wID = ID
  1368.             .dwTypeData = Label
  1369.             .hbmpChecked = If(ImageChecked IsNot Nothing, ImageChecked.GetHbitmap, Nothing)
  1370.             .hbmpUnchecked = If(ImageUnchecked IsNot Nothing, ImageUnchecked.GetHbitmap, Nothing)
  1371.             .cch = .dwTypeData.Length
  1372.         End With
  1373.  
  1374.         Return InsertMenuItem(MenuHandle, GetPosition(Position), True, mii)
  1375.  
  1376.     End Function
  1377.  
  1378.     ''' <summary>
  1379.     ''' Adds an Item at the given position.
  1380.     ''' </summary>
  1381.     ''' <param name="Label">
  1382.     ''' The text of the item.
  1383.     ''' </param>
  1384.     ''' <param name="ID">
  1385.     ''' A Identifier to interact with this item when is clicked.
  1386.     ''' </param>
  1387.     ''' <param name="position">
  1388.     ''' The position where the item will be added.
  1389.     ''' </param>
  1390.     ''' <param name="ImageChecked">
  1391.     ''' Image displayed when Item is selected.
  1392.     ''' </param>
  1393.     ''' <param name="ImageUnchecked">
  1394.     ''' Image displayed when Item is not selected.
  1395.     ''' </param>
  1396.     ''' <returns>
  1397.     ''' True if the operation was successful, otherwise False.
  1398.     ''' </returns>
  1399.     Public Function AddItem(ByVal Label As String,
  1400.                        ByVal ID As Integer,
  1401.                        ByVal Position As Integer,
  1402.                        Optional ByVal ImageChecked As Bitmap = Nothing,
  1403.                        Optional ByVal ImageUnchecked As Bitmap = Nothing) As Boolean
  1404.  
  1405.         DisposedCheck()
  1406.  
  1407.         mii = New MenuItemInfo
  1408.  
  1409.         With mii
  1410.             .cbSize = Runtime.InteropServices.Marshal.SizeOf(GetType(MenuItemInfo))
  1411.             .fMask = ItemMask.STATE Or ItemMask.ID Or ItemMask.TYPE Or ItemMask.CHECKMARKS
  1412.             .fType = ItemType.TEXT
  1413.             .fState = ItemState.Enabled
  1414.             .wID = ID
  1415.             .dwTypeData = Label
  1416.             .hbmpChecked = If(ImageChecked IsNot Nothing, ImageChecked.GetHbitmap, Nothing)
  1417.             .hbmpUnchecked = If(ImageUnchecked IsNot Nothing, ImageUnchecked.GetHbitmap, Nothing)
  1418.             .cch = .dwTypeData.Length
  1419.         End With
  1420.  
  1421.         Return InsertMenuItem(MenuHandle, Position, True, mii)
  1422.  
  1423.     End Function
  1424.  
  1425.     ''' <summary>
  1426.     ''' Determines whether a handle is a menu handle.
  1427.     ''' </summary>
  1428.     ''' <returns>
  1429.     ''' True if is a menu handle, otherwise False.
  1430.     ''' </returns>
  1431.     Public Function IsMenuHandle(ByVal Handle As IntPtr) As Boolean
  1432.  
  1433.         DisposedCheck()
  1434.  
  1435.         Return IsMenu(Handle)
  1436.  
  1437.     End Function
  1438.  
  1439.     ''' <summary>
  1440.     ''' Gets the ID of a menu item.
  1441.     ''' </summary>
  1442.     Public Function GetItemID(ByVal Item As Item) As Integer
  1443.  
  1444.         DisposedCheck()
  1445.  
  1446.         Return Item
  1447.  
  1448.     End Function
  1449.  
  1450.     ''' <summary>
  1451.     ''' Gets the ID of a menu item at given position.
  1452.     ''' </summary>
  1453.     Public Function GetItemID(ByVal position As Integer) As Integer
  1454.  
  1455.         DisposedCheck()
  1456.  
  1457.         Return GetMenuItemID(MenuHandle, position)
  1458.     End Function
  1459.  
  1460.     ''' <summary>
  1461.     ''' Gets the text of a menu item.
  1462.     ''' </summary>
  1463.     Public Function GetItemText(ByVal Item As Item) As String
  1464.  
  1465.         DisposedCheck()
  1466.  
  1467.         ItemText.Clear()
  1468.         GetMenuString(MenuHandle, Item, ItemText, ItemText.Capacity, ItemPosition.ByCommand)
  1469.         Return ItemText.ToString
  1470.  
  1471.     End Function
  1472.  
  1473.     ''' <summary>
  1474.     ''' Gets the text of a menu item at given position.
  1475.     ''' </summary>
  1476.     Public Function GetItemText(ByVal position As Integer) As String
  1477.  
  1478.         DisposedCheck()
  1479.  
  1480.         ItemText.Clear()
  1481.         GetMenuString(MenuHandle, position, ItemText, ItemText.Capacity, ItemPosition.ByPosition)
  1482.         Return ItemText.ToString
  1483.  
  1484.     End Function
  1485.  
  1486.     ''' <summary>
  1487.     ''' Gets the state of a menu item.
  1488.     ''' </summary>
  1489.     Public Function GetItemState(ByVal Item As Item) As ItemState
  1490.  
  1491.         DisposedCheck()
  1492.  
  1493.         Return [Enum].Parse(GetType(ItemState), GetMenuState(MenuHandle, Item, ItemPosition.ByCommand))
  1494.  
  1495.     End Function
  1496.  
  1497.     ''' <summary>
  1498.     ''' Gets the state of a menu item at given position.
  1499.     ''' </summary>
  1500.     Public Function GetItemState(ByVal position As Integer) As ItemState
  1501.  
  1502.         DisposedCheck()
  1503.  
  1504.         Return [Enum].Parse(GetType(ItemState), GetMenuState(MenuHandle, position, ItemPosition.ByPosition))
  1505.  
  1506.     End Function
  1507.  
  1508.     ''' <summary>
  1509.     ''' Set the background color of a menu.
  1510.     ''' </summary>
  1511.     ''' <returns>
  1512.     ''' True if the operation was successful, otherwise False.
  1513.     ''' </returns>
  1514.     Public Function SetMenuBackColor(ByVal color As Color) As Boolean
  1515.  
  1516.         DisposedCheck()
  1517.  
  1518.         MenuBrush = CreateSolidBrush(CUInt(ColorTranslator.ToWin32(color)))
  1519.  
  1520.         mi = New MenuInfo
  1521.  
  1522.         With mi
  1523.             .cbSize = Runtime.InteropServices.Marshal.SizeOf(GetType(MenuInfo))
  1524.             .fMask = MenuMask.BACKGROUND
  1525.             .hbrBack = MenuBrush
  1526.         End With
  1527.  
  1528.         Return SetMenuInfo(MenuHandle, mi)
  1529.  
  1530.     End Function
  1531.  
  1532.     ''' <summary>
  1533.     ''' Set the menu style.
  1534.     ''' </summary>
  1535.     ''' <returns>
  1536.     ''' True if the operation was successful, otherwise False.
  1537.     ''' </returns>
  1538.     Public Function SetMenuStyle(ByVal Style As MenuStyle) As Boolean
  1539.  
  1540.         DisposedCheck()
  1541.  
  1542.         mi = New MenuInfo
  1543.  
  1544.         With mi
  1545.             .cbSize = Runtime.InteropServices.Marshal.SizeOf(GetType(MenuInfo))
  1546.             .fMask = MenuMask.STYLE
  1547.             .dwStyle = Style
  1548.         End With
  1549.  
  1550.         Return SetMenuInfo(MenuHandle, mi)
  1551.  
  1552.     End Function
  1553.  
  1554.     ''' <summary>
  1555.     ''' Set the text of a menu item.
  1556.     ''' </summary>
  1557.     ''' <param name="item">
  1558.     ''' The menu item.
  1559.     ''' </param>
  1560.     ''' <param name="text">
  1561.     ''' The new text for the item.
  1562.     ''' </param>
  1563.     Public Function SetItemText(ByVal item As Item,
  1564.                                 ByVal text As String) As Boolean
  1565.  
  1566.         DisposedCheck()
  1567.  
  1568.         mii = New MenuItemInfo
  1569.  
  1570.         With mii
  1571.             .cbSize = Runtime.InteropServices.Marshal.SizeOf(GetType(MenuItemInfo))
  1572.             .fMask = ItemMask.TEXT
  1573.             .dwTypeData = text
  1574.         End With
  1575.  
  1576.         Return SetMenuItemInfo(MenuHandle, item, False, mii)
  1577.  
  1578.     End Function
  1579.  
  1580.     ''' <summary>
  1581.     ''' Set the text of a menu item at given position.
  1582.     ''' </summary>
  1583.     ''' <param name="position">
  1584.     ''' The menu item position.
  1585.     ''' </param>
  1586.     ''' <param name="text">
  1587.     ''' The new text for the item.
  1588.     ''' </param>
  1589.     Public Function SetItemText(ByVal position As Integer,
  1590.                                 ByVal text As String) As Boolean
  1591.  
  1592.         DisposedCheck()
  1593.  
  1594.         mii = New MenuItemInfo
  1595.  
  1596.         With mii
  1597.             .cbSize = Runtime.InteropServices.Marshal.SizeOf(GetType(MenuItemInfo))
  1598.             .fMask = ItemMask.TEXT
  1599.             .dwTypeData = text
  1600.         End With
  1601.  
  1602.         Return SetMenuItemInfo(MenuHandle, position, True, mii)
  1603.  
  1604.     End Function
  1605.  
  1606.     ''' <summary>
  1607.     ''' Disables the opening of the systemmenu.
  1608.     ''' </summary>
  1609.     Public Sub DisableMenu()
  1610.  
  1611.         DisposedCheck()
  1612.  
  1613.         Me.IsMenuEnabled = False
  1614.  
  1615.     End Sub
  1616.  
  1617.     ''' <summary>
  1618.     ''' Reenables the system menu.
  1619.     ''' </summary>
  1620.     Public Sub EnableMenu()
  1621.  
  1622.         DisposedCheck()
  1623.  
  1624.         Me.IsMenuEnabled = True
  1625.  
  1626.     End Sub
  1627.  
  1628. #End Region ' Public Methods
  1629.  
  1630. #Region " Private Methods "
  1631.  
  1632.     ''' <summary>
  1633.     ''' Converts a MenuItemPosition value to a menu item position.
  1634.     ''' </summary>
  1635.     ''' <param name="position">
  1636.     ''' The MenuItemPosition value.
  1637.     ''' </param>
  1638.     Private Function GetPosition(ByVal position As ItemPosition) As Integer
  1639.  
  1640.         Select Case position
  1641.  
  1642.             Case DefaultPositions.First
  1643.                 Return 0
  1644.  
  1645.             Case DefaultPositions.Second
  1646.                 Return 1
  1647.  
  1648.             Case DefaultPositions.Third
  1649.                 Return 2
  1650.  
  1651.             Case DefaultPositions.Middle
  1652.                 Return (GetItemCount() \ 2)
  1653.  
  1654.             Case DefaultPositions.Penultimate
  1655.                 Return (GetItemCount() - 1)
  1656.  
  1657.             Case DefaultPositions.Last
  1658.                 Return (GetItemCount() + 1)
  1659.  
  1660.             Case Else
  1661.                 Return Nothing
  1662.  
  1663.         End Select
  1664.  
  1665.     End Function
  1666.  
  1667.     ''' <summary>
  1668.     ''' Refreshes the state of the Close menu item.
  1669.     ''' </summary>
  1670.     ''' <remarks>
  1671.     ''' Action is only taken if the state is Disabled or Grayed.
  1672.     ''' </remarks>
  1673.     Private Sub Refresh_CloseItem()
  1674.  
  1675.         If CloseItem_State = ItemState.Disabled _
  1676.         OrElse CloseItem_State = ItemState.Grayed Then
  1677.  
  1678.             ' Set the Close menu item state.
  1679.             EnableMenuItem(MenuHandle, Item.Close, ItemPosition.ByCommand Or CloseItem_State)
  1680.  
  1681.         End If
  1682.  
  1683.     End Sub
  1684.  
  1685. #End Region ' Private Methods
  1686.  
  1687. #Region " Form Event Handlers "
  1688.  
  1689.     ''' <summary>
  1690.     ''' The Close menu item must have it's state refresehed,
  1691.     ''' if it is present and not enabled.
  1692.     ''' </summary>
  1693.     Private Sub Refresh() _
  1694.     Handles Form.Load, Form.Resize
  1695.  
  1696.         Refresh_CloseItem()
  1697.  
  1698.     End Sub
  1699.  
  1700.     ''' <summary>
  1701.     ''' Assign the handle of the target form to this NativeWindow,
  1702.     ''' necessary to override WndProc.
  1703.     ''' </summary>
  1704.     Private Sub SetFormHandle() _
  1705.     Handles Form.HandleCreated, Form.Load, Form.Shown
  1706.  
  1707.         Try
  1708.             If Not Me.Handle.Equals(Me.form.Handle) Then
  1709.                 Me.AssignHandle(Me.form.Handle)
  1710.             End If
  1711.         Catch ' ex As InvalidOperationException
  1712.         End Try
  1713.  
  1714.     End Sub
  1715.  
  1716.     ''' <summary>
  1717.     ''' Releases the Handle.
  1718.     ''' </summary>
  1719.     Private Sub OnHandleDestroyed() _
  1720.     Handles Form.HandleDestroyed
  1721.  
  1722.         Me.ReleaseHandle()
  1723.  
  1724.     End Sub
  1725.  
  1726. #End Region ' Form Event Handlers
  1727.  
  1728. #Region " Windows Messages "
  1729.  
  1730.     ''' <summary>
  1731.     ''' Intercepts Menu messages.
  1732.     ''' </summary>
  1733.     Protected Overrides Sub WndProc(ByRef m As Message)
  1734.  
  1735.         Select Case m.Msg
  1736.  
  1737.             Case &H116 ' WM_INITMENU
  1738.                 ' Message is sent when a menu is about to become active.
  1739.                 ' It occurs when the user clicks an item on the menu bar or presses a menu key.
  1740.                 ' This allows the application to modify the menu before it is displayed.
  1741.                 MenuHandle = GetSystemMenu(form.Handle, False)
  1742.  
  1743.             Case &H117 ' WM_INITMENUPOPUP
  1744.                 ' Message is sent when a drop-down menu or submenu is about to become active.
  1745.                 ' This allows an application to modify the menu before it is displayed,
  1746.                 ' without changing the entire menu.
  1747.  
  1748.                 ' Refresh the states of the Items by command.
  1749.                 If ItemStates.FirstOrDefault(Function(item) item.Key).Value <> Nothing Then
  1750.                     ItemStates.ToList().
  1751.                                ForEach(Function(item) SetItemState(item.Key, item.Value))
  1752.                 End If
  1753.  
  1754.                 ' Refresh the states of the Items by position.
  1755.                 If PositionItemStates.FirstOrDefault(Function(item) item.Key).Value <> Nothing Then
  1756.                     PositionItemStates.ToList().
  1757.                     ForEach(Function(item) SetItemState(CInt(item.Key), item.Value))
  1758.                 End If
  1759.  
  1760.             Case &HA4, &HA5 ' WM_NCRBUTTONDOWN, WM_NCRBUTTONUP
  1761.  
  1762.                 ' Disables right clicking on title bar
  1763.                 If Not Me.IsMenuEnabled Then
  1764.                     m.Result = IntPtr.Zero
  1765.                     Return
  1766.                 End If
  1767.  
  1768.             Case &H112 ' WM_SYSCOMMAND
  1769.                 ' Message is sent when the user chooses a command from the system menu,
  1770.                 ' or when the user chooses the "maximize", "minimize", "restore", or "close" buttons.
  1771.  
  1772.                 ' Disables left click on icon in title bar
  1773.                 If Not Me.IsMenuEnabled AndAlso m.WParam = &HF093 Then
  1774.                     m.Result = IntPtr.Zero
  1775.                     Return
  1776.                 End If
  1777.  
  1778.                 ' Begin step to retrieve the item Text
  1779.                 mii = New MenuItemInfo With {
  1780.                     .cbSize = Runtime.InteropServices.Marshal.SizeOf(GetType(MenuItemInfo)),
  1781.                     .fMask = ItemMask.TEXT
  1782.                 }
  1783.  
  1784.                 ' Retrieve the text length member.
  1785.                 GetMenuItemInfo(MenuHandle, m.WParam, False, mii)
  1786.  
  1787.                 ' Account for terminating NUL character and allocate String
  1788.                 mii.cch += 1
  1789.                 mii.dwTypeData = Space(mii.cch)
  1790.  
  1791.                 ' Retrieve the rest of the information.
  1792.                 mii.fMask = ItemMask.ID Or ItemMask.TEXT Or ItemMask.STATE Or ItemMask.FTYPE
  1793.                 GetMenuItemInfo(MenuHandle, m.WParam, False, mii)
  1794.  
  1795.                 ' Set the Event arguments
  1796.                 With ItemClickedArgs
  1797.                     .ID = mii.wID
  1798.                     .Text = mii.dwTypeData
  1799.                     .State = [Enum].Parse(GetType(ItemState), mii.fState)
  1800.                     .Type = [Enum].Parse(GetType(ItemType), mii.fType)
  1801.                 End With
  1802.  
  1803.                 RaiseEvent ItemClicked(MenuHandle, ItemClickedArgs)
  1804.  
  1805.         End Select
  1806.  
  1807.         ' Return control to base message handler.
  1808.         MyBase.WndProc(m)
  1809.  
  1810.     End Sub
  1811.  
  1812. #End Region ' Windows Messages
  1813.  
  1814. #Region " IDisposable "
  1815.  
  1816.     ''' <summary>
  1817.     ''' To detect redundant calls when disposing.
  1818.     ''' </summary>
  1819.     Private IsDisposed As Boolean = False
  1820.  
  1821.     ''' <summary>
  1822.     ''' Prevents calls to methods after disposing.
  1823.     ''' </summary>
  1824.     Private Sub DisposedCheck()
  1825.         If Me.IsDisposed Then
  1826.             Throw New ObjectDisposedException(Me.GetType().FullName)
  1827.         End If
  1828.     End Sub
  1829.  
  1830.     ''' <summary>
  1831.     ''' Disposes the objects generated by this instance.
  1832.     ''' </summary>
  1833.     Public Sub Dispose() Implements IDisposable.Dispose
  1834.         Dispose(True)
  1835.         GC.SuppressFinalize(Me)
  1836.     End Sub
  1837.  
  1838.     ' IDisposable
  1839.     Protected Overridable Sub Dispose(IsDisposing As Boolean)
  1840.  
  1841.         If Not Me.IsDisposed Then
  1842.  
  1843.             If IsDisposing Then
  1844.                 DeleteObject(MenuBrush)
  1845.                 EnableMenu()
  1846.                 Restore_Menu()
  1847.                 EndMenu()
  1848.                 Me.form = Nothing
  1849.                 MenuHandle = IntPtr.Zero
  1850.                 Me.ReleaseHandle()
  1851.                 Me.DestroyHandle()
  1852.             End If
  1853.  
  1854.         End If
  1855.  
  1856.         Me.IsDisposed = True
  1857.  
  1858.     End Sub
  1859.  
  1860. #End Region ' Dispose
  1861.  
  1862. #Region " ToDO?: "
  1863.  
  1864.     ' función "AppendMenu"?
  1865.     ' usar HotKeys? (&)
  1866.     ' Alguna cosa interesante con los submenus?
  1867.  
  1868. #End Region ' ToDo
  1869.  
  1870. End Class
  1871.  
  1872. #End Region
Advertisement
Add Comment
Please, Sign In to add comment