Visual C++ Main Page

Messages and Events

 

Introduction to Messages

Some of your applications will be made of various objects. Most of the time, more than one application is running on the computer. These two scenarios mean that 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, one message at a time, to the operating system. For this reason, Microsoft Windows is said to be a message-driven operating system.

The messages are divided in various categories but as mentioned already, each object has the responsibility to decide what message to send and when. Therefore, most of the messages we will review here are part of a window frame. Others will be addressed when necessary.

Once a control has composed a message, it must send it to the right target which could be the operating system. In order to send a message, a control must create an event. It is also said to fire 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. Remember, the message is what needs to be sent. The event is the action of sending the message.

A Map of Messages

For the compiler to manage messages, they should be included in the class definition. The list of messages starts on a section driven by, but that ends with, the DECLARE_MESSAGE_MAP macro. The section can be created as follows:

#include <afxwin.h>

class CSimpleFrame : public CFrameWnd
{
public:
	CSimpleFrame();

	DECLARE_MESSAGE_MAP()
};

The DECLARE_MESSAGE_MAP macro should be provided at the end of the class definition. The actual messages (as we will review them shortly) should be listed just above the DECLARE_MESSAGE_MAP line. This is mostly a suggestion. In some circumstances, and for any reason, you may want, or have, to provide one message or a few messages under the DECLARE_MESSAGE_MAP line.

To implement the messages, you should/must create a table of messages that your program is using. This table uses two delimiting macros. It 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. An example would be:

BEGIN_MESSAGE_MAP(CSimpleFrame, CFrameWnd)

Like the DECLARE_MESSAGE_MAP macro, END_MESSAGE_MAP takes no argument. Its job is simply to specify the end of the list of messages. The table of messages can be created as follows:

#include <afxwin.h>
#include "resource.h"

class CMainFrame : public CFrameWnd
{
public:
	CMainFrame ();

	DECLARE_MESSAGE_MAP()
};

CMainFrame::CMainFrame()
{
	LoadFrame(IDR_MAINFRAME);
}

class CMainApp: public CWinApp
{
public:
	BOOL InitInstance();
};

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

END_MESSAGE_MAP()

BOOL CMainApp::InitInstance()
{
	m_pMainWnd = new CMainFrame ;
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();

	return TRUE;
}

CMainApp theApp;

There various categories of messages the operating system receives. Some of them come from the keyboard, some from the mouse, and some others from various other origins. For example, some messages are sent by the application itself while some other messages are controlled by the operating.

Practical Learning: Creating a Map of Messages

  1. Create a new and empty Win32 Project located in C:\Programs\MSVC Exercises and set its the Name to Messages1
  2. Specify that you want to Use MFC in a Shared DLL
  3. Create a C++ file and name it Exercise
  4. To create a frame for the window, in the Exercise.cpp file, type the following:
     
    #include <afxwin.h>
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame ();
    
    protected:
    	
    	DECLARE_MESSAGE_MAP()
    };
    
    CMainFrame::CMainFrame()
    {
    	// Create the window's frame
    	Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
    	       CRect(120, 100, 700, 480), NULL);
    }
    
    class CExerciseApp: public CWinApp
    {
    public:
    	BOOL InitInstance();
    };
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    
    END_MESSAGE_MAP()
    
    BOOL CExerciseApp::InitInstance()
    {
    	m_pMainWnd = new CMainFrame ;
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    CExerciseApp theApp;
  5. Test the application and return to MSVC

Windows Messages

 

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. Its syntax is:

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

This message calls the CFrameWnd::Create() method to create a window. To do that, it takes one argument, which is a pointer to a CREATESTRUCT class. The CREATESTRUCT class provides all the information needed to create a window. It is defined as follows:

typedef struct tagCREATESTRUCT {
   LPVOID    lpCreateParams;
   HANDLE    hInstance;
   HMENU     hMenu;
   HWND      hwndParent;
   int       cy;
   int       cx;
   int       y;
   int       x;
   LONG      style;
   LPCSTR    lpszName;
   LPCSTR    lpszClass;
   DWORD     dwExStyle;
} CREATESTRUCT;

This class provides the same types of information as the WNDCLASS object. When sending the OnCreate() message, the class is usually created without your intervention but when calling it, you should check that the window has been created. This can be done by checking the result returned by the OnCreate() message from the parent class. If the message returns 0, the window was created. If it returns -1, the class was not created or it would simply be destroyed. This can be done as follows:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	// Create the window and make sure it doesn't return -1
	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	// else is implied
	return 0;
}

