Tuesday, April 15, 2008

FCUK!!!

Talk about unclean. Let's say you're working with a dialog object, in this case subclassed from CDialog like so

CBitmapDlg : public CDialog{
// some stuff
};

You instantiate it somewhere like this:

CBitmapDlg dlg(this);

Now, just for kicks let's take a look at the default constructor. It goes something like this:

CBitmapDlg::CBitmapDlg(CWnd* pParent /*=NULL*/)
: CDialog(CBitmapDlg::IDD, pParent)
{

}

Hmmm.... it looks like the parameter being passed to the constructor is a pointer to the parent window (or NULL if the parameter is omitted). Very good. That might come in handy, but just to make sure what exactly does the CDialog constructor do with this parameter? Well, it does this:

CDialog::CDialog(UINT nIDTemplate, CWnd* pParentWnd)
{
// extra code omitted for clarity
m_pParentWnd = pParentWnd;
}


Wow, the CDialog constructor stores the pointer in a member variable called m_pParentWnd. It looks to me like that's supposed to be a pointer to the parent window. Good. So you instantiate your object inside of another window (of whatever type your heart desires) like this:

CBitmapDlg dlg(this);

You pass the this pointer, as you want your window to be the parent of the dialog. So far, everything is great. Then you do something silly like this inside your CBitmapDlg class

CBitmapDlg::SomeFunc()
{
CWnd *pParent = GetParent();
// I want to do something to my parent window, in this case send a message
pParent ->SendMessage(WM_SOMEMESSAGE, (WPARAM) 0, (LPARAM) 0);

}

You try to send your parent window a message, but it just isn't getting it. I mean, what the fuck? Where's the message going? So you fire up the debugger, take a look at what's going on, and discover this:

GetParent() does NOT return a pointer to the parent window specified during object creation. WHAT??? I mean, you've used GetParent() many times with no problems, what gives? Apparently, with dialogs, somebody decided to do something screwy. With regular windows GetParent() seems to actually return a pointer to the parent window, but with dialogs it decides to return a pointer to the main window. According to the documentation, it will do this if you pass NULL for the parent window. But you didn't pass NULL, did you? You gave it a valid pointer, and still it returns a pointer to the main window. What does all of this lead to? It leads to this absurdity:

CBitmapDlg::SomeFunc()
{
CWnd *pParent = GetParent(); // get your pointer using GetParent()

CWnd* pParentX = CDialog::m_pParentWnd // access member variable directly

// pParent != pParentX


}

You see, the member variable m_pParentWnd, which we supposed stored a pointer to the parent window, does indeed store a pointer to the parent window. But this is not the same pointer returned by a call to GetParent(). WHAT THE FUCK??? FUCK YOU WHOEVER DID THIS! FUCK YOU!

Hopefully all of you can learn from this and not have to find it out the hard way. Which I did. Which I'm pissed about.

3 comments:

cyrusfx said...

I passed NULL. He was going really slow and waved me around.

marchhare14 said...

I understood none of that.

Huge Larry said...

Matt... please post your source code for the cross-process critical section.

If you do that I'll give you my CBitmapButtonNoDblClk class, which is just like CBitmapButton except that quick double clicks are registered as two single clicks.