Wrapper for OpenGL, can't user member function WndProc

Started by
27 comments, last by MikeD 22 years ago
Well I hope the entire Subject Header gets through on this one. I''m writing a wrapper for OpenGL (do I hear yawns at the back?) and I''ve come across one specific problem. When I try to register my window with the windows system I have to pass in the WndProc function for message handling. This function is in my OpenGL class and I can''t cast it to anything the Visual C++ SDK is interested in compiling. i.e. the error generally is error C2440: ''return'' : cannot convert from ''long (__stdcall COpenGL::*)(struct HWND__ *,unsigned int,unsigned int,long)'' to ''long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long)'' i.e. it won''t accept a member function as the message handler. Is there a way around this or do I have to redesign? Cheers, Mike
Advertisement
I am aware that I can get around this by making the WndProc function a static member, but that would involve abstracting the function to a higher level class that deals with an OpenGL window by passing the messages through, as my WndProc function currently touches member variables.

This raises one question I''m not quite sure about, is it possible to have multiple windowed OpenGL windows or does hardware acceleration just not work that way?

Forgive me, I''m an AI programmer and I know not what I do.

Mike
MikeD is right, you can use a static member function for the callback. You then call a private member function on the correct window.

The trick then becomes figuring out which instance of the class belongs to this window. I've seen this done a number of ways...

One way is to use the SetWindowLong function to store a pointer to the object for each window. Then in your static member function, you get the HWND, and use GetWindowLong to retreive the pointer. Then you can call the correct private member like this...

pObject->PrivateWndProc().

The other cool way i've seen is to use an STL map or linked list to map HWNDs to object pointers. In your window creation function, store the HWND and this pointer in the map. Then you simply look up the HWND and retrieve the correct pointer.

Hope this works.

Chris Miller.

CosmicBee - Software With Buzz

[edited by - crizo on March 21, 2002 12:57:16 PM]
CosmicBee - Software With Buzz
Now that last method is elegant.
~V'lionBugle4d
My lead programmer at my last company (which fell 2 days ago) has an article in the pipeline for games programming gems 3 on an idea called autolists, where, using templates, a list is automatically stored with every instantiation of a class of the members of that class. So when you instantiate a window it would automatically have a list of the other windows as a static member. The static WndProc could access that list and, with each instantiation holding its own windows handle, you could use the static WndProc to traverse the list and find the suitable PrivateWndProc to call.

Either way, cheers crizo for a good direction to head in.

Mike
I searched long and hard on how to use a non-static member function as my WindowProc as well, and I ended up going with what crizo was getting at.

Basically I pass the this pointer of the object that creates the window to my custom window creation function. In this function, right after CreateWindowEx I call SetProperty with the handle of the newly created window, a string for the property (e.g., "PrivateWindowProc") and the this pointer which was passed to the function.

My CWindow class has a static member function MainWindowProc (which is what I use in RegisterClass) which simply checks to see if any window that is sending it messages has a property called "PrivateWindowProc", and if so I do what crizo said:

return(pThis->PrivateWindowProc(hWnd,uMsg,wParam,lParam));

If the messaging window doesn''t have, or doesn''t yet have, a property for the this pointer then I just pass the message to DefWindowProc.

This way, the MainWindowProc passes all messages to my non-static member function, PrivateWindowProc, which can then access member data normally.

If you want to see exactly what I''m talking about let me know.

Care,
Chris Rasmus

Florida, USA
RTS Engine in Development
http://www.knology.net/~heaven
Jesus is LORD!
Florida, USA
Current Project
Jesus is LORD!
You could have a static function that calls the WndProc function of the appropriate instance for you, using a static pointer to the current instance.

static OGLWrapperObj* OGLWrapperObj::currentObj;

static void OGLWrapperObj::CallFunc( void )
{
currentObj->WndProc();
}

Then you could simply make any instance the current instance...

void OGLWrapperObj::MakeCurrent( void )
{ currentObj = this; }

and call the function.



[edited by - smitty1276 on March 22, 2002 12:49:00 PM]
Interesting, reading this thread has given me insight to pretty much the same problem I am experiencing.

I've been trying to create a "CWindowGL" class which would just create the actual Window and handle all the messages. However, I came across the WndProc problem. I've been trying to get my head around these replies, but it's difficult because I am quite new to Windows programming.

The one method of implementing a solution to the WndProc problem that intrests me is the one that Heaven posted. However, I am curious: What does the MainWndProc() function handle, and what does the PrivateWndProc() function handle? Can you maybe explain the relationship between these two in greater detail? Are you using MFC to make use of the SetProperty() func? Any help is appreciated, thanks!

PS:

Earlier today I was sort of able to get it working: I friended the WndProc function in my CWindowGL class, however my CPU usage jumped up to ~50% and nothing got drawn to the screen. I guess friending it isn't the optimal route... :D

[edited by - Wheaty on March 22, 2002 5:27:56 PM]
The relationship between the static MainWndProc and the PrivateWndProc is as follows.
As you require a static (or non-member) function to pass into the WndProc pointer when you register the window, to handle messages, you have to have a MainWndProc to do the message handling. However you want each window to handle its own messages with its own member function that can access the member variables. So the MainWndProc must have access to all of the window instantiations so it can pass the message on to the correct window. So the MainWndProc handles passing the relavent message to the correct instantiation of the class of window.

If that makes sense.

Mike
Ugh...

Well, I understand WHY this needs to be done, however I am confused over how to implement it. For example (not using GL stuff, just trying to get a regular window drawn -- I also chopped some member funcs out, just want to get this WndProc stuff straightend out):


        class CWindowGL{protected:	HWND hWnd; // window handle	HDC hDC;   // device contextprivate:        bool done; //on/off flagpublic:        CWindowGL() { done = false; } // constructor	static LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);        LRESULT PrivateWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);};        


[edit: whoops, moved the PrivateWndProc() to public: ]

So what you're trying to say is that the MainWndProc() would determine WHICH object to use, and then call that object's PrivateWndProc function. So there would be no need to use a switch(message) {... } in that function, because its only purpose would be to determine which PrivateWndProc to call. I understand that -- I guess where I'm stuck is how to store the pointer data. I saw Heaven referring to a "SetProperty" function... I checked my MSDN documentation and it seems to be a MFC call.

[edited by - Wheaty on March 22, 2002 6:46:04 PM]

This topic is closed to new replies.

Advertisement