Receiving Messages


Visual Basic controls and forms constantly receive messages and translate them into events or attributes according to instructions in the messages. For example, let’s say that you used the Menu Editor to define a File menu named mnuFile with items mnuNew, mnuOpen, and so on. When the user of your application chooses Open, the mnuOpen_Click event occurs, and the code in the mnuOpen_Click event procedure executes.


But what really happens behind the scenes? Windows gets a signal from the mouse port that a click has occurred at a certain screen location (or possibly it discovers that the Alt, F, and O keys have been pressed consecutively). Windows checks its internal information to find out which window owns that location and discovers that the click occurred on the Open item of the File menu. It then sends a slew of messages related to this event, culminating in a WM_COMMAND message with the ID number of the Open item.


Meanwhile, the window procedure for the form containing the menu has a Select Case block similar to the one shown here:

Select Case iMessage
Case WM_COMMAND
Select Case wParam
Case IDM_NEW
mnuNew_Click
Case IDM_OPEN
mnuOpen_Click
§
End Select
§
End Select

This code intercepts the WM_COMMAND message, and the mnuOpen_Click event starts executing. In short, Windows sends messages; Visual Basic turns them into events.


Now consider the system menu. By default, Visual Basic puts the standard system menu on all forms whose ControlBox property is set to True. When a user chooses from a system menu, Windows sends the WM_SYSCOMMAND message to the window (form). The window procedure for a form works this way:

‘ Set default return value
WindowProc = 0&
‘ Handle messages
Select Case iMessage
Case WM_DOHOPEVENT
Form.HopEvent_Click
Case WM_GETJUMPDATA
Form.JumpData = wParam
Case Else
‘ Let default window procedure handle the rest
WindowProc = DefWindowProc(hWnd, iMessage, wParam, lParam)
End Select

Because the WM_SYSCOMMAND message isn’t handled by a specific Case statement, it falls through to the Case Else statement to be handled by DefWindow­Proc. The default window procedure knows how to do the standard operations—move, size, minimize, maximize, close, and switch to—which are the same for any window.


But what if you add an About item to the system menu? Visual Basic won’t help you do this, but neither will it stand in your way. It’s a simple matter to add an item to the system menu using Windows API calls:

Const IDM_ABOUT = 1010
Dim hSysMenu As Long
‘ Get handle of system menu
hSysMenu = GetSystemMenu(hWnd, 0&)
‘ Append separator and menu item with ID IDM_ABOUT
Call AppendMenu(hSysMenu, MF_SEPARATOR, 0&, 0&)
Call AppendMenu(hSysMenu, MF_STRING, IDM_ABOUT, “About...”)

When the user selects this new menu item, Windows sends a WM_SYS­COMMAND message with the IDM_ABOUT value to the window procedure. Having no clue what to do with this message, the window procedure passes it off to Def­WindowProc, which also hasn’t a clue. Your message rides off into the sunset.