Annotation of mstools/mfc/doc/tn006.txt, revision 1.1.1.1

1.1       root        1: Microsoft Foundation Classes                           Microsoft Corporation
                      2: Technical Notes 
                      3: 
                      4: #6 : Message Maps
                      5: 
                      6: This note describes the Foundation message map facility.
                      7: 
                      8: -----------------------------------------------------------------------------
                      9: The Problem
                     10: ===========
                     11: 
                     12: Microsoft Windows implements what are essentially virtual functions
                     13: in window classes using its messaging facility.  Due to the large
                     14: number of messages involved, providing a separate virtual function
                     15: for each Windows message results in a prohibitively large 
                     16: vtable.
                     17: 
                     18: -----------------------------------------------------------------------------
                     19: Overview
                     20: ========
                     21: 
                     22: The Foundation provides an alternative to the switch statement usually
                     23: used in Windows programs to handle messages sent to a window.  A
                     24: mapping from messages to member-functions may be defined so that when
                     25: a message is to be handled by a window, the appropriate member
                     26: function is called automatically.  This message map facility was
                     27: designed to be as similar to virtual functions as possible without a
                     28: large vtable overhead.
                     29: 
                     30: 
                     31: Defining a Message Map
                     32: ======================
                     33: 
                     34: 
                     35: The DECLARE_MESSAGE_MAP macro declares a private array for the
                     36: message map entries called _messageEntries, a protected CMessageMap
                     37: called messageMap, and a protected virtual function called
                     38: GetMessageMap that returns the address of messageMap.  This macro
                     39: should be placed in the declaration of any class using message maps.
                     40: By convention, it is at the end of the class declaration.
                     41: 
                     42: For example:
                     43: 
                     44:     class CMyWnd : public CMyParentWndClass
                     45:     {
                     46:         // my stuff...
                     47:         afx_msg void OnPaint();
                     48: 
                     49:         DECLARE_MESSAGE_MAP()
                     50:     };
                     51: 
                     52: 
                     53: The message map's table is defined with a set of macros that expand
                     54: to message map entries.  A table begins with the BEGIN_MESSAGE_MAP
                     55: macro that defines the class that is handled by this message map and
                     56: the parent class to pass unhandled messages to.  The table ends with
                     57: the END_MESSAGE_MAP macro.
                     58: 
                     59: Between these two lines is an entry for each message to be handled by
                     60: this message map.  Every standard Windows message has a macro of the
                     61: form ON_WM_xxx (where xxx is the name of the message) that generates
                     62: an entry for that message.  
                     63: 
                     64: A standard function signature has been defined for unpacking the
                     65: parameters of each Windows message and providing type safety.  These
                     66: signatures may be found in the file AFXWIN.H in the declaration of
                     67: CWnd.  Each one is marked with the word afx_msg for easy identification.
                     68: 
                     69: These function signatures were derived using a simple convention to
                     70: make them easier to deduce.  The name of the function always starts
                     71: with On.  This is followed by the name of the Windows message with
                     72: the WM_ removed and only the first letter of each word capitalized.
                     73: The ordering of the parameters is wParam followed by LOWORD(lParam)
                     74: then HIWORD(lParam).  Unused parameters are not passed.  Any handles
                     75: that are wrapped by Foundation classes are converted to pointers to
                     76: the appropriate Foundation objects.
                     77: 
                     78: The following example shows how to handle the WM_PAINT message
                     79: and cause the CMyWnd::OnPaint function to get called:
                     80: 
                     81:     BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
                     82:         ON_WM_PAINT()
                     83:     END_MESSAGE_MAP()
                     84: 
                     85: The message map table must be defined outside the scope of any 
                     86: function or class definition.  It should not be placed within 
                     87: an extern "C" block.
                     88: 
                     89: 
                     90: User Defined Messages
                     91: =====================
                     92: 
                     93: User defined messages may be included in a message map by using the
                     94: ON_MESSAGE macro.  This macro accepts a message number and a member
                     95: function of the form:
                     96: 
                     97: // inside the class declaration
                     98:     afx_msg LONG OnMyMessage(UINT wParam, LONG lParam);
                     99: 
                    100: For example:
                    101: 
                    102:     #define WM_MYMESSAGE 5
                    103: 
                    104:     BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
                    105:         ON_MESSAGE(WM_USER + WM_MYMESSAGE, OnMyMessage)
                    106:     END_MESSAGE_MAP()
                    107: 
                    108: In this example, we establish a handler for a custom message with
                    109: a Windows message ID derived from the standard WM_USER base for
                    110: user-defined messages.  You might invoke this handler with code
                    111: such as:
                    112: 
                    113:     extern CMyWnd myWnd;
                    114:     myWnd->SendMessage(WM_USER + WM_MYMESSAGE);
                    115: 
                    116: 
                    117: Registered Windows Messages
                    118: ===========================
                    119: 
                    120: The ::RegisterWindowMessage function is used to define a new window
                    121: message that is guaranteed to be unique throughout the system.
                    122: The macro ON_REGISTERED_MESSAGE is used to handle these messages.
                    123: This macro accepts a the name of a near UINT variable that contains
                    124: the registered windows message ID.
                    125: 
                    126: 
                    127: For example:
                    128: 
                    129: class CMyWnd : public CMyParentWndClass
                    130: {
                    131: public:
                    132:     CMyWnd();
                    133: 
                    134:     afx_msg LONG OnFind(UINT wParam, LONG lParam);
                    135:     
                    136:     DECLARE_MESSAGE_MAP()
                    137: };
                    138: 
                    139: 
                    140: static UINT _near wm_Find = RegisterWindowMessage("commdlg_Find");
                    141: 
                    142: BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
                    143:     ON_REGISTERED_MESSAGE(wm_Find, OnFind)
                    144: END_MESSAGE_MAP()
                    145: 
                    146: 
                    147: Note: the registered Windows message ID variable (wm_Find in
                    148: the example above) must be a _near variable because of the
                    149: way ON_REGISTERED_MESSAGE is implemented.  If your program
                    150: is designed to run in an ambient far data model (large or compact)
                    151: you must explicitly qualify the variable declaration with the
                    152: __near modifier, as shown above.  You are not required to qualify
                    153: the declaration if your program uses small or medium model, but it
                    154: does not hurt to make the declaration explicit.
                    155: 
                    156: The Foundation library header file 'afx.h' #defines NEAR to be '_near'.
                    157: 
                    158: 
                    159: User Defined Command Messages
                    160: =============================
                    161: 
                    162: Command messages from menus and accelerators are handled in message
                    163: maps with the ON_COMMAND macro.  This macro accepts a command id as
                    164: well as a member function.  Only WM_COMMAND messages with a wParam
                    165: equal to the id match these table entries.  The macro has the form:
                    166: 
                    167:     ON_COMMAND(id, memberFxn)
                    168: 
                    169: Command handler member functions must take no parameters and 
                    170: return void.
                    171: 
                    172: For example:
                    173: 
                    174: // inside a resource header (usually generated by DLGEDIT)
                    175: #define    IDM_MYCMD    100
                    176: 
                    177: // inside the class declaration
                    178:     afx_msg void OnMyCommand();
                    179: 
                    180: // inside the message map definition
                    181:     ON_COMMAND(IDM_MYCMD, OnMyCommand)
                    182: 
                    183: 
                    184: Control Notification Messages
                    185: =============================
                    186: 
                    187: Messages that are sent from child controls to a window have an extra
                    188: bit of information in their message map entry: the control's id.  The
                    189: message map entry only matches the message if the id in the entry
                    190: matches the id sent with the notification message.
                    191: 
                    192: Custom control notification messages may use the ON_CONTROL macro to
                    193: define a message map entry with a custom notification code.  This
                    194: macro has the form:
                    195: 
                    196:     ON_CONTROL(wNotificationCode, id, memberFxn)
                    197: 
                    198: 
                    199: How a Message is Translated
                    200: ===========================
                    201: 
                    202: The WindowProc member function of class CWnd is the workhorse of the
                    203: message handler.  It is the default window procedure for every window
                    204: created with the Foundation.
                    205: 
                    206: When a message is to be handled, WindowProc searches the message map
                    207: attached to the window receiving the message for an appropriate
                    208: entry.  
                    209: 
                    210: If an entry is found, the wSig field of the entry is used to
                    211: call the function pointer, pfn, in the entry with the appropriate
                    212: signature.
                    213: 
                    214: If an entry is not found, the message map of the window's parent
                    215: class is searched.  This process continues until a handler is found
                    216: or the top of the CWnd class hierarchy is found at which point the
                    217: message is passed to DefWindowProc so the system can perform any
                    218: default processing.
                    219: 
                    220: A cache of recently handled messages is used to speed up searches
                    221: through the message map.
                    222: 
                    223: Registered windows messages are handled as a special case of the
                    224: general mechanism.
                    225: 
                    226: 
                    227: NOTE:
                    228: It is important to realize that the message map parent class-child
                    229: class relationship described above is established through the
                    230: BEGIN_MESSAGE_MAP macro and *NOT* through the normal C++ language
                    231: inheritance mechanism.
                    232: 
                    233: For example:
                    234: 
                    235: class CMyParentWnd : public CFrameWnd
                    236: { 
                    237:     ... 
                    238:     DECLARE_MESSAGE_MAP()
                    239: };
                    240: 
                    241: BEGIN_MESSAGE_MAP(CMyParentWnd, CFrameWnd)  // correct
                    242:    ...
                    243: END_MESSAGE_MAP()
                    244: 
                    245: class CMyWnd : public CMyParentWnd
                    246: { 
                    247:     ... 
                    248:     DECLARE_MESSAGE_MAP()
                    249: };
                    250: 
                    251: BEGIN_MESSAGE_MAP(CMyWnd, CFrameWnd)    // incorrect
                    252:   ...
                    253: END_MESSAGE_MAP()
                    254: 
                    255: The first message map is defined correctly.  CFrameWnd is an
                    256: immediate base class of CMyParentWnd, and the BEGIN_MESSAGE_MAP 
                    257: macro reflects this relationship.
                    258: 
                    259: The second message map is defined incorrectly.  While CFrameWnd
                    260: is a base class of CMyWnd, it is not an immediate base class.  If
                    261: a message is sent to a CMyWnd object that the object does not
                    262: know how to handle, the message will be passed on to the CFrameWnd
                    263: message map for processing.  The message should have been passed
                    264: to the CMyParentWnd message map first.  There is no way for this
                    265: error to be caught at compile time -- it will only be evident
                    266: by runtime misbehavior.
                    267: 
                    268: 
                    269: 
                    270: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.