Annotation of mstools/mfc/doc/tn006.txt, revision 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.