Making WindowProc part of a window wrapper class without using static

Started by
13 comments, last by Subotron 21 years, 1 month ago
Use a static std::map in the CWindow class to map from window handles to CWindow pointers. Create the mappings during window creation, and when you receive a message in WndProc use that map to translate from HWND to CWindow*.


  class CWindow {public:  CWindow();private:  void init();  HWND mHandle;  static std::map<HWND, CWindow*> msThisMap;  static long FAR PASCAL staticWndProc(...);  long instanceWndProc(...);};// during some CWindow::CWindow() {  init();}void CWindow::init() {  // pass the static WndProc callback  WNDCLASS wc;  wc.lpfnWndProc = &staticWndProc  RegisterClass(wc);  // associate the HWND with a this pointer  HWND mHandle = CreateWindowEx(...);  if (!mHandle) {    throw "ahhhhhhhhhhhhh!";  }  msThisMap[mHandle] = this;}long CWindow::staticWndProc(HWND hwnd, UINT msg, UINT wParam, UINT lParam) {  // retrieve the CWindow* pointer that was stored in init()  CWindow* thisPointer = msThisMap[mHandle];  // dispatch the call to the correct instance  return thisPointer->instanceWndProc(msg, wParam, lParam);}   


That code sample is far from complete, and is probably incorrect in a few places since I pretty much did it from memory, but it should give you an idea of how to accomplish your goal. It's a hack, but hacks are all you have.


edit: code /code tags don't handle templates

[edited by - Dobbs on March 18, 2003 10:21:12 AM]
Advertisement
www.gamedev.net/community/forums/topic.asp?topic_id=144717


[edited by - BlackHC on March 18, 2003 10:19:29 AM]

[edited by - BlackHC on March 18, 2003 10:20:02 AM]
I do know that I don't know anything.
Another way is to create a global(or static) map containing pointers to instances of the window wrapper class. The HWND is used as a key to the map.

Every time a window object is created, add it to the map with HWND as key. In the static WndProc, use the map to find what window object is associated with the HWND and pass the message handling to the object. AFAIK MFC uses this method.
"-1 x -1 = +1 is stupid and evil."-- Gene Ray
Here''s what I do. Store the class attached to a window in the window''s user data area.
i.e. (NOTE: casts omitted)

WM_CREATE:
SetWindowLong (the_window, GWL_USERDATA, this);

The ''this'' pointer would be passed as the lpParam parameter to the CreateWindow(Ex) function. Note that WM_CREATE is not the first message to be sent to a window, so you''ll need to check for NULL pointers (the user data area is initialised to 0). So, to create a window:
window = new WindowClass ();
window->Create (creation_args); // CreateWindow(Ex) (..., this);
window->Show ();


EVERYTHING_ELSE:
this_ptr = GetWindowLong (the_window, GWL_USERDATA);
this_ptr->do_a_function (some_args);

Pros: No nasty globals.
Cons: If you''re already using the GWL_USERDATA for something, then you''ll need to either add extra bytes in the WNDCLASS(EX) or have the GWL_USERDATA point to a structure/class.

Skizz
Well, if you want less complexity, and don't mind a bit of a 'hack' in this area, I can suggest this:

Make your WinProc outside any class, and give it a static variable as a pointer to your class. Like this:

int __stdcall WinProc(...)
{
static EntireGame* me = NULL;
}

Then, *before* you actually make the window, but *after* you construct your class, call this function manually.

//...
EntireGame* game = new EntireGame(...);
WinProc(0, OBJECT_INIT, 0, (LPARAM)game);
//...

So, now you just have to look for this in your WinProc function and set the static variable to the LPARAM of the function, and from then on, have it simply relay all messages to your object. Like this:

int __stdcall WinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp){  static EntireGame* me = 0;  if(msg == OBJECT_INIT)  {    me = (EntireGame*) lp;    return 0;  }  if(me == NULL)    return DefWindowProc(hwnd,msg,wp,lp);  else    return me->WindowProc(hwnd,msg,wp,lp);  } 


And from then on, your class' own, personal WindowProc will be responsible for messages.

NOTE: This is basically the same method as setting the Window's User Data, but a little more straight-forward if you aren't used to that sort of thing.

[edited by - Rick Scott on March 18, 2003 11:54:53 AM]

This topic is closed to new replies.

Advertisement