Solved

Handling WM_NCPAINT message in a none CWnd derived class!

Posted on 2009-05-10
13
773 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
  • 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
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

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.

 
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 500 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

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

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.

Question has a verified solution.

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

Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

861 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