How to subclass an MFC window?

Is there any easy way of overriding the responses to some messages to a 
CWnd-derived object buried deep within MFC?

One reason for the question is:

In the old days CMainFrame was derived from CMDIFrameWnd and this had a 
member

HWND m_hWndMDIClient;

To draw the background of this window I used to do a

SubclassWindow( )

on it, and with my own CWnd-derived object, respond to WM_ERASEBKGND 
messages.

Nowadays CMainFrame is derived from CMDIFrameWndEx and this has a member

CMDIClientAreaWnd m_wndClientArea;

and (I think) because a CWnd object already exists for the MDI client area, 
then SubclassWindow() doesn't work on it.

A second reason is that CMFCToolBar etc come with a customisation property 
sheet, and I am considering what I might do to override one of its property 
pages.

[I used to think that I knew MFC quite well - but all these new classes have 
thrown me somewhat!]

Dave
-- 
David Webber
Mozart Music Software
http://www.mozart.co.uk
For discussion and support see
http://www.mozart.co.uk/mozartists/mailinglist.htm



 

0
David
6/25/2010 3:14:02 PM
vc.mfc 33608 articles. 0 followers. Follow

9 Replies
8674 Views

Similar Articles

[PageSpeed] 29

>Nowadays CMainFrame is derived from CMDIFrameWndEx and this has a member
>
>CMDIClientAreaWnd m_wndClientArea;
>
>and (I think) because a CWnd object already exists for the MDI client area, 
>then SubclassWindow() doesn't work on it.

I wonder if you can handle the message some other way - perhaps in the
application's PreTranslateMessage handler?

Dave
0
David
6/25/2010 3:54:23 PM

"David Lowndes" <DavidL@example.invalid> wrote in message 
news:44k926hsb0voea68aeerl1r2vdq21i9btc@4ax.com...

>>Nowadays CMainFrame is derived from CMDIFrameWndEx and this has a member
>>
>>CMDIClientAreaWnd m_wndClientArea;
>>
>>and (I think) because a CWnd object already exists for the MDI client 
>>area,
>>then SubclassWindow() doesn't work on it.
>
> I wonder if you can handle the message some other way - perhaps in the
> application's PreTranslateMessage handler?

Sounds like a plausible idea for one message for that particular window - 
thanks.

But it sounds pretty horrible for a whole property page and all its 
controls.    BUT.....

Please forgive me if I think aloud here, as something might be dawning on me 
in real time as I type.

The App Wizard has given me:

void CMainFrame::OnViewCustomize()
{
  CMFCToolBarsCustomizeDialog* pDlgCust
        = new CMFCToolBarsCustomizeDialog(this, TRUE);
  pDlgCust->EnableUserDefinedToolbars();
  pDlgCust->Create();
}

so I can derive a class from CMFCToolBarsCustomizeDialog, and use that 
instead.

This is a property sheet with a number of property pages, including

  CMFCToolBarsKeyboardPropertyPage*  m_pKeyboardPage;

which allows the user to set a new keyboard shortcut.   No whilst I can't 
easily get at the property *page*,  the property *sheet* (which I *can* 
subclass) has lots of virtual members, including

    virtual BOOL OnAssignKey( ACCEL *pAccel ) { return TRUE; }

It *looks* like this gets called with the newly selected accelerator, and I 
can do what I want with it and return FALSE to tell MFC to ignore it!

This is looking very promising!!!!!!!!