To use this message, in the class definition, type its syntax. In the message table, type the name of the message ON_WM_CREATE():

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	ON_WM_CREATE()
END_MESSAGE_MAP()

Practical Learning: Creating a Window

  1. To create an ON_WM_CREATE message, change the file as follows:
     
    #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, "Windows Application", WS_OVERLAPPEDWINDOW,
    	       CRect(120, 100, 700, 480), NULL);
    }
    
    class CExerciseApp: 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("The window has been created!!!");
                      // Since the window was successfully created, return 0
    		return 0;
    	}
    	// Otherwise, return -1
    	return -1;
    }
    
    BOOL CExerciseApp::InitInstance()
    {
    	m_pMainWnd = new CMainFrame ;
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    CExerciseApp theApp;
  2. Test the application and return to MSVC

Window's Showing State

WM_SHOWWINDOW: After creating a window, it needs to be displayed. Also, if the window was previously hidden, you can decide to show it. On the other hand, if a window is displaying, you may want to hide it, for any reason you judge necessary. To take any of these actions, that is, to show or hide a window, you must send the ON_WM_SHOWWINDOW message. The syntax of this message is:

afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);

When using this message, bShow is a Boolean argument determines what state to apply to the window. If it is TRUE, the window needs to be displayed. If it is FALSE, the window must be hidden.

nStatus is a positive integer that can have one of the following values:

  Value Description
  SW_PARENTCLOSING If the window that sent this message is a frame, the window is being minimized.
If the window  that sent this message is hosted by another window, the window is being hidden.
  SW_PARENTOPENING If the window that sent this message is a frame, the window is being restored.
If the window  that sent this message is hosted by another window, the window is displaying.
  0 The message was sent from a CWnd::ShowWindow() method.
 

Practical Learning: Showing a Window

  1. To maximize the window at startup, change the program as follows:
     
    #include <afxwin.h>
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame ();
    
    protected:
    	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    	afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
    	DECLARE_MESSAGE_MAP()
    };
    
    CMainFrame::CMainFrame()
    {
    	// Create the window's frame
    	Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
    	       CRect(120, 100, 700, 480), NULL);
    }
    
    class CExerciseApp: public CWinApp
    {
    public:
    	BOOL InitInstance();
    };
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    	ON_WM_CREATE()
    	ON_WM_SHOWWINDOW()
    END_MESSAGE_MAP()
    
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	// Call the base class to create the window
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	return 0;
    }
    
    void CMainFrame::OnShowWindow(BOOL bShow, UINT nStatus) 
    {
    	CFrameWnd::OnShowWindow(bShow, nStatus);
    	
    	// TODO: Add your message handler code here
    	ShowWindow(SW_MAXIMIZE);
    }
    
    BOOL CExerciseApp::InitInstance()
    {
    	m_pMainWnd = new CMainFrame ;
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    CExerciseApp theApp;
  2. Test the program and return to MSVC

Window Activation

WM_ACTIVATE: When two or more windows are running on the computer, only one can receive input from the user, that is, only one can actually be directly used at one particular time. Such a window has a title bar with the color identified in Control Panel as Active Window. The other window(s), if any, display(s) its/their title bar with a color called Inactive Window:

Display Properties

To manage this setting, the windows are organized in a 3-dimensional coordinate system and they are incrementally positioned on the Z coordinate, which defines the (0, 0, 0) origin on the screen (actually on the top-left corner of your monitor) with Z coordinate coming from the screen towards you.

In order to use a window other than the one that is active, you must activate it. To do this, you can send a message called ON_WM_ACTIVATE. The syntax of this message is:

afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);

This message indeed does two things: it activates a window of your choice, or brings it to the front, and deactivates the other window(s) or sends it/them to the back of the window that is being activates. The nState argument specifies what  action to apply. It is a constant that can assume of the following values:

  Value Description
  WA_ACTIVE Used to activate a window without using the mouse, may be by pressing Alt + Tab
  WA_INACTIVE Used to deactivate a window
  WA_CLICKACTIVE Used to activate a window using the mouse

If this message was sent by the window that is being activated, pWndOther designates the other window, the one being deactivated. If this message was sent by the window that is being deactivated, pWndOther designates the other window, the one being activated.

If the window that sent this message is being restored from its deactivation, pass the bMinimized value as TRUE.

When calling this message, before implementing the custom behavior you want, first call its implementation from the parent class:

