WinMain, WndProc & Variable

Started by
24 comments, last by CrazyCdn 15 years, 1 month ago
Quote:Original post by Mike2343
Quoted as its exactly what I was trying to get at. I read Codeka's solution and honestly it sounds hackish to me. Thats why I was trying to really get more information so we could actually help the OP develop a "proper" solution to his issues.


I was mostly responding to the people saying "put the WndProc in your class" or "post a special message", "make it a global" or whatever. My second response did come off a bit harsh, and I apologize for that :-)

Anyway, I agree that in many cases, there might be a better way to do things, and certainly in this particular instance that may very well be the case.

Having said that, my solution is quite common if you're writing a Win32 wrapper and want to pass an instance of your "window" class to the WndProc.
Advertisement
This is what I do:

// engine.hclass Engine{public:    Engine(HWND Hw);    ~Engine();    void Update();    void Render();    void KeyDown();};// engine.cppEngine::Engine(HWND Hw){    SetWindowLongPtr(Hw,GWLP_USERDATA,reinterpret_cast<LONG>(this));}Engine::~Engine(){    SetWindowLongPtr(Hw,GWLP_USERDATA,NULL);}// main.cpp#include "engine.h"int WinMain(yada yayda){     try         {         HWND Hw=CreateWindow(yada yada);         Engine E(Hw);         while(yada yada)              {              MessagePumpStuff();              E.Update();              E.Render();              }         }      catch(...)         {         }}LRESULT WnnProc(yada yada){    Engine *E=reinterpret_cast<Engine*>(GetWindowLongPtr(Hw,GWLP_USERDATA));    switch(Msg)        {        case WM_KEYDOWN: if(E) E->KeyDown(wParam); break;        default: return DefWndProc(yada yada);        }    return 0;}


No globals, Engine E() exists as a local variable so obeys all the usual rules regarding initialisation/destruction and the WndProc only ever gets called during the message pump, so no chance of calling it while the user data is in an indeterminate state.

Some people pass the user data to CreateWindow and respond to the WM_NCCREATE message to assign it to the HWND user data but I find my approach simpler - as long as you don't need to call the engine back during the window creation or destruction process, it's fine.

The other advantage is that I can instantiate my Engine class after Window creation (which is necessary as Engine creates the GraphicsDevice in its constructor) and avoid an Engine::Initialise() method.

[Edited by - EasilyConfused on March 13, 2009 12:36:01 PM]
*All that said, the class you are making is silly. It's, at best, a marginally better solution than the globals you had before. Its certainly not going to be very scalable to continue this way, so you would be wise to work towards a more sensible, correctly encapsulated design.*

Well, its either putting variables in a class or getting slapped on the fingers :P

I would prefer neither, but what to do?

*Engine *E=reinterpret_cast<Engine*>(GetWindowLongPtr(Hw,GWLP_USERDATA));*

I've never written code like that so could you please tell me alittle about it?

*case WM_KEYDOWN: if(E) E->KeyDown(wParam);*
I hope you dont mind if I continue with this kind of code? I see new ways of doing code and some I would never have thought about..
Quote:Original post by 1st_maza
*Engine *E=reinterpret_cast<Engine>(GetWindowLongPtr(Hw,GWLP_USERDATA));*


I've never written code like that so could you please tell me alittle about it?

SetWindowLongPtr stores a long datatype. The thing is, an 'Engine*' is not a 'long'. The reinterpret_cast - which, by the way, is best to avoid except when doing things like this - takes a variable and re-interprets it as an entirely new datatype, no questions asked (or, at least, very few). The value it outputs is exactly the same... except it's considered as something other than what it was.

Basically, we have a 'long' doppelganger that's really an Engine*, that SetWindowLongPtr stores. GetWindowLongPtr then returns that long value, but we need to cast it back to an Engine*.

~Jonathan
Well, thank you all for the help you have given... :D
Yeah, EasilyConfused way of doing it is a nice KISS method. I personally catch the WM_NCCREATE message but I created my class years ago and have no reason to reinvent the wheel. But for someone just starting out, I would go this route.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

This topic is closed to new replies.

Advertisement