An application is made of various objects. Most of the time, more than one application is running on the computer and the operating system is constantly asked to perform some assignments. Because there can be so many requests presented unpredictably, the operating system leaves it up to the objects to specify what they want, when they want it, and what behavior or result they expect.
The Microsoft Windows operating system cannot predict what kinds of requests one object would need to be taken care of and what type of assignment another object would need.
To manage all these assignments and requests, the objects send messages.
Each object has the responsibility to decided what message to send and when.
In order to send a message, a control must create an event.
To make a distinction between the two, a message's name usually starts with WM_ which stands for Window Message.
The name of an event usually starts with On which indicates an action.
The event is the action of sending the message.
Since Windows is a message-oriented operating system, a large portion of programming for the Windows environment involves message handling. Each time an event such as a keystroke or mouse click occurs, a message is sent to the application, which must then handle the event.
For the compiler to manage messages, they should be included in the class definition.
The DECLARE_MESSAGE_MAP macro should be provided at the end of the class definition as shown in the following code.
class CMainFrame : public CFrameWnd { public: CMainFrame(); protected: DECLARE_MESSAGE_MAP() };
The actual messages should be listed just above the DECLARE_MESSAGE_MAP line.
To implement the messages, you need to create a table of messages that your program is using.
This table uses two delimiting macros;
Its starts with a BEGIN_MESSAGE_MAP and ends with an END_MESSAGE_MAP macros.
The BEGIN_MESSAGE_MAP macro takes two arguments, the name of your class and the MFC class you derived your class from as shown in the following code.
#include <afxwin.h> class CMainFrame : public CFrameWnd { public: CMainFrame(); protected: DECLARE_MESSAGE_MAP() }; CMainFrame::CMainFrame() { // Create the window's frame Create(NULL, L"MFC Messages Demo", WS_OVERLAPPEDWINDOW, CRect(120, 100, 700, 480), NULL); } class CMessagesApp : public CWinApp { public: BOOL InitInstance(); }; BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) END_MESSAGE_MAP() BOOL CMessagesApp::InitInstance(){ m_pMainWnd = new CMainFrame; m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow(); return TRUE; } CMessagesApp theApp;
Let us look into a simple example by creating a new Win32 project.
Step 1 − To create an MFC project, right-click on the project and select Properties.
Step 2 − In the left section, click Configuration Properties → General.
Step 3 − Select the ‘Use MFC in Shared DLL’ option in Project Defaults section and click OK.
Step 4 − We need to add a new source file.
Step 5 − Right-click on your Project and select Add → New Item.
Step 6 − In the Templates section, click C++ File (.cpp).
Step 7 − Click Add to Continue.
Step 8 − Now, add the following code in the *.cpp file.
#include <afxwin.h> class CMainFrame : public CFrameWnd { public: CMainFrame(); protected: DECLARE_MESSAGE_MAP() }; CMainFrame::CMainFrame() { // Create the window's frame Create(NULL, L"MFC Messages Demo", WS_OVERLAPPEDWINDOW, CRect(120, 100, 700, 480), NULL); } class CMessagesApp : public CWinApp { public: BOOL InitInstance(); }; BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) END_MESSAGE_MAP() BOOL CMessagesApp::InitInstance() { m_pMainWnd = new CMainFrame; m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow(); return TRUE; } CMessagesApp theApp;
There are different types of Windows messages like creating a window, showing a window etc. Here are some of the commonly used windows messages.
Let us look into a simple example of window creation.
WM_CREATE − When an object, called a window, is created, the frame that creates the objects sends a message identified as ON_WM_CREATE.
Step 1 − To create ON_WM_CREATE, add afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); before the DECLARE_MESSAGE_MAP() as shown below.
class CMainFrame : public CFrameWnd { public: CMainFrame(); protected: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); DECLARE_MESSAGE_MAP() };
Step 2 − Add the ON_WM_CREATE() after the BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) and before END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP()
Step 3 − Here is the Implementation of OnCreate()
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { // Call the base class to create the window if (CFrameWnd::OnCreate(lpCreateStruct) == 0) { // If the window was successfully created, let the user know MessageBox(L"The window has been created!!!"); // Since the window was successfully created, return 0 return 0; } // Otherwise, return -1 return -1; }
Step 4 − Now your *.cpp file will look like as shown in the following code.
#include <afxwin.h> class CMainFrame : public CFrameWnd { public: CMainFrame(); protected: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); DECLARE_MESSAGE_MAP() }; CMainFrame::CMainFrame() { // Create the window's frame Create(NULL, L"MFC Messages Demo", WS_OVERLAPPEDWINDOW, CRect(120, 100, 700, 480), NULL); } class CMessagesApp : public CWinApp { public: BOOL InitInstance(); }; BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP() int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { // Call the base class to create the window if (CFrameWnd::OnCreate(lpCreateStruct) == 0) { // If the window was successfully created, let the user know MessageBox(L"The window has been created!!!"); // Since the window was successfully created, return 0 return 0; } // Otherwise, return -1 return -1; } BOOL CMessagesApp::InitInstance() { m_pMainWnd = new CMainFrame; m_pMainWnd -> ShowWindow(SW_SHOW); m_pMainWnd -> UpdateWindow(); return TRUE; } CMessagesApp theApp;
Step 5 − When the above code is compiled and executed, you will see the following output.
Step 6 − When you click OK, it will display the main window.
One of the main features of a graphical application is to present Windows controls and resources that allow the user to interact with the machine. Examples of controls that we will learn are buttons, list boxes, combo boxes, etc.
One type of resource we introduced in the previous lesson is the menu. Such controls and resources can initiate their own messages when the user clicks them. A message that emanates from a Windows control or a resource is called a command message.
Let us look into a simple example of Command messages.
To provide your application the ability to create a new document, the CWinApp class provides the OnFileNew() method.
afx_msg void OnFileNew(); BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_COMMAND(ID_FILE_NEW, CMainFrame::OnFileNew) END_MESSAGE_MAP()
Here is the method definition −
void CMainFrame::OnFileNew() { // Create New file }
A keyboard is a hardware object attached to the computer. By default, it is used to enter recognizable symbols, letters, and other characters on a control. Each key on the keyboard displays a symbol, a letter, or a combination of those, to give an indication of what the key could be used for. The user typically presses a key, which sends a signal to a program.
Each key has a code that the operating system can recognize. This code is known as the virtual key code.
Pressing a key causes a WM_KEYDOWN or WM_SYSKEYDOWN message to be placed in the thread message. This can be defined as follows −
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
Let us look into a simple example.
Step 1 − Here is the message.
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_CREATE() ON_WM_KEYDOWN() END_MESSAGE_MAP()
Step 2 − Here is the implementation of OnKeyDown().
void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { switch (nChar) { case VK_RETURN: MessageBox(L"You pressed Enter"); break; case VK_F1: MessageBox(L"Help is not available at the moment"); break; case VK_DELETE: MessageBox(L"Can't Delete This"); break; default: MessageBox(L"Whatever"); } }
Step 3 − When the above code is compiled and executed, you will see the following output.
Step 4 − When you press Enter, it will display the following message.
The mouse is another object that is attached to the computer allowing the user to interact with the machine.
If the left mouse button was pressed, an ON_WM_LBUTTONDOWN message is sent. The syntax of this message is −
afx_msg void OnLButtonDown(UINT nFlags, CPoint point)
If the right mouse button was pressed, an ON_WM_RBUTTONDOWN message is sent. Its syntax is −
afx_msg void OnRButtonDown(UINT nFlags, CPoint point)
Similarly If the left mouse is being released, the ON_WM_LBUTTONUP message is sent. Its syntax is −
afx_msg void OnLButtonUp(UINT nFlags, CPoint point)
If the right mouse is being released, the ON_WM_TBUTTONUP message is sent. Its syntax is −
afx_msg void OnRButtonUp(UINT nFlags, CPoint point)
Let us look into a simple example.
Step 1 − Add the following two functions in CMainFrame class definition as shown in the following code.
class CMainFrame : public CFrameWnd { public: CMainFrame(); protected: afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnRButtonUp(UINT nFlags, CPoint point); DECLARE_MESSAGE_MAP() };
Step 2 − Add the following two Message Maps.
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_KEYDOWN() ON_WM_LBUTTONDOWN() ON_WM_RBUTTONUP() END_MESSAGE_MAP()
Step 3 − Here is the functions definition.
void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point) { CString MsgCoord; MsgCoord.Format(L"Left Button at P(%d, %d)", point.x, point.y); MessageBox(MsgCoord); } void CMainFrame::OnRButtonUp(UINT nFlags, CPoint point) { MessageBox(L"Right Mouse Button Up"); }
Step 4 − When you run this application, you will see the following output.
Step 5 − When you click OK, you will see the following message.
Step 6 − Right-click on this window. Now, when you release the right button of the mouse, it will display the following message.