65.9K
CodeProject is changing. Read more.
Home

Message Reflection for WTL Controls

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.08/5 (5 votes)

Jan 26, 2001

viewsIcon

63153

downloadIcon

989

Impementation of message reflection for WTL wrappers for Windows Controls

  • Download demo project - 10 Kb
  • Download source - 1 Kb
  • Introduction

    Recently I needed to create a WTL control that would handle all its functionality inside of the control itself, like can be done in any standard MFC control.

    In MFC to do this the Control should get its own notifications back from its parent using message reflection, which is described in TN061-TN062. I did not found anything like this in the current version of WTL, so I decided to implement it myself. I created two macros: the first macro does the reflection - it sends some of the notifications received by the window back to it source, and the second macro which resides in a control wrapper handle these messages. Maybe this way is slightly rude but so far it works and it is simple... ;-)

    Here is the first macros, "reflector":

    #define WM_NOTIFY_REFLECTOR()\
        if(uMsg == WM_NOTIFY)\
        {\
            UINT code = ((LPNMHDR)lParam)->code;\
            switch(code)\
            {\
            case NM_SETCURSOR:\
                break;\
            default:\
                if ((NULL != lParam) &&\
                (NULL != ((LPNMHDR)lParam)->hwndFrom))\
                {\
                    BOOL bHandled = ::SendMessage(((LPNMHDR)lParam)->hwndFrom, \
                                                  WM_NOTIFY + WM_REFLECT_BASE, wParam, lParam);\
                    if(bHandled) \
                        return TRUE; \
                };\
            };\
        }\
    

    To use it just place it in message map of any window which you want to reflect WM_NOTIFY.

    Here is the second macros, "handler":

    #define NOTIFY_REFLECT_CODE_HANDLER(cd, func) \
    { \
        if (((WM_NOTIFY + WM_REFLECT_BASE) == uMsg) && \
            (NULL != lParam) && \
            (cd == ((LPNMHDR)lParam)->code)) \
        {\
            bHandled = FALSE;\
            lResult = func((int)wParam, (LPNMHDR)lParam, bHandled);\
            if(bHandled)\
                return TRUE;\
        }\
    }
    

    Use it just like usual MESSAGE_HANDLER or NOTIFY_HANDLER in message map of control.

        BEGIN_MSG_MAP(CCusomTreeCtrl)
            NOTIFY_REFLECT_CODE_HANDLER(TVN_ITEMEXPANDING, OnExpand)
        END_MSG_MAP()
        LRESULT OnExpand(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
        {
            // disable expanding
            LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) pnmh;
            if (pnmtv->action == TVE_EXPAND)
            {
                bHandled = TRUE;
                return 1;
            }
            return 0;
        }
    

    And do not forget to put header file with macroses into stdafx.h.

    I suspect that I missed a lot of important stuff in this implementation but for my needs it works. If you feel that you can improve it just do it or let me know how to do it.