We help IT Professionals succeed at work.

PreSubclassWindow

tser
tser asked
on
Medium Priority
1,494 Views
Last Modified: 2013-11-20
Realize that we override this function to do the initialization regardless
the window is Created or Subclassed after creation.

However, I found that the following code works only when dealing with
dialog controls (DDX_...).

void CMyCombo::PreSubclassWindow()
  {
    // TODO: Add your specialized code here and/or call the base class
      
    CComboBox::PreSubclassWindow();

    AddString("Default Entry");
  }

It will crash at "AddString"

pCombo = new CMyCombo;
pCombo->Create(....);

Seems like I cannot do a SendMessage to the window inside the
PreSubclassWindow function.

Any Idea ?

Comment
Watch Question

Commented:
hi,

maybe only the c++ object is created and the windows window is not created when the call to addstring is called.


Commented:
can you post these two things:

code for CMyCombo::CMyCombo()
code for CMyCombo::Create() // if it exists
code for CMyCombo::OnCreate() // if it exists

tracing through the MFC source, I don't see how/where PreSubclassWindow is getting called at all (since this isn't in a dialog box).


Author

Commented:
Regarding hariki,
The window should be created already. The m_hWnd of the base class is valid. Also, if the window is not created, it should have failed the MFC assertion in AddString instead of crash.
I suspect something to do with the WndProc of the window being not ready.

Regarding anichini,
The constructor is empty, no Create() and no OnCreate. PreSubclassWindow is not called directly by Create or OnCreate. Its called by one of the Afx hooks .
Commented:
This is my theory:
If you look at the WH_CBT windows hook that MFC uses to hook window creation, you see that it is called before WM_CREATE or WM_NCCREATE. I assume that the default windows combo box class handles WM_CREATE to set up its internal data structures. Herein lies the problem, though, because when you call AddString it sends a message before the combo box has initialized.

The code is no problem in a dialog tho, because by the time subclassing occurs the combo box has already been created (and WM_CREATE has been sent).

Here is my proposed solution:

1) add a BOOL member variable to CMyCombo called m_fInDialog
2) in the constructor, initialize m_fInDialog to TRUE
3) override Create, and set m_fInDialog to FALSE before defering to the base class's create.
4) in PreSubclassWindow, do something like this:
void CMyCombo::PreSubclassWindow()
{
    CComboBox::PreSubclassWindow();

    if(m_fInDialog)
    {
        Initialize();
    }
}

5) handle the WM_CREATE message. In the handler, do this:

void CMyCombo::OnCreate(LPCREATESTRUCT pcs)
{
   CComboBox::OnCreate(pcs); // or whatever the base class is
   if(!m_fInDialog)
   {
       Initialize();
   }
}

6) write a Initialize() routine like this:

void CMyCombo::Initialize()
{
    AddString("Default Entry");
}

This should handle both cases adequately.
 

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts

Author

Commented:
Thanks for your answer. Quite detail.
Couple comments here:

1. Where (filename & line #) can I see WH_CBT called before WM_CREATE ?

2. Doubtful on the fact that WH_CBT called before the window is actually ready. It makes the hook useless.

3. The solution is complete but it defeats the idea of using PreSubclassWindow to handle both cases. Well, if your explanation is correct, there aren't too many choices. But it also mean that PreSubclassWindow is pretty useless.

Commented:
1) WINCORE.CPP:583, AfxHookWindowCreate (in VC++ 5.0, other versions might be a different line number) - this sets up the hook.
   AfxHookWindowCreate is called from CWnd::CreateEx(WINCORE.CPP:662), which is eventually called from all Create() statements.

The hook itself is at WINCORE.CPP:474. You can see that the only code it handles for WH_CBT is HCBT_CREATEWND.

2) From the windows SDK: (documentation of CBTProc, the procedure that handles WH_CBT)

"HCBT_CREATEWND: A window is about to be created. The system calls the hook procedure before sending the WM_CREATE or WM_NCCREATE message to the window. If the hook procedure returns a nonzero value, the system destroys the window; the CreateWindow function returns NULL, but the WM_DESTROY message is not sent to the window. If the hook procedure returns zero, the window is created normally.
 At the time of the HCBT_CREATEWND notification, the window has been created, but its final size and position may not have been determined and its parent window may not have been established. It is possible to send messages to the newly created window, although it has not yet received WM_NCCREATE or WM_CREATE messages..."

3) Well, pretty much yeah. Blame the designers of MFC.


Commented:
You know, I just had another thought:

If you really are intent on having everything be in PreSubclassWindow, you could use CWnd::PostMessage to send the CB_ADDSTRING to the combo box. This would cause the list box to recieve the message after it receives WM_CREATE. But this is a pain because you'd have to be sure that the pointer to the string is valid until the message is received. Sending a string constant should work fine (since it's in the program's code and won't go anywhere), but I think my original solution is still the best.

Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.