c++/win32 - static and callback

I have a Window class with a callback on it.
So each instance (window) must have its own callback(so callback cannot be static), but “wc.lpfnWndProc” requires a “static” member.

The error:

error C2440: ‘=’ : cannot convert from ‘long (stdcall MYCLASS::*)(struct HWND *,unsigned int,unsigned int,long)’ to ‘long (stdcall *)(struct HWND *,unsigned int,unsigned int,long)’

So you want to have a single class with several wndproc functions to choose from? That doesn’t sound right. Or do you want to have a virtual wndproc and implement it in derived classes? That sounds better but it won’t work in your case.
How about storing the address of the window in the user data field? Then have a static callback function in the base class which grabs the address and calls the real callback function (implemented in the derived class).

Your callback must be a static member. The solution is to use a map, to map instances to member functions and to execute the appropriate method.

Frameworks like MFC and ATL do this automatically, so you don’t have to worry about all the WndProc rubbish.

C++ does this automatically. Your class methods are merely static C functions, and the C++ precompiler invisibly passes in an instance argument every time you call one.
The Win32 framework is a C interface, so you have to do this yourself.

>>> So each instance (window) must have its own callback(so callback cannot be static), but “wc.lpfnWndProc” requires a “static” member.<<<

Callbacks are static. They are your basic C style functions.

wc.lpfnWndProc=MYCLASS::function;

where function is declared static.

V-man

in createwindow you can give over an additional parameter, wich is the thispointer.
in the static messageproc you check for WM_NCCREATE and there, you look for this additional userparameter of createwindow (the CREATEWINDOWSTRUCT you ressieve in one param, i think the LPARAM). this this-pointer you got over there you store into your window with SetWindowLong(GWL_USERDATA,(long)_the_this_pointer_of_createwindow);

then, for all other messsages, use GetWindowLong(hwnd,GWL_USERDATA) to recieve the thispointer again, and call the nonstatic per window implemented HRESULT Window::WndProc(UINT msg,WPARAM wParam,LPARAM lParam);

thats the way that is the fastest and best one…

For MDI child windows, you need to pass a specific Windows struct as the lpParam parameter. I prefer to pass an actual CLIENTCREATESTRUCT but embellish with my own window pointer, something like:

struct MyCreateStruct {
IMyWindow * window;
CLIENTCREATESTRUCT mdiData;
};

Then you pass &myStruct.mdiData as lpParam, and recover the pointer to MyCreateStruct inside NCCREATE using pointer arithmetic.

davepermen;

do you have an example?

Hey guys. please help me. I Know theres an simple and object oriented solution for this problem.

Thanks a lot;

have fun: http://www.itstudents.ch/users/dave/free/files/Window.zip
its now some time old, dunno. but it works…

it has more in than you want, but, its a working example

lsdi,

Because Win32 is a procedural interface, you have to interface with it procedurally. We’ve shown you two ways to minimize the procedural interface, both of which are good solutions to the problem of adapting the given procedural interface to some polymorphic interface of your choice.

The Win32 API requires that a window procedure be a C function with no this pointer. There is no way around this. Your options are:

  1. create a map that maps HWND’s to C++ Object pointers and have your window procedure use this map to forward the messages to the C++ objects - this is how MFC does it.
  2. do it the way ATL does it. - Basically what happens is that when the first message is received by a StartWindowProcedure, the C++ object that corresponds the the HWND is looked up and a thunk is created that hold’s the C++ objects this pointer. SetWindowLong is then used to sub-class the window to use the thunk as the window procedure. What the thunk does is to replace the HWND parameter with the this pointer, then jmp to a Window procedure that casts the hwnd parameter to a CWindow pointer and call the CWindow’s ProcessWindowMessage() method which is non-static. Hope this helps

Dslater, that sounded quite painfull. Does WTL do things any differently?

Davepermen, your method works VERY fine. Thanks.