Originally written on 10/03/2005.
This article assumes the reader has some knowledge of Win32 programming with C++.
It wasn't until Raymond Chen talked briefly about the extra storage space you get free with every window that I realised how few people could think of a use for it, or even knew it existed at all.
"The window manager provides a pointer-sized chunk of storage you can access via the GWLP_USERDATA constant. You pass it to the GetWindowLongPtr function and the SetWindowLongPtr function to read and write that value. Most of the time, all you need to attach to a window is a single pointer value anyway, so the free memory in GWLP_USERDATA is all you need."
This article intends to demonstrate a possible use for this extra space: For creating a simple self-contained windowing wrapper-class.
In order to encapsulate a window in a wrapper-class, the natural thing to do is to make its window message handling procedure a member of the wrapper-class. When this is done in the normal way, however, the compiler will die saying that it cannot convert an overloaded function to type WNDPROC, or something similar. This is because that in the WNDCLASSEX structure you use to register the class of window with the API, the lpfnWndProc member expects a pointer to a function with a prototype that doesn't account for the implicit this parameter that's passed to every class member function. It's this type mismatch that generates the compiler error.
The obvious solution to this is, of course, to make the function static because giving the function class scope removes the implicit this argument. The drawback to a static function is that it removes the function's ability to use other non-static members, as it cannot tell from which instance of the class the call was made without the this pointer. This is bad because the message procedure will more than likely need to use other non-static member functions and data members.
This where the GWLP_USERDATA space comes in. If the SetWindowLongPtr function is used to store the this pointer to the window immediately after creation, it can later be retrieved in the static message procedure through the window handle that gets passed into it. It's then possible to call a non-static message procedure for the correct instance of the wrapper-class through the retrieved pointer:
//statically declared message procedure LRESULT WINAPI CWindow::StaticProc(HWND hWnd, unsigned Msg, WPARAM wParam, LPARAM lParam) { //retrieve the window pointer from user data area CWindow* pWnd = (CWindow*)(GetWindowLongPtr(hWnd, GWL_USERDATA)); //call the real message handler return pWnd->Proc(hWnd, Msg, wParam, lParam); } //real message procedure LRESULT CWindow::Proc(HWND hWnd, unsigned Msg, WPARAM wParam, LPARAM lParam) { //... }
I've found it's handy to know about this user data space and I often use the technique outlined above for applications like small games or prototypes where MFC or other heavy-weight windowing toolkits would be a bit overkill.
Incidentally, the MSDN library states that the GWLP_USERDATA space is intended for use by the application that created the window, but Raymond rightly warns that enough other classes of window use this space for their own purposes that you should only use it if you are using a class of window that you registered yourself through RegisterClassEx.
It may also be worth noting that if you do register your own class of window, you can set the cbWndExtra member of the WNDCLASSEX structure to specify a number of additional extra bytes for the window manager to allocate if you want, for some reason, the user data area to be larger. Specifying an additional 4 bytes for example, (or 8 bytes when on 64bit hardware) will allow you store a second pointer.
Download sample source code (written for VC++ 2k3).