Windows based user interface applications are message driven. When a message is generated, its associated message handler will be executed.
MFC (Microsoft Foundation Classes) framework enables to write message driven applications more easily. MFC provides CCmdTraget class for this purpose.
In this article I am going to explain the steps to create user-defined messages and its handlers.
Step 1. First we need to define an user defined message. Remember that the defined message should be unique. For example WM_CLOSE is a pre-defined message and it has some value already defined. If we define our user-defined message with the value given for WM_CLOSE; MFC will route to pre-defined message handler instead of user defined message handler; in this case it results to execute pre-defined message handler which will close the application. Suppose this is not we have expected with our user defined message; we have to define our user defined message properly.
To over come this, Windows categorize the messages as pre-defined and user-defined messages. All user defined messages must be defined from WM_USER or WM_APP value. Suppose “WM_USER + 1” is one message, “WM_USER + 2” is another message etc.,.
You can use WM_USER to define user-defined messages to use within the private window class. Whereas WM_APP to define user-defined messages to use across the applications.
So the declaration looks like below:
#define WM_USER_MY_OWN_MESSAGE WM_USER + 1
Above statement will define WM_USER_MY_OWN_MESSAGE user-defined message.
Step 2. Now we have to provide a message handler to our message. The syntax of user defined message handler should be like below:
afx_msg LRESULT OnUserDefinedMessage(WPARAM wParam, LPARAM lParam);
Where wParam and lParam are additional information to pass to the handler.
This declaration should be in the our class; which is directly or indirectly derived from CCmdTarget class. If the class is not derived from CCmdTarget, message routing functionality will not work; so, user defined message handler never called.
Step 3. We have defined our user defined message and its handler. Now we need to map these. Below is the macro which will map message handler with the message ID.
ON_MESSAGE( <message id>, <message handler> )
Where <message id> is the ID of our user-defined message and <message handler> is the our message handler function.
Step 4. Place above macro in between message map macros BEGIN_MESSAGE_MAP and END_MESSAGE_MAP. This is an important step. This step enables to place our user defined message into message routing. So, MFC will call the appropriate message handler when the particular message is generated. The code will looks like below:
BEGIN_MESSAGE_MAP(CMyWndClass, CMyWndClassParentClass) ON_MESSAGE(WM_USER_MY_OWN_MESSAGE, OnUserDefinedMessage) END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP is used to begin the definition of the message map and END_MESSAGE_MAP is required to ends its definition. Through BEGIN_MESSAGE_MAP macro we should pass the class name as first parameter and its parent class as its second parameter. As discussed before, the parent class must be directly or indirectly derived from CCmdTarget class.
Step 5. Last step is to generate the message. MFC framework knows when to call pre-defined messages like WM_PAINT, WM_CLOSE etc.,. But user defined messages are not triggered by MFC framework. We have to explicitly trigger them using MFC functions SendMessage or PostMessage.
SendMessage is calls the message handler and then returns the control. Whereas PostMessage posts the message into Thread’s message queue and immediately returns the control. So, there will be a delay in execution of our message handler when we trigger the message using PostMessage.
In this example, I am using SendMessage function to trigger the message. Below is the statement to trigger the message:
If we need to call from outside from our window class; we need to pass our window handle as the first argument. So the call will be like below:
Where hWnd is the window handle of our window class.
Once the user defined message is generated, MFC will check the message map and execute the associated message handler.