6

good known that GWLP_USERDATA can be used to associate some pointer size data with the specified window. but who has the right do it ? obviously if two piece of code independently do this - one piece is overwrite data of another - so there must only be one owner. but it must be clear determined a general rule - who is owner of GWLP_USERDATA cell ? whom it belong ?

can be two internally consistent agreements:

  1. code that created the window is owner. belong to the creator of the window
  2. code which implement window class. belong to the window class implementer

what of this two solutions must be used ?

1. from MSDN:

GWLP_USERDATA:

Sets the user data associated with the window. This data is intended for use by the application that created the window. Its value is initially zero.

how need understand This data is intended for use by the application that created the window ?

so code which call CreateWindowEx, CreateDialogParam, DialogBoxParam, etc - and only this code can use GWLP_USERDATA. from this also follows that window class implementer can not use GWLP_USERDATA. so huge number of examples where GWLP_USERDATA used for bind instance of class to the specified window is incorrect. Managing Application State - official MSDN example, where GWLP_USERDATA used for bind data structure to window is incorrect ?!

SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);

is error under this rule.

what can be said in favor of this version ? i check different windows versions (from xp to win10) - how i can see all windows built-in window classes ( WC_* and others) use

SetWindowLongPtr(hwnd, 0, (LONG_PTR)pThis);

for bind instance of class to the specified window. always index 0 used instead GWLP_USERDATA

many can say - so what ? even if now this is true, what about future windows versions ? but if think, what sense migrate from index 0 (really private implementer index in all senses) to GWLP_USERDATA ? change existing SetWindowLongPtr(hwnd, 0, (LONG_PTR)pThis); to SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis); what prize ? or additional begin use GWLP_USERDATA with index 0 too ? this already absolute senseless - one pointer is enough for bind window to data structure, all additional pointers must be (and in case windows code will be) in this structure already. so i personally can assume that this is not changed


also can note an error in the documentation for SetWindowLongPtr and GetWindowLongPtr here:

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

really minus the size of an pointer which 8 bytes on x64, when size of an integer always 4.


2. look at a reputable blog - The bonus window bytes at GWLP_USERDATA:

Note that this value, ..., belongs to the window class and not to the code that creates the window... only the window class implementer may read or write the values.

but exist also next two author remarks:

Interesting. I’m checking into that. But even if it does belong to the creator of the window, enough window class implementations use it that you still should stay away for safety’s sake.

and

I asked around and guidance is "unclear", though leaning slightly towards "it belongs to the person who called CreateWindow". For safety’s sake, then, you should just avoid it unless you can establish clear ownership

again look for Managing Application State MSDN example - window class implementer used GWLP_USERDATA !

look for ATL atlhost.h - AtlAxWindowProc used GWLP_USERDATA

//case WM_CREATE:
::SetWindowLongPtr(hWnd, GWLP_USERDATA, (DWORD_PTR)pAxWindow);

again class implementer used GWLP_USERDATA

but under this agreement we can not use GWLP_USERDATA with CreateDialogParam, DialogBoxParam because here we not implementer (The DialogProc function is an application-defined callback function called from DefDlgProc - real class implementation code for dialogs - so only DefDlgProc can potential use GWLP_USERDATA cell)


so application that created the window or window class implementer is owner ?


if think - the variant application that created the window is more logical. window class implementer have two choice: can set cbWndExtra to sizeof(PVOID) and use index 0 or use GWLP_USERDATA index. when application that created the window - have no choice - only GWLP_USERDATA index or use another (less effective and more complex) way like SetProp, SetWindowSubclass, etc. so be logical if window class implementer use index 0 for bind self data to window and leave free GWLP_USERDATA for code that created the window. again how about CreateDialogParam, DialogBoxParam - most native way here for use data structure binds to dialog use GWLP_USERDATA index, but here we window creator, not dialog class implementer ! so can use GWLP_USERDATA or not ?

in all case need take to account that enough existing custom window class implementations use GWLP_USERDATA

my assumptions:

  • if we call CreateWindowEx for non windows core built-in class - we must not use GWLP_USERDATA here
  • if we call CreateDialogParam, DialogBoxParam - i assume that we can here use GWLP_USERDATA
  • if we call CreateWindowEx for windows built-in class (WC_* named) we also can use GWLP_USERDATA
  • if we window class implementer - the best choice - set cbWndExtra to sizeof(PVOID) and use index 0
