quick windows question (c++)

Started by
3 comments, last by TonyFish 21 years, 11 months ago
Hi, I haven''t touched the Win API for years and have forgotten a fair bit ! I was just wondering what exactly the purpose of the following (in the NEHE OGL BaseCode 2) code was. case WM_CREATE: { CREATESTRUCT* creation = (CREATESTRUCT*)(lParam); window = (GL_Window*)(creation->lpCreateParams); SetWindowLong (hWnd, GWL_USERDATA, (LONG)(window)); } why do all this upon WM_CREATE ?? Cheers { <Fish>{
<Fish>{
Advertisement
Overall they are attaching data to the window. That data is a pointer to the creation parms for the window. Any time they have the window handle they can access that information such as when they get a message for that window. If you want to know why then look for the GetWindowLong calls. If you want to know what it is actually pointing at then you need to look for the CreateWindow or CreateWindowEx statement and it is the last parameter in that call.
Keys to success: Ability, ambition and opportunity.
Short answer: it''s sort of a hack to avoid making the GL_Window a global variable. LilBudyWizer is right on, I just thought I''d expand on his answer.

People often want to make their Windows message callback a class member function so that when they receive Windows messages they can just call this->paint() or this->close() or whatever. But because of the API''s design the callback can''t be a member function, so many people''s solution is to have a global window variable (a no-no if you ask a lot of people). There are several tricks you can use to get around this; the code you listed is part of one of these tricks. If you want a full explanation read on.

In a call to CreateWindowEx the last argument is optional, of type LONG. If you pass it something then it will get passed to the message handler callback in the lParam argument when the WM_CREATE message is generated.

If you have a window handle you can associate some of your own data with it by calling SetWindowLong(someWindowHandle, GWL_USERDATA, (LONG)(yourDataHere)); and retrieve it later with GetWindowLong(sameWindowHandle, GWL_USERDATA);.

What the basecode does is pass a pointer to a GL_Window structure as the optional argument to CreateWindowEx (lines 114-124 of NeHeGL.cpp). When the callback receives WM_CREATE the pointer is extracted from the lParam argument and then saved with SetWindowLong (the code you posted). In future calls to the callback this pointer is retrieved with:

GL_Window* window = (GL_Window*)(GetWindowLong (hWnd, GWL_USERDATA));

at the beginning of the message handler. That pointer is used when responding to messages (eg when a WM_CLOSE message is received the basecode calls TerminateApplication(window)). Voila, the variable window doesn''t have to be global and you have access to it in the callback.

You might have noticed that GetWindowLong is actually called once before SetWindowLong has been called, I think in this case it just retrieves garbage, which isn''t used anyway since the first message sent is always WM_CREATE (or possibly WM_NCCREATE?).

You might be wondering why SetWindowLong can''t be called immediately after CreateWindowEx to avoid the whole lParam thing you posted. I think it''s because you don''t actually have a valid window handle until WM_CREATE is received (I could be wrong here, just making an educated guess).
NCCREATE is documented to be first.. but actually a queue sync message is sent before that.. (found that out the hard way)
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
Well thanks for the detailed answer. That was most helpfull.
Unfortunately I want the user input to be handled by a Win32MsgManager class which will basically hold the various key bindings (modifiable by the user) which (hopefully) will permit me to bind complex things like console actions-a-la-quake (bind a "echo 'binding'; +forward; +left") or even scripts. Thing is I'm not sure whether such a class is really necessary or whether these binding-related functions wouldn't be better of nested in the window class or the console class. Any ideas ?
Btw I heard that the WM_KEYDOWN events didn't cover the function keys (F1,F2 etc) is this true ?

Thanks again

[edited by - TonyFish on May 25, 2002 7:07:56 PM]
<Fish>{

This topic is closed to new replies.

Advertisement