Solved

BEGIN_MESSAGE_MAP ....

Posted on 2004-03-30
6
3,421 Views
Last Modified: 2007-12-19
Hi Experts,

    Can anyone please tell me what do "BEGIN_MESSAGE_MAP" and "END_MESSAGE_MAP" do ? also, how are they different from "afx_MSG_MAP" ? Thanks !

meow

0
Comment
Question by:meow00
6 Comments
 
LVL 14

Expert Comment

by:wayside
Comment Utility
BEGIN_MESSAGE_MAP and END_MESSAGE_MAP are macros that set up a table  that maps a Windows message to the function to call to handle it.

I don't know what an "afx_MSG_MAP" is; if you are referring to the line in a header file that looks like

  //{{AFX_MSG(CMyClass)

it's a marker for Class Wizard to know what was created by the Class Wizard.

0
 
LVL 1

Author Comment

by:meow00
Comment Utility
..... thanks for the information .... so what is "macro" ? how is it defined and used exactly ? thanks !
meow.
0
 
LVL 14

Assisted Solution

by:wayside
wayside earned 50 total points
Comment Utility
A macro sets up text which gets substituted in your code everywhere the macro appears. This happens before the code is compiled (it is often called the preprocessing step).

For example if I do this:

#define PURPLE 12

then everywhere I use PURPLE in my code, 12 will be substituted.

You can also do blocks of code:

#define MY_MAX(x,y) ((x)>(y)?(x):(y))

So if I have

int a = MY_MAX(b+3,c+4);

this gets turned into

int a = ((b+3)>(c+4)?(b+3):(c+4));


Becaause the substitutions happen before the code is compiled, the macro can be a code fragment:

#define START_WHILE (a, b) while ((a) != (b)) {
#define END_WHILE }

Then I can do

int a = 0;
int b = 10;

START_WHILE(a,b)
a++;
END_WHILE

This sort of thing is generally frowned on but is occasionally handy. The BEGIN_MESSAGE_MAP/END_MESSAGE_MAP pair do this.
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 10

Accepted Solution

by:
Sys_Prog earned 150 total points
Comment Utility
Here is an excerpt from good MFC book. It explains well

The Message Map
How is it that a WM_PAINT message from Windows turns into a call to CMainWindow::OnPaint? The answer lies in the message map. A message map is a table that correlates messages and member functions. When Hello's frame window receives a message, MFC scans the window's message map, sees that a handler exists for WM_PAINT messages, and calls OnPaint. The message map is MFC's way of avoiding the lengthy vtables that would be required if every class had a virtual function for every possible message it might receive. Any class derived from CCmdTarget can contain a message map. What MFC does internally to implement message maps is hidden behind some rather complex macros, but using a message map is exceedingly simple. Here's all you have to do to add a message map to a class:


Declare the message map by adding a DECLARE_MESSAGE_MAP statement to the class declaration.


Implement the message map by placing macros identifying the messages that the class will handle between calls to BEGIN_MESSAGE_MAP and END_MESSAGE_MAP.


Add member functions to handle the messages.

Hello's CMainWindow class handles just one message type, WM_PAINT, so its message map is implemented as follows:

BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
    ON_WM_PAINT ()
END_MESSAGE_MAP ()

 