RbMm
  • 31,280
  • 3
  • 35
  • 56
  • Haven't you provided enough examples to prove that there is no clear-cut answer to this? – Jonathan Potter Jan 07 '17 at 20:57
  • @JonathanPotter - yes, no clear-cut answer for my look. i decide post this question after some disputes on this forum - how correct and safe we use `GWLP_USERDATA`. say question is next - are my assumptions at the end how use `GWLP_USERDATA` is correct and safe enough ? if not - good be listen constructive critic - where and why i wrong. – RbMm Jan 07 '17 at 21:06
  • 2
    If there's no clear-cut answer that it's safe, then it might be safe or unsafe, which sounds unsafe to me. There is a perfectly safe alternative though, `SetProp` - I don't know why you don't just use that instead of continually arguing about something which simply can't be definitively resolved. – Jonathan Potter Jan 07 '17 at 21:07
  • @JonathanPotter - ok, if i correct understand your think - better not use `GWLP_USERDATA` at all. for my look if we yourself implement window class - the best use index 0. which clear is owning by implementer. if we use need subclass 3rd party window - here really `SetProp` or `SetWindowSubclass` (it internally use `SetProp`) or thunks in ATL style. however most interesting situation are we can use `GWLP_USERDATA` with built-in window classes. i think that it is possible, and tried to explain why i think so. however strange situation when documented feature become so unclear and not safe. – RbMm Jan 07 '17 at 21:24
  • @JonathanPotter - in all case thank you for your answer – RbMm Jan 07 '17 at 21:26
  • There's one flaw in your reasoning, that the standard controls did not use `GWLP_USERDATA`. The value `0` is also data, and some standard controls might rely on this value under some conditions you didn't investigate. The fact that `GWLP_USERDATA` is pointer-sized doesn't require storing a pointer. It could just as well be a bit field, and the value `0` can be a valid encoding. – IInspectable Jan 08 '17 at 12:35
  • @IInspectable - standard controls used `GetWindowLongPtr(hwnd, 0)` for get pointer to data (class instance) associated with `hwnd`. and additional pointers, bit field etc - is already inside this class instance. i sure in this on 100%. No, of course you can use what else `GWLP_USERDATA` for store some additional data, when you *already* have data storage to which index 0 point. but it would be extremely strange and not professional solution. – RbMm Jan 08 '17 at 13:00
  • like this can be only in 3rd party code. in standard controls - 0 **XOR** `GWLP_USERDATA`. they will be not use both. if i view that index 0 is **used** - can be sure that `GWLP_USERDATA` **not used**. about migration from 0 to `GWLP_USERDATA` in future this is possible but no sense. – RbMm Jan 08 '17 at 13:00
  • look like that buit-in controls design for case `This data is intended for use by the application that created the window`. but strange that documented index, have so unclear usage. – RbMm Jan 08 '17 at 13:02
  • I wasn't commenting on whether this is reasonable. I was commenting on your lapse of reason. You have observed an effect, and jumped to a conclusion: standard controls store `0` in `GWLP_USERDATA` so they cannot be using it. You cannot draw this conclusion from the observation if your playing field is confined by the laws of logic. – IInspectable Jan 08 '17 at 13:06
  • @IInspectable - no, my logical chain: standard controls **used** index 0 `GetWindowLongPtr(hwnd, 0)` -> they not used `GWLP_USERDATA` – RbMm Jan 08 '17 at 13:09
  • @IInspectable - but this is from msdn - `This data is intended for use by the application that created the window` - this is error in documentation ? and from Raymond blog - `I asked around and guidance is "unclear", though leaning slightly towards "it belongs to the person who called CreateWindow". ` – RbMm Jan 08 '17 at 13:11
  • The MSDN doesn't exclude custom window class implementations. So that would make your distinction between standard and custom window classes unfounded then. Anyway, this question and potential answers aren't very interesting, since there are viable, **safe** alternatives. Use `cbWndExtra` if you need additional space for custom controls, and `SetProp` for standard controls. There's no need ever to touch `GWLP_USERDATA`. – IInspectable Jan 08 '17 at 13:21
  • @IInspectable - ok, I understand your position. thank you. – RbMm Jan 08 '17 at 13:23
  • Interesting, long-standing question. Out of interest, how did you find out that Windows controls always use index 0 (instead of `GWLP_USERDATA`)? And that `SetWindowSubclass` internally uses `SetProp`? Did you disassemble the code? Or hook the functions? – dialer Jan 24 '21 at 11:36
  • @dialer - both this very easy visible if look for asm code. that standard windows controls use index 0 and *SetWindowSubclass* use GetProp/SetProp use atom for *UxSubclassInfo* – RbMm Jan 24 '21 at 13:55
  • Just stepped through it and this is quite interesting. `SetProp` internally uses `GlobalAddAtom`. `GlobalAddAtom` is *really* global, so if you use it, you *must* use `GlobalDeleteAtom`, or you might starve the system-wide global atom table. That means if you use `SetProp`, you *must* use `RemoveProp`, otherwise your property name will stay in the atom table forever. Same for `SetWindowSubclass`, although it uses the same atom name "UxSubclassInfo" for everything, so it'll only ever use up one entry in the atom table for all processes. Still, `SetProp` makes me rather uneasy now... – dialer Jan 24 '21 at 14:34

0 Answers0