4

When a standard window control (e.g. an "EDIT" control) is created, its WNDPROC is defined as part of the window class (i.e. "EDIT" has a specific WNDPROC that is designed to make the window display & behave as an edit-control).

MFC allows you to interact with such controls via their wrapper classes, such as a CEdit wrappers the specialized messages for an "EDIT" window control.

MFC further allows you to bind an instance of an "EDIT" window to a C++ subclass of CEdit, say a CMyEdit, where you can override inherited virtual functions of CEdit and CWnd, and you can define a message table to gain access / override messages sent to the window instance itself.

There is CWnd::Default(), which calls this->DefWndProc with the current message arguments. This appears to lookup the WNDPROC for the HWND it is associated with. So is this the correct answer: call DefWndProc() (or equally, Default()), which will hand it off to the WNDPROC of the windows control?

Obviously, this is different than other message table handlers which can return FALSE to indicate that they didn't handle the message, and MFC will automatically route the message up the class inheritance hierarchy to the next message handler for this message, or, I assume, to Default() to be handled by the native WNDPROC?

If I define an arbitrary message handler, say for WM_SETTEXT, what is the correct way to pass this message on to the "EDIT" WNDPROC?

I'd also love to know if there is a way to pass the message up to a superclass (C++ class hierarchy) for handling? Many OnXXX style handlers do have a way to do so, but is there a mechanism that works for ON_MESSAGE handlers?

class CDynamicMenuControlEdit : public CEdit  
{
    ...
    LRESULT OnSetText(WPARAM wParam, LPARAM lParam);
    ...
}

BEGIN_MESSAGE_MAP(CDynamicMenuControlEdit, CEdit)
    ...
    ON_MESSAGE(WM_SETTEXT, OnSetText)
    ...
END_MESSAGE_MAP()

LRESULT CDynamicMenuControlEdit::OnSetText(
    WPARAM wParam,          // not used; must be zero
    LPARAM lParam           // window-text string (LPCTSTR)
)
{
    if (m_bHasFocus)
    {
        // do normal thing 
        // !!! THIS IS MY QUESTION: IS THIS CALLING EDIT's WNDPROC, or ::DefWinProc()? !!!
        return DefWindowProc(WM_SETTEXT, wParam, lParam);
    }
    ...
}

Clarification

You can have multiple MFC subclasses at the C++ level -

so C inherits B inherits A, where A is an MFC class (e.g. CEdit).

Each of those can have an MFC message table - i.e. BEGIN_MESSAGE_MAP ... END_MESSAGE_MAP which can each have a handler for any arbitrary windows message, such as WM_MESSAGE(WM_SETTEXT, OnSetText) - and that OnSetText member is not necessarily virtual - just a static member (each MFC subclass can route that message in any arbitrary way).

My question is - since a WM_MESSAGE dispatch entry doesn't have a return value, how do I allow MFC to walk up the MFC dispatch tables from C to B to A before handing back to the real windows 'EDIT' class's wndproc?

Or are all such entries intended at the MFC design-level NOT to be walked? i.e. the most subclassed layer's dispatcher is intended to be the only one called? And if it wants to leverage an inherited member it has to manually make that call - MFC simply doesn't have any specific generic structure for this?

Mordachai
  • 9,412
  • 6
  • 60
  • 112

2 Answers2

4

Calling Default() will cause the "normal" processing that would have happened in response to a message to occur. I'm not entirely clear on what you are trying to achieve, but it seems to me that calling Default() is what you want to do.

If you look at a lot of the handlers from Windows messages in the CWnd handlers (and handlers from classes derived from CWnd such as CEdit) you will see that they call Default().

Word to the wise, that Default() will actually use whatever parameters the original message had - you cannot change them.

Nik Bougalis
  • 10,495
  • 1
  • 21
  • 37
  • At an abstract/general level, yes Default() will do the "normal" thing. It sounds like that means that the WNDPROC that MFC hooked will be called, as opposed to ::DefWindowProc being called (we want window class "EDIT"'s WNDPROC to be called, not the global generic default window proc!) However, I'd like confirmation on that, and clarification on what would be the right way to cause the next message handler in the MFC message table chain to be called if my ON_MESSAGE handler wants to punt? – Mordachai Mar 06 '13 at 18:31
2

You're doing it right. CWnd::DefWindowProc() uses the WINDOWPROC you subclassed from and will call the EDIT window's window procedure.

Joseph Willcoxson
  • 5,853
  • 1
  • 15
  • 29
  • How would it be different in *this particular instance* for him to call `Default()`? – Nik Bougalis Mar 06 '13 at 17:25
  • Looking at wincore.cpp, Default and DefWindowProc() are identical in my example, because I pass the same args to DefWindowProc() as Default() would, and default calls DefWindowProc() so exactly the same results. – Mordachai Mar 06 '13 at 18:28
  • I'm more confused about the distinction between ON_MESSAGE being a message sink vs. other ON_WM_xxx which have a BOOL result to indicate if your handler handled the message or if it should propagate up the message table chain. Or how one would even accomplish that for my example (i.e. if my subclass wants to punt up the message handler chain- how?). And verify that my example calls the WNDPROC that was there prior to MFC's WNDPROC subclassing (hooking). – Mordachai Mar 06 '13 at 18:28
  • I'm not sure if I understand your question. In a thread, you can only subclass a window via MFC once. So when a message comes in to a subclassed window, it tries to find a MFC message handler. If it finds one, it calls it. If it doesn't find one, it calls the default window procedure from which MFC had subclassed from. Generally, if you want to punt up the MFC chain, you call the baseclass directly--CSomeBaseClass::OnSetText(wParam, lParam). – Joseph Willcoxson Mar 07 '13 at 15:32
  • You can have multiple MFC subclasses at the C++ level - so C inherits B inherits A, where A is an MFC class (e.g. `CEdit`). Each of those can have an MFC message table - i.e. `BEGIN_MESSAGE_MAP` ... `END_MESSAGE_MAP` which can each have a handler for `WM_MESSAGE(WM_SETTEXT)` - and my question is - since `WM_MESSAGE` doesn't have a return value, how do I allow MFC to walk up the MFC dispatch tables from C to B to A before handing back to 'EDIT' window class's wndproc? – Mordachai Jan 30 '18 at 17:40