Pass the address of a message map for use in SetWindowLong!

Ah hello.

This is a related question to the one at http:Q_24437902.html.  I have a helper class whose job is to handle certain messages from a certain CWnd.  I do this by setting a new WNDPROC via SetWindowLong (not shown).  See code below:

// .h
class CMyHelper
{
public:
      // Handler for the WM_NCPAINT message
      virtual LRESULT OnNcPaintHandler ( HRGN hUpdateRgn );
      // ...
protected:
      // Window whose WNDPROC we are replacing
      CWnd* m_pWnd;
      // Replacement WNDPROC
      static LRESULT CALLBACK CustomWndProc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM );      
}

//.cpp
/*static*/ LRESULT CALLBACK CMyHelper::CustomWndProc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
      CMyHelper* pHelper = ( CMyHelper*) GetProp ( hwnd, _T("HELPER") );
      switch ( msg )
      {
            // ...
      case WM_NCPAINT:
            {
                  // Call handler for WM_NCPAINT
                  pHelper->OnNcPaintHandler ( ( HRGN ) wParam )
            }
      }
      // ...
}

However, at the related question, ZOPPO has suggested that I derive CMyHelper from CWnd: that way, I can access the base class handler functions of the CWnd* that is passed in.

This has triggered a new thought: if I inherit from CWnd, I can have a message map.  This would do away with the messy switch statement in CustomWndProc (above).  The thing is, if I have

BEGIN_MESSAGE_MAP(Cwnd, CCmdTarget)
ON_WM_NCPAINT()
END_MESSAGE_MAP()

I cannot see how to wire up m_pWnd in CHelper to make use of this message map, instead of the message map it currently has.  If I could, I could just have dummy one-liners handling the functions that forward the call onto the appropriate virtual function within CMyHelper: in the case of WM_NCPAINT, it would be OnNCPaintHandler.

Is what I am after possible?

TIA
LVL 19
mrwad99Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

itsmeandnobodyelseCommented:
>>>> that I derive CMyHelper from CWnd: that way, I can access the base class handler functions of the CWnd* that is passed in.
You also can call CWnd functions if CHelper has a CWnd pointer member or a hwnd where you can get a CWnd pointer by calling CWnd::FromHandle(hwnd).

>>>> how to wire up m_pWnd in CHelper to make use of this message map, instead of the message map it currently has.

The BEGIN_MESSAGE_MAP defines a function YourClass::_GetBaseMessageMap() which is a static function declared by one of the DYNAMIC macros in the class header. As a static function it easily could be stored in the windows proc and called that way. The base class mechanism is made by using the arguments given with the BEGIN_MESSAGE_MAP.

------------------------------

#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
      const AFX_MSGMAP* PASCAL theClass::_GetBaseMessageMap() \
            { return &baseClass::messageMap; } \
      const AFX_MSGMAP* theClass::GetMessageMap() const \
            { return &theClass::messageMap; } \
      AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \
      { &theClass::_GetBaseMessageMap, &theClass::_messageEntries[0] }; \
      AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \
      { \

----------


If CMyHelper *knows* the name of CMyClass it easily could call the static member function :GetBaseMessageMap. If it doesn't know you would need to *register* the function pointer in a member (or container) of CMyHelper at construction time.
0
mrwad99Author Commented:
Thanks.  So you are saying that I would still call

SetWindowLong (), passing CMyHelper::CustomWndProc(), but then  in the body of that function, instead of my switch statement, just call the address of the message map somehow?

/*static*/ LRESULT CALLBACK CMyHelper::CustomWndProc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
   // How do I call the message map here?
}

TIA
0
itsmeandnobodyelseCommented:
>>>> // How do I call the message map here?

I would try

  const AFX_MSGMAP* pmsgMap =  YourClass::_GetBaseMessageMap();

Then you get a pointer to the message map array  defined in your class where each entry has a message code and a function pointer to the non-static member function defined in the ON_ macros.

I don't know whether it makes much sense to copy the functionality of the MFC message map mechanism. I think it is easier to register an object (base class pointer) of your (window) class with your helper and and then virtually call any function you like. The MFC mechanism is born as a means to customize derived classes with a polymorphic approach which is nearly as mighty as the C++ virtual concept with the additional advantage to not having to change the base class itself, i. e. to add new virtual functions to the baseclass. The caveats are ugly casts on function pointers hidden in macros and not using multi-inheritance (because of the casts).
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Introduction to Web Design

Develop a strong foundation and understanding of web design by learning HTML, CSS, and additional tools to help you develop your own website.

mrwad99Author Commented:
Thanks again.

On hindsight: yes; the MESSAGE_MAP approach is not the best I now feel.  I will stick to my original idea of a switch statement inside the classic WNDPROC.

Closing this soon...
0
mrwad99Author Commented:
Thank you :o)
0
mrwad99Author Commented:
I agree; using the message map is not the best way therefore the WNDPROC/switch statement is the way to go.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.