Changing the System Menu

by Itay Sagui

Sometimes you may find yourself in need to change the system menu of a form. This menu, which is a built in part of the window class, cannot be accessed normally using pure VB. The only way to handle and modify this menu, is using th menu APIs. In this article I will cover the APIs needed to perform those changes.

Let's start with the most basic API that we'll use in this article - GetSystemMenu. Given a handle of form, this API will return the handle of the form's system menu:

Private Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, ByVal bRevert As Long) As Long

hSysMenu = GetSystemMenu(Me.hwnd, False)

The second parameter specify if you want to reset the window's system menu to its default.

Now that we've got the menu's handle, there are different that we can do. We'll start with retrieving the number of items in the menu:

Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long

nCnt = GetMenuItemCount(hSysMenu)

One thing that you should remember is that the menu items "array" is 0-based, which means that the first item is item number 0, and the last item is item (nCnt-1).

We can add items to the menu by calling the AppendMenu API:

Private Declare Function AppendMenu Lib "user32" Alias "AppendMenuA" (ByVal hMenu As Long,
ByVal wFlags As Long, ByVal wIDNewItem As Long, ByVal lpNewItem As Any) As Long

The first parameter, hMenu, is the handle to the menu that we append the new item to. wFlags is a combination of the following constants:

Private Const MF_CHECKED As Long = &H8&
Private Const MF_DISABLED As Long = &H2&
Private Const MF_GRAYED As Long = &H1&
Private Const MF_SEPARATOR As Long = &H800&
Private Const MF_STRING As Long = &H0&

The wIDNewItem parameter is the ID of the new item. Although menu items can be identified by their caption, it is always better to give the new item a custom ID, that will be used when the menu is handles. lpNewItem is the caption of the new item.

Okay. We've learned how to add items to the system menu. Now let's see how you remove them. The process of removing an item from a menu is quite simple - all you have to do is call the RemoveMenu API, with the handle of the menu, and either the ID of the item to be removed, or its location. Here's how it is done:

Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, 
ByVal wFlags As Long) As Long Private Const MF_BYPOSITION = &H400& Provate Const MF_REMOVE = &H1000& ' Removes the 'Move' item. RemoveMenu hSysMenu, 1, MF_BYPOSITION Or MF_REMOVE

If the wFlags contains the MF_BYPOSITION flag, the nPosition parameter is looked at as the position of the item in the menu. Otherwise, the function expect nPosition to be the ID of the item.

Now, we all like the small icons next to our menus. How about changing the system's icons?

Private Declare Function SetMenuItemBitmaps Lib "user32" (ByVal hMenu As Long, ByVal nPosition As
Long, ByVal wFlags As Long, ByVal hBitmapUnchecked As Long, ByVal hBitmapChecked As Long) As Long SetMenuItemBitmaps hMenu, 1, MF_BYPOSITION, Picture1.Picture, Picture2.Picture

As in previous APIs, the first parameters specify which item we want to change. The first picture is the icon to be shown when the menu item is unchecked, and the second picture is used when it is checked.

This will be all for this article, but I will leave you with these words: All that I've shown you here, can be also applied to normal menus. The way to get them is quite similar to the way we got the system menu:

Private Declare Function GetMenu Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetSubMenu Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long