Making WinProc a member function

Started by
10 comments, last by Evil Steve 17 years, 11 months ago
Hello, I'm writing a simple wrapper class for creating and managing windows in the Win32 API. I got to the point where I needed to give the window message handler access to data members of the wrapper class, and decided to include it as a member function. However, when I tried to assign its pointer to the lpfnWndProc field in the WNDCLASSEX structure I got an error saying that it wasn't possible. The question is: How can you give WinProc access to private data members without making the wrapper class global (and making WinProc a friend fucntion), or some cheap quick fix like that?
Advertisement
There are a number of different approaches. Here's a popular one: Creating a Win32 Window Wrapper Class
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
My implemenation does just that - the global WndProc is a friend of the class, and calls a private WndProc of the application class. I don't know if there's a "better" way to do it, but this method is the simplest and most straightforward to use.
Use SetWindowLongPtr to store a pointer to your object in the window instance, and register a trampoline (non-member or static member) WndProc that retrieves that pointer with GetWindowsLongPtr, casts it to the appropriate type then uses it to call the appropriate member function.

The amount extra storage for that pointer must be specified when the window class is registered.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Quote:Original post by Fruny
Use SetWindowLongPtr to store a pointer to your object in the window instance, and register a trampoline (non-member or static member) WndProc that retrieves that pointer with GetWindowsLongPtr, casts it to the appropriate type then uses it to call the appropriate member function.
Trampoline WndProc? Juh? Never heard a non-member/static member function be called that before.

Anyway, I have a program thta does what Fruny is suggesting, but I use hooks in my "trampoline" WndProc to do the job.
Interesting article. I'm going to try implementing some of that stuff now, but I'm pretty sure it solved my problem. Thanks a lot for the replies.
Actually, I just had an idea. You see, my main class is what coordinates the actual Window classes. All they do is store important information, like the window handle/rendering context etc. The main class does things like creating the individual windows and dispatching messages to a single WndProc. So, could I just eliminate the need for a WndProc ( and just create a dumby WndProc for winclass.lpfnWndProc ) by doing all of the message handling in a regular member function of the main class?

An example:

//inside of a member function of the central classwhile( PeekMessage( &msg, 0, 0, PM_REMOVE ) ){  TranslateMessage( &msg );  //then cycle through container containing the Window classes until a matching   //handle to window is found.    //DO NOT dispatch to WnDProc    //do specific message handling for the particular window  switch( msg.message )  {    case WM_CREATE:       //stuff...       break;    case WM_CLOSE:       //you get the idea...       break;    default:break;   }      //and then something along the lines of....   return( DefWindowProc( msg.hwnd, msg.message, msg.wParam, msg.lParam ) );}
Quote:Original post by SL33pY_Kr3W
So, could I just eliminate the need for a WndProc ( and just create a dumby WndProc for winclass.lpfnWndProc ) by doing all of the message handling in a regular member function of the main class?
I suppose you could, but I would recommend against it because with this method you'd have to determine which window generated the message and then handle that howerver, whereas if each window had its own instance of a WndProc then that step is handled for you. In other words, you could do it the way you've suggested, but it seems like you'd just be making things harder for yourself in the long run.
Can't you just make the WndProc function a static member function?

static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)?

EDIT: Ooh. If you need multiple windows this might be a problem. I'm going to leave this here in case it's any help though. [disturbed]
I think you should stick to what Fruny has said about attaching the pointer of your object owning the window handle to the actual window itself

So your modifications to your WNDCLASSEX struct might be:

wcex.cbWndExtra = sizeof(Window*);

I put the sizeof(Window*) in there just in case sometime down the timeline we get a >4 byte pointer.


class Window {public:   bool CreateWindow(); // Remeber to #undef CreateWindow otherwise compiler will spew, or you could name it differentprotected:    virtual LRESULT HandleMessage(UINT umsg, WPARAM wparam, LPARAM lparam);private:  HWND hwnd;  static LRESULT CALLBACK WndProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam);};bool Window::CreateWindow(){  hwnd = CreateWindowEx(...);  if (!hwnd)    return false;  SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));    // Additional window setup code  return true;}LRESULT HandleMessage(UINT umsg, WPARAM wparam, LPARAM lparam){  return DefWindowProc(this->hwnd, umsg, wparam, lparam);}LRESULT CALLBACK Window::WndProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam){  // Get the window object attached to the window handle  Window* wnd = reinterpret_cast<Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));    if (wnd) return wnd->HandleMessage(umsg, wparam, lparam);  else return DefWindowProc(hwnd, umsg, wparam, lparam);}


You can derive off Window and the correct window object will be called from your WndProc function.

This topic is closed to new replies.

Advertisement