Background:
Shortcut keys like ^ > + - are very useful mnemonics for music applications. 
Equally Ctrl+> etc are very useful shortcuts.
But I want it to appear as Ctrl+> on the menu, and not Ctrl+Shift+.
And I want to define these shortcuts for all national keyboards (even if > 
isn't Shift+.)
Accelerators are not up to the job, so I rolled my own method, built into 
WM_KEYDOWN and WM_CHAR processing.  Maybe I *will* be able to integrate it 
with the new customisable toolbars!!!!
A nice thought on which to end the week (especially as I'm out all weekend 
playing on bandstands.)

Dave
-- 
David Webber
Mozart Music Software
http://www.mozart.co.uk
For discussion and support see
http://www.mozart.co.uk/mozartists/mailinglist.htm

 

0
David
6/25/2010 5:30:15 PM
This is remarkably ugly, but something like this should work...

First, have a window subclass that you want.  I'll call it CMySubclass

void CMyApp::RedrawClientArea()
   {
    CMySublcass w;
    w.Attach(m_wndClientArea.Detach());
    w->Invalidate();
    w->UpdateWindow();
    m_wndClientArea.Attach(w.Detach());
   }

Overall, this is pretty gross.  Also, I have not figured out quite where you would need to
call this, but I'd suspect this is one of the interesting uses of PreTranslateMessage,
looking for a WM_PAINT directed to the client area (in that case, the Invalidate() would
not be required)
				joe

On Fri, 25 Jun 2010 16:14:02 +0100, "David Webber" <dave@musical-dot-demon-dot-co.uk>
wrote:

>Is there any easy way of overriding the responses to some messages to a 
>CWnd-derived object buried deep within MFC?
>
>One reason for the question is:
>
>In the old days CMainFrame was derived from CMDIFrameWnd and this had a 
>member
>
>HWND m_hWndMDIClient;
>
>To draw the background of this window I used to do a
>
>SubclassWindow( )
>
>on it, and with my own CWnd-derived object, respond to WM_ERASEBKGND 
>messages.
>
>Nowadays CMainFrame is derived from CMDIFrameWndEx and this has a member
>
>CMDIClientAreaWnd m_wndClientArea;
>
>and (I think) because a CWnd object already exists for the MDI client area, 
>then SubclassWindow() doesn't work on it.
>
>A second reason is that CMFCToolBar etc come with a customisation property 
>sheet, and I am considering what I might do to override one of its property 
>pages.
>
>[I used to think that I knew MFC quite well - but all these new classes have 
>thrown me somewhat!]
>
>Dave
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Joseph
6/26/2010 9:53:55 PM
"Joseph M. Newcomery" <newcomer@flounder.com> wrote in message 
news:j2qc26pnsge8f50k0c8jatcst7ae6n93ii@4ax.com...

> This is remarkably ugly, but something like this should work...
>
> First, have a window subclass that you want.  I'll call it CMySubclass
>
> void CMyApp::RedrawClientArea()
>   {
>    CMySublcass w;
>    w.Attach(m_wndClientArea.Detach());
>    w->Invalidate();
>    w->UpdateWindow();
>    m_wndClientArea.Attach(w.Detach());
>   }
>
> Overall, this is pretty gross.  Also, I have not figured out quite where 
> you would need to
> call this, but I'd suspect this is one of the interesting uses of 
> PreTranslateMessage,
> looking for a WM_PAINT directed to the client area (in that case, the 
> Invalidate() would
> not be required)

I vaguely wondered about something like that.  When it says that 
SubclassWindow only works for an HWND with no CWnd attached, the immediate 
question is why?   The next question is - well if we remove the attached 
CWnd, what then?

If we take your suggestion one step further:  suppose I derive CMySubclass 
from the CWnd-derived class which was attached in the first place.  Then I 
could detach the original and attach mine, and leave it attached, with no 
apparent penalties.   But if it is as easy as that, why doesn't 
SublassWindow just do it?   I guess the originally attached class may itself 
have some data necessary to the correct functioning of the window?

I feel I am walking on eggshells here.

Dave
-- 
David Webber
Mozart Music Software
http://www.mozart.co.uk
For discussion and support see
http://www.mozart.co.uk/mozartists/mailinglist.htm 

0
David
6/26/2010 10:39:23 PM
See below...
On Sat, 26 Jun 2010 23:39:23 +0100, "David Webber" <dave@musical-dot-demon-dot-co.uk>
wrote:

>
>"Joseph M. Newcomery" <newcomer@flounder.com> wrote in message 
>news:j2qc26pnsge8f50k0c8jatcst7ae6n93ii@4ax.com...
>
>> This is remarkably ugly, but something like this should work...
>>
>> First, have a window subclass that you want.  I'll call it CMySubclass
>>
>> void CMyApp::RedrawClientArea()
>>   {
>>    CMySublcass w;
>>    w.Attach(m_wndClientArea.Detach());
>>    w->Invalidate();
>>    w->UpdateWindow();
>>    m_wndClientArea.Attach(w.Detach());
>>   }
>>
>> Overall, this is pretty gross.  Also, I have not figured out quite where 
>> you would need to
>> call this, but I'd suspect this is one of the interesting uses of 
>> PreTranslateMessage,
>> looking for a WM_PAINT directed to the client area (in that case, the 
>> Invalidate() would
>> not be required)
>
>I vaguely wondered about something like that.  When it says that 
>SubclassWindow only works for an HWND with no CWnd attached, the immediate 
>question is why?   The next question is - well if we remove the attached 
>CWnd, what then?
****
When an HWND is placed in a CWnd-derived class (as the m_hWnd), an entryis made in the
handle map for that thread.  If, in the future, someone delivers an HWND (say, a message
is received), the way the methods are found is to use the handle map to obtain the CWnd*
pointer; in the case of message dispatching, from the CWnd* reference, the message map is
found.  Note that in general if the lookup fails, a *temporary* CWnd* reference is
generated, which is deleted in the CWinApp::OnIdle handler.  This is why there all all the
warnings about the CWnd* reference being temporary, and that it must not be stored.

So you cannot have an HWND mapped to two different CWnd-derived objects.  Hence the ugly
detach/attach code I gave;  the Attach code creates a new mapping of an newly-unattached
HWND.

Note that when an Attach (or SubclassWindow, which ultimately does an Attach) occurs, the
handle is looked up in the handle map.  It had better return an error coden (handle not
found), otherwise, there is an ASSSERT failure that there is an attempt to create a handle
map entry for an HWND which is already mapped.
*****
>
>If we take your suggestion one step further:  suppose I derive CMySubclass 
>from the CWnd-derived class which was attached in the first place.  Then I 
>could detach the original and attach mine, and leave it attached, with no 
>apparent penalties.   But if it is as easy as that, why doesn't 
>SublassWindow just do it?   I guess the originally attached class may itself 
>have some data necessary to the correct functioning of the window?
****
Actually, there are penalties; messages directed to that window will not be handled by the
class of the m_wndClientArea.  Presumably, this will not be healthy for your app.

And, as I indicated, SubclassWindow *cannot* work correctly if the HWND is already mapped!
It is considered erroneous to let SubclassWIndow map an HWND to some other CWnd* when it
is already mapped to a CWnd*.  So the code I showed (remember, I said it was gross and
ugly) creates a *temporary* remapping only in the cases where you need it.  Otherwise, the
mapping is left at the correct class for the new framework, so it continues to work
correctly.

				joe
****
>
>I feel I am walking on eggshells here.
>
>Dave
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Joseph
6/27/2010 12:31:32 AM
A friend who wrote an analogously ugly piece of code used "ASCII Art" to draw a
skull-and-crossbones in the function header comments, and quoted the Unix kernel's
context-swap code: "You are not meant to understand this"
					joe
On Sat, 26 Jun 2010 23:39:23 +0100, "David Webber" <dave@musical-dot-demon-dot-co.uk>
wrote:

>
>"Joseph M. Newcomery" <newcomer@flounder.com> wrote in message 
>news:j2qc26pnsge8f50k0c8jatcst7ae6n93ii@4ax.com...
>
>> This is remarkably ugly, but something like this should work...
>>
>> First, have a window subclass that you want.  I'll call it CMySubclass
>>
>> void CMyApp::RedrawClientArea()
>>   {
>>    CMySublcass w;
>>    w.Attach(m_wndClientArea.Detach());
>>    w->Invalidate();
>>    w->UpdateWindow();
>>    m_wndClientArea.Attach(w.Detach());
>>   }
>>
>> Overall, this is pretty gross.  Also, I have not figured out quite where 
>> you would need to
>> call this, but I'd suspect this is one of the interesting uses of 
>> PreTranslateMessage,
>> looking for a WM_PAINT directed to the client area (in that case, the 
>> Invalidate() would
>> not be required)
>
>I vaguely wondered about something like that.  When it says that 
>SubclassWindow only works for an HWND with no CWnd attached, the immediate 
>question is why?   The next question is - well if we remove the attached 
>CWnd, what then?
>
>If we take your suggestion one step further:  suppose I derive CMySubclass 
>from the CWnd-derived class which was attached in the first place.  Then I 
>could detach the original and attach mine, and leave it attached, with no 
>apparent penalties.   But if it is as easy as that, why doesn't 
>SublassWindow just do it?   I guess the originally attached class may itself 
>have some data necessary to the correct functioning of the window?
>
>I feel I am walking on eggshells here.
>
>Dave
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
0
Joseph
6/27/2010 12:33:40 AM
"Joseph M. Newcomer" <newcomer@flounder.com> wrote in message 
news:dc6d26psjoevppsmkueotlvhiq7o78h3i5@4ax.com...

>>I vaguely wondered about something like that.  When it says that
>>SubclassWindow only works for an HWND with no CWnd attached, the immediate
>>question is why?   The next question is - well if we remove the attached
>>CWnd, what then?
> ****
>
> [Can't attach an HWND to two CWnds]....

Yes I can see this - replacing the CWnd would be the only option.

> Actually, there are penalties; messages directed to that window will not 
> be handled by the
> class of the m_wndClientArea.  Presumably, this will not be healthy for 
> your app.

But if I derived my window class from CMDIClientAreaWnd then presumably the 
only danger would be that any data members it had would be different from 
the original  CMDIClientAreaWnd m_wndClientArea.

Still maybe that's danger enough.

> And, as I indicated, SubclassWindow *cannot* work correctly if the HWND is 
> already mapped!
> It is considered erroneous to let SubclassWIndow map an HWND to some other 
> CWnd* when it
> is already mapped to a CWnd*.  So the code I showed (remember, I said it 
> was gross and
> ugly) creates a *temporary* remapping only in the cases where you need it. 
> Otherwise, the
> mapping is left at the correct class for the new framework, so it 
> continues to work
> correctly.

Yes I realise that.  I think your 'gross and ugly' is my 'walking on 
eggshells'.  :-)

Dave
-- 
David Webber
Mozart Music Software
http://www.mozart.co.uk
For discussion and support see
http://www.mozart.co.uk/mozartists/mailinglist.htm
 

0
David
6/27/2010 9:31:59 AM
On Jun 25, 5:14=A0pm, "David Webber" <d...@musical-dot-demon-dot-co.uk>
wrote:
> Is there any easy way of overriding the responses to some messages to a
> CWnd-derived object buried deep within MFC?
>
> One reason for the question is:
>
> In the old days CMainFrame was derived from CMDIFrameWnd and this had a
> member
>
> HWND m_hWndMDIClient;
>
> To draw the background of this window I used to do a
>
> SubclassWindow( )
>
> on it, and with my own CWnd-derived object, respond to WM_ERASEBKGND
> messages.

How about just putting a window of your own into m_wndClientArea and
doing your drawing in that, then?

Goran.
0
Goran
7/1/2010 11:25:12 AM

"Goran" <goran.pusic@gmail.com> wrote in message 
news:a18e04e3-fa94-40a3-a651-ba96b83817b6@k39g2000yqb.googlegroups.com...
> On Jun 25, 5:14 pm, "David Webber" <d...@musical-dot-demon-dot-co.uk>
> wrote:

>> Is there any easy way of overriding the responses to some messages to a
>> CWnd-derived object buried deep within MFC?
>>
>...
>
> How about just putting a window of your own into m_wndClientArea and
> doing your drawing in that, then?

Unfortunately the m_wndClientArea being difficult to get at, I suspect it 
would be diificult to give it children.    Surely getting at its 
WM_ERASEBKGD should be easier?   But thanks for the idea - a bit of lateral 
thought is always welcome :-)

Dave

-- 
David Webber
Mozart Music Software
http://www.mozart.co.uk
For discussion and support see
http://www.mozart.co.uk/mozartists/mailinglist.htm 

0
David
7/1/2010 5:55:23 PM
Reply:

Similar Artilces: