Handling WM_NCPAINT message in a none CWnd derived class!

Ah hello.

I need to specially handle painting messages, in particular WM_NCPAINT, in my frame windows/dialogs.  For this reason, I am trying to use a special class that handles just these messages:

// .h
class CPaintHandler : public CCmdTarget
{
      DECLARE_DYNAMIC(CPaintHandler)

public:
      CPaintHandler( CWnd* pwndTarget);
      virtual ~CPaintHandler();
      virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo);
protected:
      DECLARE_MESSAGE_MAP()
      CWnd* m_pwndTarget;
};

// .cpp
BOOL CPaintHandler::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
      switch ( nID )
      {
      case WM_NCPAINT:
            {
                  ASSERT ( FALSE );
                  return 1;
            }
      }

      return FALSE;
}

// Dialog app calling code:
// Assume m_pPaintHandler is a CPaintHandler, constructed with "this" via DialogAppDlg::OnInitDialog().

BOOL DialogAppDlg::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
      BOOL bRet = m_pPaintHandler ? m_pPaintHandler->OnCmdMsg ( nID, nCode, pExtra, pHandlerInfo ) : FALSE;
      if ( !bRet )
            bRet = CDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

      return bRet;

}
As you can see, I have added a dummy handler into my CPaintHandler class for the WM_NCPAINT message.  However, this is never getting called.  

Now, I looked into OnCmdMsg, and found that it only deals with the handling of command user-interface objects.  This is hence probably why I am not getting CPaintHandler::OnCmdMsg() called.

I cannot see another way around this however.

Can anyone suggest a fix please?

Thanks in advance.
LVL 19
mrwad99Asked:
Who is Participating?
 
jkrConnect With a Mentor Commented:
Hm, I guess hooking your windows is even better hre - you can just handle the messages you need, get the measurements from the handle passed in etc. And it should be less overhead.
0
 
jkrCommented:
That dummy handler is probably never called because you don't seem to have a message map entry for it. BTE, if you want to handle messages in MFC classes, I'd rather derive from CWnd than from CCmdTarget - the latter is the base class for CWnd anyway, see the MFC hierarchy chart.
0
 
mrwad99Author Commented:
Yeah, I tried adding the handler but it would not let me:

BEGIN_MESSAGE_MAP(CPaintHandler, CCmdTarget)
      ON_WM_NCPAINT()
END_MESSAGE_MAP()

/*afx_msg*/ void CPaintHandler::OnNcPaint()
{
}

Gives me:

'static_cast' : cannot convert from 'void (__thiscall CPaintHandler::* )(void)' to 'void (__thiscall CWnd::* )(void)'

>> BTE, if you want to handle messages in MFC classes...

I thought of that, but I want to have one class that is responsible for handling the paint messages in windows *and* dialogs.  If I derive from CWnd:

CPaintHandler : public CWnd {};

CMyWnd : public CPaintHandler {};

CMyDialog : public CDialog, public CMyWnd {};

I cannot do the above as I would need to use virtual inheritance, but I would have to put the virtual keyword at the CWnd level, which would mean modifying the MFC code.  Hence I chose to use CCommandTarget...But it also seems I will have this problem anyway since CWnd is derived from CCommandTarget....arghhhhhhhhh!

Any ideas on how to get around this?

(The end result is that I want to have one class responsible for handling all painting related messages in the window that it is created within.  The message handlers can then call virtual functions, which derived classes can then override as suitable.)

Would a hook, hooking all messages, be suitable do you think?

TIA
0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
jkrCommented:
Have you tried adding the message handler likke the following?
BEGIN_MESSAGE_MAP(CPaintHandler, CCmdTarget)
      ON_MESSAGE( WM_NCPAINT,OnNcPaint)
END_MESSAGE_MAP()
 
LRESULT CPaintHandler::OnNcPaint(WPARAM, LPARAM)
{
  return 0;
}

Open in new window

0
 
mrwad99Author Commented:
OOO, had a glimmer of hope that that was the answer, but no:

'static_cast' : cannot convert from 'LRESULT (__thiscall CPaintHandler::* )(WPARAM,LPARAM)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'

?
0
 
jkrCommented:
OK, let's try to be brutal:
BEGIN_MESSAGE_MAP(CPaintHandler, CCmdTarget)
{ WM_NCPAINT, 0, 0, 0, AfxSig_lwl, \
  (AFX_PMSG)(AFX_PMSGW) \
  (static_cast< LRESULT (AFX_MSG_CALL CPaintHandler::*)(WPARAM, LPARAM)>\
   (OnNcPaint)) },
END_MESSAGE_MAP()

Open in new window

0
 
jkrCommented:
Or, maybe better:
BEGIN_MESSAGE_MAP(CPaintHandler, CCmdTarget)
{ WM_NCPAINT, 0, 0, 0, AfxSig_lwl,(AFX_PMSG)(AFX_PMSGW)(static_cast< LRESULT (AFX_MSG_CALL CPaintHandler::*)(WPARAM, LPARAM)>(OnNcPaint)) },
END_MESSAGE_MAP()

Open in new window

0
 
mrwad99Author Commented:
Heh, we are getting somewhere: that now compiles at last, so thanks.

Now.  The problem is that the handler is not getting called.  In fact, I added a breakpoint on DialogAppDlg::OnCmdMsg(), with the condition that nID was 0x85 (WM_NCPAINT).  The breakpoint never gets hit, so my CPaintHandler never gets called.  Now, I looked into OnCmdMsg, and found that it only deals with the handling of command user-interface objects.  WM_NCPAINT is not a command user-interface related message, so I guess that is why it is not being called.

Hmm...

I thought about WindowProc, that would do it, but then my CPaintHandler can't have a WindowProc because it is not a window!

Stuck.

Any ideas?

0
 
jkrCommented:
>>The problem is that the handler is not getting called.

I was more afraid that there might be a crash ;o)

Could you try to add a 'TRACE()' to 'OnNcPaint()' and check the debug output? If that does not work also, a local hook really might be the way to go...
0
 
jkrCommented:
Er, forget the last comment - if there is no window associated with the class, you won't receive messages anyway...
0
 
mrwad99Author Commented:
OK.  I might have to look into that then.  

A quick overview of what I would like to achieve:

I want all windows in my app to follow a "theme".  I have the functionality for painting various areas of windows all ready to go, but I don't want to have to keep duplicating the same code over and over for dialogs and frame windows etc.  I want it all in one place.

My first thought was to have "CThemedWnd", derived from CWnd.  I could derive dialogs and frames from that, but wait: the virtual inheritance problem I mentioned above.

(CThemedDlg : public CThemedWnd, public CDialog gives us two CWnds: the virtual keyword would need to go at the CWnd level, which I can't do as it is not my source code).

So I thought "put the functionality for  theming in a helper object.  It can handle the painting messages etc.  Each window to be themed could have one of these objects in each window to be themed, virtual functions could be exploited etc etc: lovely.

But then the problems I encountered as above.

Having (hopefully :) ) read that, is there any other way to do this other than hooking my "window to be themed" for messages, handling those I am interested in that way (if that is possible - is it?)

TIA
0
 
mrwad99Author Commented:
Thank you.  If I have any problems with the hooking, expect another question from me :)
0
 
jkrCommented:
Thsnx. No problem ;o)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.