Is it possible to have callback function as a class member?

This is a discussion on Is it possible to have callback function as a class member? within the Windows Programming forums, part of the Platform Specific Boards category; Hi, all
I am writing a class that creates and maintains a window/control. The problem is that I canít seem ...

Is it possible to have callback function as a class member?

Hi, all

I am writing a class that creates and maintains a window/control. The problem is that I canít seem to give the class its own private callback function (the Window Procedure alias WndProc); the VC++ complier simply gives a type cast error when giving out the function pointer. I thought about why and I assume that the reason lies in the different structure between class functions and global functions. But is there a way to go round this, like force the compiler to construct the class function as a global function (assuming thatís the case)? If thatís not that the case, then why does the compiler give a type cast error? And is it possible to have callback function as a class member or at least give the class some sort of private callback function? And oh yes, I know I can use MFC but I simply prefer not, I want to know if can be done without its help.

No problem....make the callback a static member function...that way it always exists even if there isnt an instance of the class (this is your problem by the way...a member function need the this poiter for it's non static member funcs)

I use MFC, but I have had to create a window wrapper class as well (For my OpenGL stuff - didnt want MFC to be used there)...nothing wrong with that

Have a peek at Ken Fitlike's page....he has some stuff on window wrappers

Thanks that worked (making the function static), but another problem came up. I get a link error saying ďillegal reference to data member 'Class::X' in a static member functionĒ, whenever the static function uses other class members (both variables and other functions). How can I solve this?

Yeah...that's the problem you have to get over...all instances of your windows class will use that 1 function....so if you reference any member variables or member functions in that static func, they must be static also......

There are ways around this.......cant remember exactly how I did it (not near my code right now), but 1 idea might be to use a static std::map member with a pair of <HWND,MyWindowWrapper*>.....you could pass the "this" pointer along with the user param of CreateWindow......then in the WM_CREATE handler, take the hWnd param and cast the lParam to a pointer to a CREATESTRUCT. The lpCreateParams member of CREATESTRUCT can be cast to a MyWindowWrapper pointer (this is the "this" param you passed). Then with the HWND and the MyWindowWrapper*, add them to the map....then in other handlers (WM_SIZE...etc) you call the map with the hWnd param of your WindowProc and you should get a pointer to a MyWindowWrapper which will allow you to access members of that class

I ran into this exact problem a while ago, and found a decent solution. A good person to ask is Ken Fitlike, he's good with classes.

Basically, you need to create two member functions: a static callback procedure, and a normal one, with the same parameters.
In the static one, the first time it is called, you have to obtain a pointer to the instance of the class you want. Then you can forward the messages to the non-static procedure, which has full access to the class members. Compilcated, I know.

It's intensely complicated actually. Basically, the callback procedure has to be static, so that there is an instance to point to from the beginning. But, this means that the procedure CANNOT know where the instance of the CLASS is. So you have to find the class instance yourself, and store that value somewhere permanent. Then you can forward messages all you want. But I don't know how it would be done when not using the window procedure. It just happens that the WM_NCCREATE is the first one to occur, and can contain a pointer to the class.

As CorenedBee said - yes...each window can have a 32bit user defined data variable with it...accessed with GetWindowLong.....this variable can be used to store the this pointer of a class.....

The difference between my idea and your example is that I store my pointers in a map for access using a HWND as a key, and with yours, you call GetWindowLong each time you need the pointer to an instance.... either should work, but if the use of your class decides to store their own data in the user defined variable, then you could have a problem with your version....if this might be a problem then you could use my std::map method (I have a sneaky suspicion that MFC uses a map for this stuff....cant tell right now though)

Hmm. Would there be callback functions not associated with a window? I mean, sometime or rather, you're going to have to give the address of a member function from a class, and it'll have to be static, and therefore you won't have access to the data members. eg:

Or something like that. I have no idea about the function return type thing, but that's not the issue. In that case, where a function pointer is returned, and there are no windows associated, where can data be stored?

Originally posted by Fordy >>But is there always somewhere to store the pointer?

As CorenedBee said - yes...each window can have a 32bit user defined data variable with it...accessed with GetWindowLong.....this variable can be used to store the this pointer of a class.....

It can store a lot more than that. You have the 32-bit (64 on 64-bit Win) value by default, but can always have more by specifying a value other than 0 for cbWndExtra in the WNDCLASS.

The difference between my idea and your example is that I store my pointers in a map for access using a HWND as a key, and with yours, you call GetWindowLong each time you need the pointer to an instance.... either should work, but if the use of your class decides to store their own data in the user defined variable, then you could have a problem with your version....if

The call to the function requiring a callback is something internal to my class - the user simply doesn't get a chance to pass his own data
The class can offer an alternative which can then be handled using member variables - but again, this doesn't need to concern the user.

this might be a problem then you could use my std::map method (I have a sneaky suspicion that MFC uses a map for this stuff....cant tell right now though)

MFC uses a map (though it's a hash map, not a tree like std::map). This is in part because only this way makes CWnd::FromHandle possible.