2

An application I'm porting from Visual C++ 6.0 to the MFC version in VC++2008, does a lot of get-AfxGetMainWnd()-and-do-C-Style-casts on it like this:

  CUserInterfaceDoc *m_pDoc = (CUserInterfaceDoc*)((CFrameWnd *)AfxGetMainWnd())
                            ->GetActiveDocument();

When I try the steps above, simply converting to dynamic_cast<>, I find that the Main Window is no longer accessible via casting-to-a-CUserInterfaceDoc in my program. I think that perhaps MFC had abused casts in VC++ 6, or that the compiler did some magic.

Rewriting the above to use dynamic casts would go like this, and it ends up with a nil pointer, which trips the assert() conditions I wrote here, as I want it to:

CUserInterfaceDoc *m_pDoc;
CWnd * mainWnd = AfxGetMainWnd();
assert(mainWnd);
CFrameWnd *frmWnd = dynamic_cast<CFrameWnd *> (mainWnd);
assert(frmWnd);
m_pDoc = dynamic_cast<CUserInterfaceDoc *> (frmWnd);
assert(m_pDoc);

I'm assuming that everybody who has done this before will be able to say "Yeah, of course, they changed that casting behaviour...." but I can't find the documentation for it.

Where possible I'm changing my C++ classes to have a member variable (field) where I store
links to things that it was formerly finding by walking down from the "more or less global" AfxMainWnd().

It would help me to know what changed though, so I can understand what's going on above.

CUserInterfaceDoc is my application's MFC C++ Document class, it is a COleServerDoc which used to be "findable" at runtime with the gross C-style cast at the top.

The above cast still compiles in modern C++ but it's broken, probably due to the fact that the old VC++ 6 compiler did some kind of internal 'magic' with C-style casts that was against the ISO C++ standards. (That's purely a guess on my part).

My question is in two parts:

  1. What's the usual way to get at the CurrentDocument (CFrameWnd::CurrentDocument) from another class that currently has no reference to the main CFrameWnd and had been using the hack I show at the top of this question?

  2. What changed between the non-ISO-compliant VC++ 6 and the more-or-less ISO-compliant later C++ versions that would change the behaviour of the cast expressions above, or did the breakage occur due to MFC internal architecture changes?

My code change:

CUserInterfaceDoc * CMyBrowser::GetUserInterfaceDoc()
{
    CUserInterfaceDoc *m_pDoc;
    // formerly did this, which works in VC++6 and doesn't work anymore:
    //m_pDoc = (CUserInterfaceDoc*)((CFrameWnd *)AfxGetMainWnd())->GetActiveDocument();
    assert(m_pMainFrm);
    m_pDoc = dynamic_cast<CUserInterfaceDoc *> ( m_pMainFrm->GetActiveDocument() );
    assert(m_pDoc);
}
Warren P
  • 65,725
  • 40
  • 181
  • 316

2 Answers2

4

If you are using MFC, you might as well just bite the bullet and use DYNAMIC_DOWNCAST which is an MFC defined macro for casting that's basically equivalent to dynamic_cast.

CFrameWnd* pFrm = DYNAMIC_DOWNCAST(CFrameWnd, AfxGetApp()->m_pMainWnd);

m_pDoc = DYNAMIC_CAST(CUserInterfaceDoc, m_pMainFrm->GetActiveDocument());
Joseph Willcoxson
  • 5,853
  • 1
  • 15
  • 29
1

In your first rewrite:

CUserInterfaceDoc *m_pDoc;
CWnd * mainWnd = AfxGetMainWnd();
assert(mainWnd);
CFrameWnd *frmWnd = dynamic_cast<CFrameWnd *> (mainWnd);
assert(frmWnd);
m_pDoc = dynamic_cast<CUserInterfaceDoc *> (frmWnd);
assert(m_pDoc);

... you simply missed the GetActiveDocument() call which was there in the C-Style cast. So it should work like this:

CUserInterfaceDoc *m_pDoc;
CWnd * mainWnd = AfxGetMainWnd();
assert(mainWnd);
CFrameWnd *frmWnd = dynamic_cast<CFrameWnd *> (mainWnd);
assert(frmWnd);    
m_pDoc = dynamic_cast<CUserInterfaceDoc *> (frmWnd->GetActiveDocument());
assert(m_pDoc);

DYNAMIC_DOWNCAST is soo oldschool and actually no longer required if you enable RTTI (which is on by default). See also: MFC DYNAMIC_DOWNCAST vs. dynamic_cast

Community
  • 1
  • 1
zett42
  • 25,437
  • 3
  • 35
  • 72
  • Accepted this answer as the one from 2012 does seem pretty dated, and others may come along and find this better advice. – Warren P Feb 17 '17 at 20:49