Click here to Skip to main content
Click here to Skip to main content

Windows Message Handling - Part 2

, 7 Jun 2000
Rate this:
Please Sign up or sign in to vote.
Message Maps, User defined messages and Registered Messages
<!-- Add the rest of your HTML here -->

How do MFC message handlers work?

Whenever your window receives a message, MFC will call a member function of your class. But how does MFC know what function to call?

MFC uses a technique called Message Maps. A Message Map is a table that associates messages with functions. When you receive a message, MFC will go through your Message Map and search for a corresponding Message Handler. I have showed in Part 1 how you add a Message Handler to the Message Map by using ClassWizard, but what really happens code-wise?

MFC uses a large set of rather complicated macros that add the Message Map to your classes. When you use ClassWizard to create a Message Handler, it will first add the function to your class, and add the corresponding macro to your Message Map. For example, examine the following ClassWizard generated WM_CLOSE handler:

Message Map: located in the class implementation

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
	ON_WM_CLOSE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

Function Declaration: located in the class declaration.

protected:
	//{{AFX_MSG(CAboutDlg)
	afx_msg void OnClose();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()

Function Implementation: located in the class implementation

void CAboutDlg::OnClose() 
{
	// TODO: Add your message handler code here and/or call default
	
	CDialog::OnClose();
}

By adding a DECLARE_MESSAGE_MAP statement to the class declaration, MFC adds the required code to declare the message map. The BEGIN_MESSAGE_MAP tells MFC where the Message Map begins, and identifies your class and it's base class. The reason it needs the base class is because Message Handlers are passed through c++ inheritance, just like any other function. END_MESSAGE_MAP obviously, tells MFC where the Message Map ends. In between these two macros is where your declare the Message Map entry for your Message Handler. MFC has many predefined macros, which associate messages with your member function. Take the the ON_WM_CLOSE macro as an example: It associates the WM_CLOSE message with your OnClose() member function. The macro takes no parameters since it always expects a function called OnClose() which is prototyped as afx_msg void OnClose(). This method gives you 2 advantages:

  1. It is easy to keep track of Message Handlers and the messages they handle
  2. MFC screens out any irrelevant and will break up lParam and wParam to parameters relevant to the message.

Also the return value is simplified, and the Message Handler is prototyped according to the message. For example: If the value should always be zero, MFC simplifies the process and allows you to declare the function as a void, and MFC will be responsible for returning 0. To find the name of the message handler that correlates with a given Message Handler macro you should look it up in the MFC documentation.

There are some messages that ClassWizard doesn't support, but you can manualy add your message handler by adding the function and Message Map macro as described above. If you add message-map entries manually, you may not be able to edit them with ClassWizard later. If you add them outside the bracketing comments //{{AFX_MSG_MAP(classname) and //}}AFX_MSG_MAP, ClassWizard cannot edit them at all. Note that by the same token ClassWizard will not touch any entries you add outside the comments, so feel free to add messages outside the comments if you do not want them to be modified. Messages that are not recognized by ClassWizard, such as message-map ranges, must be added outside the comments.

The all mighty ON_MESSAGE

Sometimes you will find yourself trying to handle a message that ClassWizard doesn't support, and it doesn't have a Message Map macro. MFC has a generic macro just for this kind of situation ON_MESSAGE. ON_MESSAGE allows you to handle any message that exists. The prototype of Message Handlers that use ON_MESSAGE is

afx_msg LRESULT OnMessage(WPARAM wParam, LPARAM lParam);

where OnMessage is the name of your handler function. The ON_MESSAGE macro takes 2 parameters: The address of the handler, and the message it should handle. For example: The following statement Maps WM_GETTEXTLENGTH to OnGetTextLength():

ON_MESSAGE (WM_GETTEXTLENGTH, OnGetTextLength)
OnGetTextLength is prototyped as
afx_msg LRESULT OnGetTextLength(WPARAM wParam, LPARAM lParam);

User-defined messages

Sometimes, you will need to communicate between 2 windows in your application or between 2 windows from different applications. An easy way to do this is by using User-defined messages. The name "User-defined" can be confusing at first; you define a User-defined message and not the user of your program. I have stated in Part 1 that messages are identified by numbers, and that Windows predefines standard messages. The way of using predefined messages is to simply use a number. To make sure that you don't conflict with the system defined messages you should use a number in the range of WM_APP through 0xBFFF:

