tags:

views:

141

answers:

1

When creating a window class for use with a DialogBox you need to add DLGWINDOWEXTRA to cbWndExtra. If you add extra data space to a DialogBox class be accessed by GetWindowLongPtr, should you add DLGWINDOWEXTRA to access this extra space?

(I'll confess that I think I know the answer, and that way the code doesn't break. But, I want to make sure my reasons tally with the collective wisdom.)

The major reason why Dialogs are being used with their own class (rather than the default) is to allow each class of Dialog to have its own Icon. Two separate items of extra data are also attached to each window.

...  
wndclass.cbWndExtra  = DLGWINDOWEXTRA+EXTRASPACE;
wndclass.lpfnWndProc = (WNDPROC) DefDlgProc;
wndclass.hIcon = LoadIcon(hInstance, "ICON_MAIN");
wndclass.lpszClassName = WND_CLASS_VLIST_POPUP;
wndclass.hIconSm = LoadImage(hInstance,
                                 "ICON_MAIN",
                                 IMAGE_ICON,
                                 16,
                                 16,
                                 LR_DEFAULTCOLOR);
...

Late edit (removed the incorrect GWLP_USERDATA and replaced with 0 ):

Effectivly the question is:

GetWindowLongPtr(hWnd, 0 + DLGWINDOWEXTRA + SOMETHING_IN_EXTRASPACE);

or

GetWindowLongPtr(hWnd, 0 + SOMETHING_IN_EXTRASPACE);

?

+1  A: 

Actually... I think you're making a mistake. The value at GWLP_USERDATA and the space allocated according to cbWndExtra are two separate things...

The GWLP_USERDATA value is part of the space Windows allocates for every window. It's so common for window classes to need a pointer-sized bit of storage that Windows just includes it in the base cost of a window, along with all of the other pre-defined "window words". Look at the documentation for the nIndex parameter to GetWindowLongPtr():

Specifies the zero-based offset to the value to be retrieved. Valid values are in the range zero through the number of bytes of extra window memory, minus the size of an integer.

So, GetWindowLongPtr(hWnd, 0) retrieves the first sizeof(LONG_PTR) bytes allocated in response to cbWndExtra, GetWindowLongPtr(hWnd, sizeof(LONG_PTR)) gives you the next pointer-sized data, and so on. As its name implies, nIndex acts like an index into an array of bytes (though it always returns a pointer-sized value). Now take a look at the index values assigned to the pre-defined window data constants: they're all negative, including GWLP_USERDATA! In effect, GetWindowLongPtr() starts indexing into the middle of the window data, with the data common to all windows residing "before" the 0 index, and any window class specific data residing after it.

Dialog windows are built on top of the baseline support provided for normal windows. Since they require more data than normal windows, you're required to specify at least DLGWINDOWEXTRA bytes in cbWndExtra. Like any other such data, it's accessed via a positive value passed to GetWindowLongPtr().

Therefore, when you ask for

GetWindowLongPtr(hWnd, GWLP_USERDATA + DLGWINDOWEXTRA + 0);

...you're actually getting the data at index -21 + 30 + 0 = 9: a value somewhere in the dialog manager's own data. Not what you want!

By now you should realize, that when accessing data allocated via cbWndExtra = DLGWINDOWEXTRA + extra you only need to offset your request by DLGWINDOWEXTRA. So:

GetWindowLongPtr(hWnd, DLGWINDOWEXTRA + 0);

...will get you the first element of extra data. GWLP_USERDATA should be used only when you wish to get or set the one pointer of always-allocated user data associated with every window.

Shog9
For some reason I had convinced myself that GWLP_USERDATA was 0 (not -21), though I did know the other values were negative. I need to re-read this and think it through some more.
David L Morris
I have fixed the question, and my code (the code that didn't crash) definitely used '0' and not GWLP_USERDATA. I'm not quite sure where I got that from, probably miss-reading the MSDN documentation while writing the question.And with the question now corrected the first result is the one that actually worked (consistent with what you are saying). I thought I had bad code smell. Glad that I actually had bad question smell.
David L Morris
Ah, much better :-)
Shog9