void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
{
	CFrameWnd::OnActivate(nState, pWndOther, bMinimized);
	
	// TODO: Add your message handler code here
}

 

 

Practical Learning: Activating a Window

  1. To activate a window that has been created, change the file as follows:
     
    #include <afxwin.h>
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame ();
    
    protected:
    	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    	afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
    	afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
    	DECLARE_MESSAGE_MAP()
    };
    
    CMainFrame::CMainFrame()
    {
    	// Create the window's frame
    	Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
    	       CRect(120, 100, 700, 480), NULL);
    }
    
    class CExerciseApp: public CWinApp
    {
    public:
    	BOOL InitInstance();
    };
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    	ON_WM_CREATE()
    	ON_WM_SHOWWINDOW()
    	ON_WM_ACTIVATE()
    END_MESSAGE_MAP()
    
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	// Call the base class to create the window
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	return 0;
    }
    
    void CMainFrame::OnShowWindow(BOOL bShow, UINT nStatus) 
    {
    	CFrameWnd::OnShowWindow(bShow, nStatus);
    	
    	// TODO: Add your message handler code here
    	//ShowWindow(SW_SHOW);
    }
    
    void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
    {
    	CFrameWnd::OnActivate(nState, pWndOther, bMinimized);
    	
    	// TODO: Add your message handler code here
    	switch( nState )
    	{
    	case WA_ACTIVE:
    		SetWindowText("This window has been activated, without the mouse!");
    		break;
    	case WA_INACTIVE:
    		SetWindowText("This window has been deactivated and cannot be changed now!!");
    		break;
    	case WA_CLICKACTIVE:
    		SetWindowText("This window has been activated using the mouse!!!");
    		break;
    	}	
    }
    
    BOOL CExerciseApp::InitInstance()
    {
    	m_pMainWnd = new CMainFrame ;
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    CExerciseApp theApp;
  2. Test the application. While it is displaying, open Notepad
  3. Display each window using the mouse. Then activate your window using Alt+Tab
     
  4. Return to MSVC

Window Painting

WM_PAINT: Whether you have just created a window or you want to show it, you must ask the operating system to display it, showing its appearance. To display such a window, the operating system would need its location (left and top measures) and its dimension (width and height). This is because the window must be painted. Also, if the window was hidden somewhere such as behind another window or was minimized, when it comes up, the operating system needs to paint it. To do this, the window that needs to be painted must send a message called ON_WM_PAINT. This message does not return anything but in its body, you can define what needs to be painted and how you want the job to be done. The syntax of this message is simply:

afx_msg void OnPaint()

Practical Learning: Using the Paint Message

  1. To use the structure of the WM_PAINT message, change the program as follows:
     
    #include <afxwin.h>
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame ();
    
    protected:
    	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    	afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
    	afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
    	afx_msg void OnPaint();
    	DECLARE_MESSAGE_MAP()
    };
    
    CMainFrame::CMainFrame()
    {
    	// Create the window's frame
    	Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
    	       CRect(120, 100, 700, 480), NULL);
    }
    
    class CExerciseApp: public CWinApp
    {
    public:
    	BOOL InitInstance();
    };
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    	ON_WM_CREATE()
    	ON_WM_SHOWWINDOW()
    	ON_WM_ACTIVATE()
    	ON_WM_PAINT()
    END_MESSAGE_MAP()
    
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	return 0;
    }
    
    void CMainFrame::OnShowWindow(BOOL bShow, UINT nStatus) 
    {
    	CFrameWnd::OnShowWindow(bShow, nStatus);
    	
    	// TODO: Add your message handler code here
    	//ShowWindow(SW_SHOW);
    }
    
    void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
    {
    	CFrameWnd::OnActivate(nState, pWndOther, bMinimized);
    	
    	// TODO: Add your message handler code here
    	switch( nState )
    	{
    	case WA_ACTIVE:
    		SetWindowText("This window has been activated, without the mouse!");
    		break;
    	case WA_INACTIVE:
    		SetWindowText("This window has been deactivated and cannot be changed now!!");
    		break;
    	case WA_CLICKACTIVE:
    		SetWindowText("This window has been activated using the mouse!!!");
    		break;
    	}	
    }
    
    void CMainFrame::OnPaint() 
    {
    	CFrameWnd::OnPaint();
    
    	SetWindowText("The window has been painted<==>");
    }
    
    BOOL CExerciseApp::InitInstance()
    {
    	m_pMainWnd = new CMainFrame ;
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    CExerciseApp theApp;
  2. Test the application and return to MSVC

Window Sizing

WM_SIZE: When using an application, one of the actions a user can perform on a window is to change its size, provided the window allows this. Also, some time to time, if the window allows it, the user can minimize, maximize, or restore a window. Whenever any of these actions occur, the operating system must keep track of the size of a window. When the size of a window has changed, the window sends the ON_WM_SIZE message. Its syntax is:

afx_msg void OnSize(UINT nType, int cx, int cy);

The nType argument specifies what type of action to take. It can have one of the following values:

  Value Description
  SIZE_MINIMIZED The window has been minimized
  SIZE_MAXIMIZED The window has been maximized
  SIZE_RESTORED The window has been restored from  being maximized or minimized
  SIZE_MAXHIDE Another window, other than this one, has been maximized
  SIZE_MAXSHOW Another window, other than this one, has been restored from  being maximized or minimized

The cx argument specifies the new width of the client area of the window

The cy argument specifies the new height of the client area of the window.

To use this message, you should first call its implementation in the parent class before implementing the behavior you want. This can be done as follows:

void CAnyWindow::OnSize(UINT nType, int cx, int cy) 
{
	CParentClass::OnSize(nType, cx, cy);
	
	// TODO: Add your message handler code here
}

WM_SIZING: While the user is changing the size of a window, a message called ON_WM_SIZING is being sent. Its syntax is:

afx_msg void OnSizing(UINT nSide, LPRECT lpRect);

When a user is resizing a window, he or she typically drags one of the borders or corners on a direction of his or her choice. The first argument, nSize, indicates what edge is being moved when resizing the window. It can have one of the following values:

  Value Description
  WMSZ_BOTTOM Bottom edge
  WMSZ_BOTTOMLEFT Bottom-left corner
  WMSZ_BOTTOMRIGHT Bottom-right corner
  WMSZ_LEFT Left edge
  WMSZ_RIGHT Right edge
  WMSZ_TOP Top edge
  WMSZ_TOPLEFT Top-left corner
  WMSZ_TOPRIGHT Top-right corner

Values of handle used to resize a window

 

The second argument, lpRect, is the new rectangle that will enclose the window after the window has been moved, resized, or restored.

Window Moving

WM_MOVE: When a window has been moved, the operating system needs to update its location. Therefore, the window sends a message called ON_WM_MOVE. Its syntax is:

afx_msg void OnMove(int x, int y);

The first argument of this message specifies the left horizontal location of the left border of the window after the window has been moved. The second argument represents the vertical position of the top border of the window after the window has been moved.

If you want to send this message, you should first call its implementation in the parent class

WM_MOVING: While the user is moving a window, it (the window sends) an ON_WM_MOVING message. Its syntax is:

afx_msg void OnMoving( UINT nSide, LPRECT lpRect );

The first argument, nSide, is the edge of the window that is being moved. It is the same as for the ON_MOVE message.

The lpRect is the target dimension of the window that is being moved. That is, it contains the new dimensions of the window as it is being moved.

 

Practical Learning: Moving a Window

  1. To see the effect of moving a window, change the file as follows:
     
    #include <afxwin.h>
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame ();
    
    protected:
    	afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
    	afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
    	afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
    	afx_msg void OnPaint();
    	afx_msg void OnSize(UINT nType, int cx, int cy);
    	afx_msg void OnMove(int x, int y);
    	DECLARE_MESSAGE_MAP()
    };
    
    CMainFrame::CMainFrame()
    {
    	// Create the window's frame
    	Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
    	       CRect(120, 100, 700, 480), NULL);
    }
    
    class CExerciseApp: public CWinApp
    {
    public:
    	BOOL InitInstance();
    };
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    	ON_WM_CREATE()
    	ON_WM_SHOWWINDOW()
    	ON_WM_ACTIVATE()
    	ON_WM_PAINT()
    	ON_WM_SIZE()
    	ON_WM_MOVE()
    END_MESSAGE_MAP()
    
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	return 0;
    }
    
    void CMainFrame::OnShowWindow(BOOL bShow, UINT nStatus) 
    {
    	CFrameWnd::OnShowWindow(bShow, nStatus);
    	
    	// TODO: Add your message handler code here
    	//ShowWindow(SW_SHOW);
    }
    
    void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
    {
    	CFrameWnd::OnActivate(nState, pWndOther, bMinimized);
    	
    	// TODO: Add your message handler code here
    	switch( nState )
    	{
    	case WA_ACTIVE:
    		SetWindowText("This window has been activated, without the mouse!");
    		break;
    	case WA_INACTIVE:
    		SetWindowText("This window has been deactivated and cannot be changed now!!");
    		break;
    	case WA_CLICKACTIVE:
    		SetWindowText("This window has been activated using the mouse!!!");
    		break;
    	}	
    }
    
    void CMainFrame::OnPaint() 
    {
    	CFrameWnd::OnPaint();
    
    	SetWindowText("The window has been painted<==>");
    }
    
    void CMainFrame::OnSize(UINT nType, int cx, int cy) 
    {
    /*	CMainFrame::OnSize(nType, cx, cy);
    	
    	// TODO: Add your message handler code here
    	char *MsgToShow = new char[20];
    	char *MsgCoord  = new char[20];
    	
    	switch(nType)
    	{
    	case SIZE_MINIMIZED:
    		strcpy(MsgToShow, "Minimized ");
    		break;
    	case SIZE_MAXIMIZED:
    		strcpy(MsgToShow, "Maximized ");
    		break;
    	case SIZE_RESTORED:
    		strcpy(MsgToShow, "Restored ");
    		break;
    	case SIZE_MAXHIDE:
    		strcpy(MsgToShow, "Maximized Not Me ");
    		break;
    	case SIZE_MAXSHOW:
    		strcpy(MsgToShow, "Restored Not Me ");
    		break;
    	}
    
    	sprintf(MsgCoord, "Left = %d | Top = %d", cx, cy);
    	strcat(MsgToShow, MsgCoord);
    	SetWindowText(MsgToShow);
    */
    }
    
    void CMainFrame::OnMove(int x, int y) 
    {
    	CFrameWnd::OnMove(x, y);
    	
    	// TODO: Add your message handler code here
    	char *MsgCoord  = new char[20];
    
    	sprintf(MsgCoord, "Left = %d | Top = %d", x, y);
    	
    	SetWindowText(MsgCoord);
    }
    
    BOOL CExerciseApp::InitInstance()
    {
    	m_pMainWnd = new CMainFrame ;
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    CExerciseApp theApp;
  2. Test the application:
     
  3. Return to MSVC

Window Destruction

WM_DESTROY: Once the window has been used and the user has closed it, the window must send a message to the operating system to destroy it. The message sent is called ON_WN_DESTROY and its syntax is:

afx_msg void OnDestroy( );

This message takes no argument but you can use its body to do any last minute assignment as needed. For example, you can use it either to prevent the window from being closed or you can enquire whether the user really wants to close the window.

Command Messages

 

Definition

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.

Creating a Command Message

You can start by declaring a framework method. Here is an example:

afx_msg void OnLetItGo();

Then you can define the method as you see fit:

void CMainFrame::OnLetItGo()
{
	// Something to do here
}

The framework allows you to associate a member function to a command message. This is done using the ON_COMMAND macro. Its syntax:

ON_COMMAND(IDentifier, MethodName)

The first argument, IDentifier, of this macro must be the identifier of the menu item or Windows control you want to associate with a method.

The second argument, MethodName, must be the name of the member function that will implement the action of the menu item or Windows control such a button.

Imagine you have a menu item IDentified as ID_ACTION_LETITGO that you want to associate with the above OnLetItGo() method. You can use the ON_COMMAND macro as follows:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	ON_COMMAND(ID_ACTION_LETITGO, OnLetItGo)
END_MESSAGE_MAP()

In the same way, you can create as many command messages as necessary.

Keyboard Messages

 

Introduction

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. The signal is analyzed to find its meaning. If the program or control that has focus is equipped to deal with the signal, it may produce the expected result. If the program or control cannot figure out what to do, it ignores the action.

Each key has a code that the operating system can recognize. This code is known as the virtual key code and they are as follows:

 
Virtual Key Used for Virtual Key Used for
VK_F1 F1 VK_F2 F2
VK_F3 F3 VK_F4 F4
VK_F5 F5 VK_F6 F6
VK_F7 F7 VK_F8 F8
VK_F9 F9 VK_F10 F10
VK_F11 F11 VK_F12 F12
VK_SCROLL Scroll Lock VK_SNAPSHOT Prt Scrn (Depends on keyboard)
VK_PAUSE Pause/Break VK_TAB Tab
VK_BACK Backspace VK_CAPITAL Caps Lock
VK_SHIFT Shift VK_CONTROL Ctrl
VK_MENU Alt VK_ESCAPE Escape
K_RETURN Enter VK_SPACE Space Bar
VK_INSERT Insert VK_HOME Home
VK_PRIOR Page Up VK_DELETE Delete
VK_END End VK_NEXT  Page Down
VK_UP Up Arrow Key VK_RIGHT Right Arrow Key
VK_DOWN Down Arrow Key VK_LEFT Left Arrow Key
VK_LWIN Left Windows Key VK_RWIN Right Windows Key
VK_APPS Applications Key    
The following keys apply to the Numeric Keypad  
VK_NUMLOCK Num Lock    
VK_NUMPAD0 0 VK_NUMPAD1 1
VK_NUMPAD2 2 VK_NUMPAD3 3
VK_NUMPAD4 4 VK_NUMPAD5 5
VK_NUMPAD6 6 VK_NUMPAD7 7
VK_NUMPAD8 8 VK_NUMPAD9 9
VK_DIVIDE / VK_MULTIPLY *
VK_SUBTRACT - VK_ADD +
VK_SEPARATOR   VK_DECIMAL .

There are actually more keys than that but the above are the most frequently used.

Practical Learning: Introducing Keyboard Messages

  1. Create a new and empty Win32 Project located in C:\Programs\MSVC Exercises and set its the Name to Messages2
  2. Specify that you want to Use MFC in a Shared DLL
  3. Create a C++ file and name it Exercise
  4. To create a frame for the window, in the Exercise.cpp file, type the following:
     
    #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, "Windows Application", WS_OVERLAPPEDWINDOW,
    	       CRect(120, 100, 700, 480), NULL);
    }
    
    class CExerciseApp: public CWinApp
    {
    public:
    	BOOL InitInstance();
    };
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    	ON_WM_CREATE()
    END_MESSAGE_MAP()
    
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	return 0;
    }
    
    BOOL CExerciseApp::InitInstance()
    {
    	m_pMainWnd = new CMainFrame ;
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    CExerciseApp theApp;
  5. Test the application and return to MSVC

The Key Down Effect

When we think of the keyboard, the first thing that comes in mind if to press a key. When a keyboard key is pressed, a message called WM_KEYDOWN. Its syntax is:

afx_msg void OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags );

The first argument, nChar, specifies the virtual code of the key that was pressed.

The second argument, nRepCnt, specifies the number of times counted repeatedly as the key was held down.

The nFlags argument specifies the scan code, extended-key flag, context code, previous key-state flag, and transition-state flag.

Practical Learning: Sending Key Down Messages

  1. To experiment with the ON_KEYDOWN message, change the file as follows:
     
    #include <afxwin.h>
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame ();
    
    protected:
    	afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
    	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
    
    	DECLARE_MESSAGE_MAP()
    };
    
    CMainFrame::CMainFrame()
    {
    	// Create the window's frame
    	Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
    	       CRect(120, 100, 700, 480), NULL);
    }
    
    class CExerciseApp: public CWinApp
    {
    public:
    	BOOL InitInstance();
    };
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    	ON_WM_CREATE()
    	ON_WM_KEYDOWN()
    END_MESSAGE_MAP()
    
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	return 0;
    }
    
    void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
    {
    	switch(nChar)
    	{
    	case VK_RETURN:
    		SetWindowText("You pressed Enter");
    		break;
    	case VK_F1:
    		SetWindowText("Help is not available at the moment");
    		break;
    	case VK_DELETE:
    		SetWindowText("Can't Delete This");
    		break;
    	default:
    		SetWindowText("Whatever");
    	}
    }
    
    BOOL CExerciseApp::InitInstance()
    {
    	m_pMainWnd = new CMainFrame ;
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    CExerciseApp theApp;
  2. Test the application and return to MSVC

The Key Up Effect

When we think of the keyboard, the first thing that comes in mind might refer to typing, which consists of pressing a key and releasing it immediately. As this is done, a key is pressed down and brought back up. When the user is releasing a key a WM_KEYUP message is sent. Its syntax is:

afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);

The first argument, nChar, is the code of the key that was pressed.

The second argument, nRepCnt, specifies the number of times counted repeatedly as the key was held down.

The nFlags argument specifies the scan code, extended-key flag, context code, previous key-state flag, and transition-state flag.

Mouse Messages

 

Introduction

The mouse is another object that is attached to the computer allowing the user to interact with the machine. The mouse and the keyboard can each accomplish some tasks that are not normally available on the other and both can accomplish some tasks the same way.

The mouse is equipped with two, three, or more buttons. When a mouse has two buttons, one is usually located on the left and the other is located on the right. When a mouse has three buttons, one is in the middle of the other two. The mouse is used to select a point or position on the screen. Once the user has located an item, which could also be an empty space, a letter or a word, he or she would position the mouse pointer on it. To actually use the mouse, the user would press either the left, the middle (if any), or the right button. If the user presses the left button once, this action is called Click. If the user presses the right mouse button, the action is referred to as Right-Click. If the user presses the left button twice and very fast, the action is called Double-Click.

Mouse-Down Messages

Imagine the user has located a position or an item on a document and presses one of the mouse buttons. While the button is pressed and is down, a button-down message is sent, depending on the button that was pressed.

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);

The first argument, nFlags, specifies what button is down or what keyboard key and what mouse button are down. It is a constant integer that can have one of the following values:

  Value Description
  MK_CONTROL A Ctrl key is held down
  MK_LBUTTON The left mouse button is down
  MK_MBUTTON The middle mouse button is down
  MK_RBUTTON The right mouse button is down
  MK_SHIFT A Shift key is held down

The point argument specifies the measure from the left and the top borders of the window to the mouse pointer.

Practical Learning: Sending a Mouse Down Message

  1. To experiment with the mouse down effect, change the program as follows:
     
    #include <afxwin.h>
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame ();
    
    protected:
    	afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
    	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
    	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    
    	DECLARE_MESSAGE_MAP()
    };
    
    CMainFrame::CMainFrame()
    {
    	// Create the window's frame
    	Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
    	       CRect(120, 100, 700, 480), NULL);
    }
    
    class CExerciseApp: public CWinApp
    {
    public:
    	BOOL InitInstance();
    };
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    	ON_WM_CREATE()
    	ON_WM_KEYDOWN()
    	ON_WM_LBUTTONDOWN()
    END_MESSAGE_MAP()
    
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	return 0;
    }
    
    void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
    {
    	switch(nChar)
    	{
    	case VK_RETURN:
    		SetWindowText("You pressed Enter");
    		break;
    	case VK_F1:
    		SetWindowText("Help is not available at the moment");
    		break;
    	case VK_DELETE:
    		SetWindowText("Can't Delete This");
    		break;
    	default:
    		SetWindowText("Whatever");
    	}
    }
    
    void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point) 
    {
    	char *MsgCoord  = new char[20];
    
    	sprintf(MsgCoord, "Left Button at P(%d, %d)", point.x, point.y);
    	
    	SetWindowText(MsgCoord);
    }
    
    BOOL CExerciseApp::InitInstance()
    {
    	m_pMainWnd = new CMainFrame ;
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    CExerciseApp theApp;
  2. Test the program:
     
  3. Return to MSVC

The Mouse-Up Messages

After pressing a mouse button, the user usually releases it. While the button is being released, a button-up message is sent and it depends on the button, left or right, that was down.

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);

The first argument, nFlags, specifies what button, right or middle, is down or what keyboard key and what mouse button were down. It is a constant integer that can have one of the following values:

  Value Description
  MK_CONTROL A Ctrl key was held down
  MK_MBUTTON The middle mouse button was down
  MK_RBUTTON The right mouse button was down
  MK_SHIFT A Shift key was held

The point argument specifies the measure from the (0, 0) origin of the window to the mouse pointer.

Practical Learning: Sending a Mouse Down Message

  1. To experiment with a mouse up message, change the program as follows:
     
    #include <afxwin.h>
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame ();
    
    protected:
    	afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
    	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()
    };
    
    CMainFrame::CMainFrame()
    {
    	// Create the window's frame
    	Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
    	       CRect(120, 100, 700, 480), NULL);
    }
    
    class CExerciseApp: public CWinApp
    {
    public:
    	BOOL InitInstance();
    };
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    	ON_WM_CREATE()
    	ON_WM_KEYDOWN()
    	ON_WM_LBUTTONDOWN()
    	ON_WM_RBUTTONUP()
    END_MESSAGE_MAP()
    
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	return 0;
    }
    
    void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
    {
    	switch(nChar)
    	{
    	case VK_RETURN:
    		SetWindowText("You pressed Enter");
    		break;
    	case VK_F1:
    		SetWindowText("Help is not available at the moment");
    		break;
    	case VK_DELETE:
    		SetWindowText("Can't Delete This");
    		break;
    	default:
    		SetWindowText("Whatever");
    	}
    }
    
    void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point) 
    {
    	char *MsgCoord  = new char[20];
    
    	sprintf(MsgCoord, "Left Button at P(%d, %d)", point.x, point.y);
    	
    	SetWindowText(MsgCoord);
    }
    
    void CMainFrame::OnRButtonUp(UINT nFlags, CPoint point) 
    {
    	SetWindowText("Right Mouse Button Up");
    }
    
    BOOL CExerciseApp::InitInstance()
    {
    	m_pMainWnd = new CMainFrame ;
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    CExerciseApp theApp;
  2. Execute the program. To test it, click in the middle of the window and hold the mouse down
  3. Then release the mouse. Notice that the title bar displays the new message only when the mouse is up.
  4. Return to MSVC

The Double-Click Message

Instead of pressing and simply releasing a mouse button, a classic action the user can perform with the mouse is to double-click an object. When this is done, a double-click message is sent. The message to consider actually depends on the button that was double-pressed.

If the double-click was performed using the left mouse button, the WM_LBUTTONDBLCLK message is sent and its syntax is:

afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);

If the action was performed using the right mouse button, the WM_RBUTTONDBLCLK message would be sent. Its syntax is:

afx_msg void OnRButtonDblClk(UINT nFlags, CPoint point);

In both cases the nFlags argument specifies the button that was double-clicked. This argument can have one of the following values:

  Value Description
  MK_CONTROL A Ctrl key was held down when the user double-clicked
  MK_LBUTTON The left mouse button is down
  MK_MBUTTON The middle mouse button is down
  MK_RBUTTON The right mouse button is down
  MK_SHIFT A Shift key was held down when the user double-clicked

The point argument specifies the location of the mouse pointer in x (horizontal) and y (vertical) coordinates.

Mouse Moving

After pressing one of the mouse buttons, depending on the requirement, the use may not need to immediately release the button. Another action performed with the mouse consists of clicking and holding the mouse button down, then dragging in a chosen direction. This action refers to the mouse moving. When this is done a WM_MOUSEMOVE message is sent. Its syntax is:

afx_msg void OnMouseMove(UINT nFlags, CPoint point);

The nFlags argument specifies what button is held down or what key is pressed in combination with the button that is held down while the mouse pointer is moving. This argument can have one of the following values:

  Value While the mouse is moving
  MK_CONTROL A Ctrl key is held down 
  MK_LBUTTON The left mouse button is down
  MK_MBUTTON The middle mouse button is down
  MK_RBUTTON The right mouse button is down
  MK_SHIFT A Shift key was held down

The point argument specifies the current location of the mouse pointer in x (horizontal) and y (vertical) coordinates at the time the message is captured.

Conditional Messages

 

Introduction

The messages we have used so far belong to specific events generated at a particular time by a window. Sometimes in the middle of doing something, you may want to send a message regardless of what is going on. This is made possible by a function called SendMessage(). Actually, there are two SendMessage() versions available.

The Win32 API version of the SendMessage() function has the following syntax:

LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

The MFC version is defined as follows:

LRESULT SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam);

Because the Win32 version is considered global, if you want to use it, you must precede it with the scope access operator "::" as in:

::SendMessage(WhatToDo);

The hWnd argument is the object or control that is sending the message.

The Msg argument is the message to be sent.

The wParam and the lParam values depend on the message that is being sent.

The advantage of using the SendMessage() function is that, when sending this message, it would target the procedure that can perform the task and this function would return only after its message has been processed.

Sending Messages

In order to send a message using the SendMessage() function, you must know what message you are sending and what that message needs in order to be complete. For example, to change the caption of a window at any time, you can use the WM_SETTEXT message. The syntax to use would be:

SendMessage(WM_SETTEXT, wParam, lParam);

Obviously you would need to provide the text for the caption you are trying to change. This string is carried by the lParam argument as a null-terminated string. For this message, the wParam is ignored.

Practical Learning Practical Learning: Sending Messages

  1. To process a message using the SendMessage() function, change the OnRButtonUp() event as follows:
     
    void CMainFrame::OnRButtonUp(UINT nFlags, CPoint point) 
    {
    	const char *Msg = "This message was sent";
    	SendMessage(WM_SETTEXT, 0, (LPARAM)(LPCTSTR)Msg);
    }
  2. Test the application and return to MSVC
 

Previous Copyright © 2003-2005 FunctionX, Inc. Next