#define WM_DELETEALL WM_APP + 0x100
//...
pYourDialog->SendMessage(WM_DELETEALL, 0, 0);
Handling a user-defined message is done with the ON_MESSAGE macro:
#define WM_DELETEALL WM_APP + 0x100
//...
//Message Map entry:
ON_MESSAGE (WM_DELETEALL, OnDeleteAll)
//OnDeleteAll is prototyped as 
afx_msg LRESULT OnDeleteAll(WPARAM wParam, LPARAM lParam);
//And is implemented as 
LRESULT OnDeleteAll(WPARAM wParam, LPARAM lParam){
	//Do What ever you want
	return somevalue;
}

Registered Windows Messages

The RegisterWindowMessage function is used to define a new window message that is guaranteed to be unique throughout the system. The macro ON_REGISTERED_MESSAGE is used to handle these messages. This macro accepts a name of a UINT variable that contains the registered Windows message ID. For example:

class CMyWnd : public CMyParentWndClass
{
public:
    CMyWnd();

    //{{AFX_MSG(CMyWnd)
    afx_msg LRESULT OnFind(WPARAM wParam, LPARAM lParam);
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

static UINT WM_FIND = RegisterWindowMessage("YOURAPP_FIND_MSG");

BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
	//{{AFX_MSG_MAP(CMyWnd)
		ON_REGISTERED_MESSAGE(WM_FIND, OnFind)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

The range of user defined messages using this approach will be in the range 0xC000 to 0xFFFF. And you send it using the regular SendMessage() method:

static UINT WM_FIND = RegisterWindowMessage("YOURAPP_FIND_MSG");
//...
pFindWindow->SendMessage(WM_FIND, lParam, wParam);

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Daniel Kopitchinski
Web Developer
Israel Israel
No Biography provided

Comments and Discussions

 
Questiondifference between user-defined and registered window messages Pinmembersepinaz29-Aug-13 15:18 
QuestionHandle message of windows applications Pinmemberstaler.ideas14-Jul-11 22:11 
GeneralMy vote of 4 Pinmemberm_tv6-Mar-11 17:23 
Questionwho will create message loop and message queue? Pinmembervasu_sri17-Oct-10 21:36 
GeneralMy vote of 4 PinmemberLaxmikant_Yadav5-Aug-10 0:51 
General2 SyncInvoke calls from one method are serial. [modified] Pinmemberalex.buzunov29-Jan-10 11:00 
Questionwho sends the message? Pinmembertiankng22-Jul-09 22:40 
GeneralDSFDS Pinmembermahbubabbas28-May-08 22:15 
Generalmake example Pinmembersupfar31-Oct-07 22:42 
QuestionWhere can I get the Part 1 part of this series Windows Message Handling - Part 1 Pinmembertom groezer1-May-07 21:31 
AnswerRe: Where can I get the Part 1 part of this series Windows Message Handling - Part 1 Pinmemberilikeopensource24-May-07 4:44 
GeneralGood Article Pinmemberpandyajigarcodeproject5-Dec-06 22:28 
GeneralUser Defined Messages Pinmemberpandyajigarcodeproject5-Dec-06 0:31 
GeneralMouse Position on non-Client Area of MDIChild Window Pinmemberfayaz var9-Jan-06 0:21 
GeneralRegistered Message. PinmemberJewel Nandy1-Dec-05 3:03 
Generalmessage from worker thread to main window PinmemberNorman Hines29-Oct-04 12:22 
GeneralRe: message from worker thread to main window PinmemberCan Isin22-Dec-04 1:24 
GeneralRe: message from worker thread to main window PinmemberNorman Hines22-Dec-04 4:22 
QuestionRe: message from worker thread to main window Pinmembertom groezer1-May-07 23:23 
Generalmessage in console app .... Pinmemberdharani3-Sep-04 2:28 
Generaluser defined messages : convert-problem PinmemberApplicator19-Jul-04 1:18 
QuestionCan we handle the messages of other applications? Pinmembershashike30-Dec-03 16:17 
GeneralIntercept message at control level PinmemberDavide Zaccanti21-Aug-03 22:27 
GeneralA Powerful tool made easy PinmemberAjay Sancheti1-Aug-03 3:23 
GeneralMessages vs. Commands PinmemberSysPro7-Jul-03 7:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140709.1 | Last Updated 8 Jun 2000
Article Copyright 2000 by Daniel Kopitchinski
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid