Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Handling WM_NCPAINT message in a none CWnd derived class!

Posted on 2009-05-10
13
Medium Priority
?
813 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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
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

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 …
Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
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…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

580 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