Handlers for Message-Map Ranges

HomeOverviewHow Do ITutorial

This article explains how to map a range of messages to a single message handler function (instead of mapping one message to only one function).

There are times when you need to process more than one message or control notification in exactly the same way. At such times, you might wish to map all of the messages to a single handler function. Message-map ranges allow you to do this for a contiguous range of messages:

Topics covered in this article include:

Important   ClassWizard does not support message-map ranges, so you must write the message-map entries and handler function declarations yourself.

Writing the Message-Map Entry

In the .CPP file, add your message-map entry, as shown in the following example:

...
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
    //{{AFX_MSG_MAP(CMyApp)
    ...
    //}}AFX_MSG_MAP
ON_COMMAND_RANGE(ID_MYCMD_ONE, ID_MYCMD_TEN, OnDoSomething)
END_MESSAGE_MAP( )
...

The message-map entry consists of the following items:

Declaring the Handler Function

In the .H file, add your handler function declaration outside the //{{AFX_MSG comment brackets. The following code shows how this might look, as shown in the next-to-last line below:

// Generated message-map functions
protected:
    //{{AFX_MSG(CMyApp)   
        ...
    //}}AFX_MSG
    afx_msg void OnDoSomething( UINT nID );
    DECLARE_MESSAGE_MAP()

Handler functions for single commands normally take no parameters. With the exception of update handler functions, handler functions for message-map ranges require an extra parameter, nID, of type UINT. This parameter is the first parameter. The extra parameter accommodates the extra command ID needed to specify which command the user actually chose. 

See Example for a Range of Command IDs for more information about parameter requirements for updating handler functions.

Example for a Range of Command IDs

When might you use ranges? One example is in handling commands like the Zoom command in the MFC sample HIERSVR. This command zooms the view, scaling it between 25% and 300% of its normal size. HIERSVR’s view class uses a range to handle the Zoom commands with a message-map entry resembling this:

ON_COMMAND_RANGE(ID_VIEW_ZOOM25, ID_VIEW_ZOOM300, OnZoom)

When you write the message-map entry, you specify:

The function declaration would resemble this:

afx_msg void OnZoom(UINT nID);

The case of update handler functions is similar, and likely to be more widely useful. It’s quite common to write ON_UPDATE_COMMAND_UI handlers for a number of commands and find yourself writing, or copying, the same code over and over. The solution is to map a range of command IDs to one update handler function using the ON_UPDATE_COMMAND_UI_RANGE macro. The command IDs must form a contiguous range. For an example, see the OnUpdateZoom handler and its ON_UPDATE_COMMAND_UI_RANGE message-map entry in the HIERSVR sample’s view class.

Update handler functions for single commands normally take a single parameter, pCmdUI, of type CCmdUI*. Unlike handler functions, update handler functions for message-map ranges do not require an extra parameter, nID, of type UINT. The command ID, which is needed to specify which command the user actually chose, is found in the CCmdUI object.

Example for a Range of Control IDs

Another interesting case is mapping control-notification messages for a range of control IDs to a single handler. Suppose the user can click any of 10 buttons. To map all 10 buttons to one handler, your message-map entry would look like this:

ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON1, IDC_BUTTON10, OnButtonClicked)

When you write the ON_CONTROL_RANGE macro in your message map, you specify:

When you write the handler function, specify the extra UINT parameter, as shown in the following:

...
void CMyDialog::OnButtonClicked( UINT nID )
{
    int nButton = nID - IDC_BUTTON1;
    ASSERT( nButton >= 0 && nButton < 10 );
    // ...
}

The OnButtonClicked handler for a single BN_CLICKED message takes no parameters. The same handler for a range of buttons takes one UINT. The extra parameter allows for identifying the particular control responsible for generating the BN_CLICKED message.

The code shown in the example is typical: converting the value passed to an int within the message range and asserting that this is the case. Then you might take some different action depending on which button was clicked.