BEGIN_MESSAGE_MAP begins the message map and identifies both the class to which the message map belongs and the base class. (Message maps are passed by inheritance just as other class members are. The base class name is required so that the framework can find the base class's message map when necessary.) END_MESSAGE_MAP ends the message map. In between BEGIN_MESSAGE_MAP and END_MESSAGE_MAP are the message map entries. ON_WM_PAINT is a macro defined in the MFC header file Afxmsg_.h. It adds an entry for WM_PAINT messages to the message map. The macro accepts no parameters because it is hardcoded to link WM_PAINT messages to the class member function named OnPaint. MFC provides macros for more than 100 Windows messages, ranging from WM_ACTIVATE to WM_WININICHANGE. You can get the name of the message handler that corresponds to a given ON_WM macro from the MFC documentation, but it's fairly easy to deduce the name yourself by replacing WM_ with On and converting all the remaining letters except those at the beginning of the word to lowercase. Thus, WM_PAINT becomes OnPaint, WM_LBUTTONDOWN becomes OnLButtonDown, and so on.

You'll need to consult the MFC documentation to determine what kinds of arguments a message handler receives and what type of value it returns. OnPaint takes no arguments and returns no value, but OnLButtonDown is prototyped like this:

afx_msg void OnLButtonDown (UINT nFlags, CPoint point)

 


nFlags contains bit flags specifying the state of the mouse buttons and the Ctrl and Shift keys, and point identifies the location at which the click occurred. The arguments passed to a message handler come from the wParam and lParam parameters that accompanied the message. But whereas wParam and lParam are of necessity generic, the parameters passed to an MFC message handler are both specific and type-safe.

What happens if you want to process a message for which MFC doesn't provide a message-map macro? You can create an entry for the message using the generic ON_MESSAGE macro, which accepts two parameters: the message ID and the address of the corresponding class member function. The following statement maps WM_SETTEXT messages to a member function named OnSetText:

ON_MESSAGE (WM_SETTEXT, OnSetText)
 


OnSetText would be declared like this:

afx_msg LRESULT OnSetText (WPARAM wParam, LPARAM lParam);
 


Other special-purpose message-map macros provided by MFC include ON_COMMAND, which maps menu selections and other UI events to class member functions, and ON_UPDATE_COMMAND_UI, which connects menu items and other UI objects to "update handlers" that keep them in sync with the internal state of the application. You'll be introduced to these and other message-map macros in the chapters that follow.

Getting back to Hello for a moment, CMainWindow's OnPaint function and message map are declared with the following statements in Hello.h:

afx_msg void OnPaint ();
DECLARE_MESSAGE_MAP ()
 


afx_msg is a visual reminder that OnPaint is a message handler. You can omit it if you'd like because it reduces to white space when compiled. The term afx_msg is meant to connote a function that behaves as if it were a virtual function but does so without requiring a vtable entry. DECLARE_MESSAGE_MAP is usually the final statement in the class declaration because it uses C++ keywords to specify the visibility of its members. You can follow DECLARE_MESSAGE_MAP with statements declaring other class members, but if you do, you should also lead off with a public, protected, or private keyword to ensure the visibility you want for those members.

How Message Maps Work
You can find out how message maps work by examining the DECLARE_MESSAGE_MAP, BEGIN_MESSAGE_MAP, and END_MESSAGE_MAP macros in Afxwin.h and the code for CWnd::WindowProc in Wincore.cpp. Here's a synopsis of what goes on under the hood when you use message-mapping macros in your code, and how the framework uses the code and data generated by the macros to convert messages into calls to corresponding class member functions.

MFC's DECLARE_MESSAGE_MAP macro adds three members to the class declaration: a private array of AFX_MSGMAP_ENTRY structures named _messageEntries that contains information correlating messages and message handlers; a static AFX_MSGMAP structure named messageMap that contains a pointer to the class's _messageEntries array and a pointer to the base class's messageMap structure; and a virtual function named GetMessageMap that returns messageMap's address. (The macro implementation is slightly different for an MFC application that's dynamically rather than statically linked to MFC, but the principle is the same.) BEGIN_MESSAGE_MAP contains the implementation for the GetMessageMap function and code to initialize the messageMap structure. The macros that appear between BEGIN_MESSAGE_MAP and END_MESSAGE_MAP fill in the _messageEntries array, and END_MESSAGE_MAP marks the end of the array with a NULL entry. For the statements

// In the class declaration
DECLARE_MESSAGE_MAP ()

// In the class implementation
BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
    ON_WM_PAINT ()
END_MESSAGE_MAP ()
 


the compiler's preprocessor generates this:

// In the class declaration
private:
    static const AFX_MSGMAP_ENTRY _messageEntries[];
protected:
    static const AFX_MSGMAP messageMap;
    virtual const AFX_MSGMAP* GetMessageMap() const;

// In the class implementation
const AFX_MSGMAP* CMainWindow::GetMessageMap() const
    { return &CMainWindow::messageMap; }

const AFX_MSGMAP CMainWindow::messageMap = {
    &CFrameWnd::messageMap,
    &CMainWindow::_messageEntries[0]
};

const AFX_MSGMAP_ENTRY CMainWindow::_messageEntries[] = {
    { WM_PAINT, 0, 0, 0, AfxSig_vv,
        (AFX_PMSG)(AFX_PMSGW)(void (CWnd::*)(void))OnPaint },
    {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
};

 


With this infrastructure in place, the framework can call GetMessageMap to get a pointer to CMainWindow's messageMap structure. It can then scan the _messageEntries array to see if CMainWindow has a handler for the message, and if necessary it can grab a pointer to CFrameWnd's messageMap structure and scan the base class's message map, too.

That's a pretty good description of what happens when a message for CMainWindow arrives. To dispatch the message, the framework calls the virtual WindowProc function that CMainWindow inherits from CWnd. WindowProc calls OnWndMsg, which in turn calls GetMessageMap to get a pointer to CMainWindow::messageMap and searches CMainWindow::_messageEntries for an entry whose message ID matches the ID of the message that is currently awaiting processing. If the entry is found, the corresponding CMainWindow function (whose address is stored in the _messageEntries array along with the message ID) is called. Otherwise, OnWndMsg consults CMainWindow::messageMap for a pointer to CFrameWnd::messageMap and repeats the process for the base class. If the base class doesn't have a handler for the message, the framework ascends another level and consults the base class's base class, systematically working its way up the inheritance chain until it finds a message handler or passes the message to Windows for default processing. Figure 1-5 illustrates CMainWindow's message map schematically and shows the route that the framework travels as it searches for a handler to match a given message ID, beginning with the message map entries for CMainWindow.

What MFC's message-mapping mechanism amounts to is a very efficient way of connecting messages to message handlers without using virtual functions. Virtual functions are not space-efficient because they require vtables, and vtables consume memory even if the functions in them are not overridden. The amount of memory used by a message map, in contrast, is proportional to the number of entries it contains. Since it's extremely rare for a programmer to implement a window class that includes handlers for all of the different message types, message mapping conserves a few hundred bytes of memory just about every time a CWnd is wrapped around an HWND.

Amit
0
 
LVL 1

Assisted Solution

by:GJanusz
GJanusz earned 50 total points
Comment Utility
If you are using VS 2003 and want to see what MFC macros are being transformed into before they are compiled, pull up the properties for your project, then under Configuration Properties -> C/C++ -> Preprocessor, change "Generate Preprocessed File" to "With Line Numbers (/P)" or "Without Line Numbers (/EP /P)."  Then recompile the file you are interested in.  It will create a large file with a *.i extention.  All the declarations from #includes will be there, which is why the file is so large (with a lot of whitespace).  Scroll to the bottom to find your code.  Sometimes it is hard find the line(s) of code you want to look at, so before doing all this, put unique code fragments before and after the MACRO you want to examine (not comments, which are removed by the preprocessor).
0
 
LVL 14

Expert Comment

by:wayside
Comment Utility
> Virtual functions are not space-efficient because they require vtables, and vtables > consume memory even if the functions in them are not overridden. The amount of > memory used by a message map, in contrast, is proportional to the number of
> entries it contains.

There are at least two downsides to using message maps, however:

1) They are not type-safe. One of the primary reasons MFC programs work in debug but crash in release build is that a handler has been added to the message map by hand and it doesn't have the right prototype for that message.

2) They are not time efficient. Instead of having a nice efficient vtable it has to search through (possibly) multiple message maps until it finds an entry to handle the event.

In the days of 8 mb Windows systems the message map might have been a good choice; if the MFC developers were doing this today I wonder if they would make the same choice.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now