?
Solved

Handling WM_NCPAINT message in a none CWnd derived class!

Posted on 2009-05-10
13
Medium Priority
?
787 Views
Last Modified: 2013-12-03
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.
0
Comment
Question by:mrwad99
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 5
13 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 24348843
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
 
LVL 19

Author Comment

by:mrwad99
ID: 24349102
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
 
LVL 86

Expert Comment

by:jkr
ID: 24349160
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
Get free NFR key for Veeam Availability Suite 9.5

Veeam is happy to provide a free NFR license (1 year, 2 sockets) to all certified IT Pros. The license allows for the non-production use of Veeam Availability Suite v9.5 in your home lab, without any feature limitations. It works for both VMware and Hyper-V environments

 
LVL 19

Author Comment

by:mrwad99
ID: 24349181
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
 
LVL 86

Expert Comment

by:jkr
ID: 24349210
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
 
LVL 86

Expert Comment

by:jkr
ID: 24349213
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
 
LVL 19

Author Comment

by:mrwad99
ID: 24349330
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
 
LVL 86

Expert Comment

by:jkr
ID: 24349435
>>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
 
LVL 86

Expert Comment

by:jkr
ID: 24349448
Er, forget the last comment - if there is no window associated with the class, you won't receive messages anyway...
0
 
LVL 19

Author Comment

by:mrwad99
ID: 24349472
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
 
LVL 86

Accepted Solution

by:
jkr earned 2000 total points
ID: 24349529
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
 
LVL 19

Author Comment

by:mrwad99
ID: 24349588
Thank you.  If I have any problems with the hooking, expect another question from me :)
0
 
LVL 86

Expert Comment

by:jkr
ID: 24349604
Thsnx. No problem ;o)
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question