Member function pointers and things

Hello,

(My question contains a trace amount of the Win32 API, so if any of you wizards see what I'm trying to do, and know a better way of doing it, please say so).

I'm trying to make a mini-wrapper for the Win32 API - "mini" because this is for some project I want to give a maker over, and because it'll only wrap windows (poorly).

Through my frustration, I've narrowed my problem down to the example below:

foo.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef _FOO_H_
#define _FOO_H_
#include <windows.h>

class Base {
public :
	Base() {}
	void init();
	

	LRESULT (CALLBACK Base::*fptr)(HWND, UINT, WPARAM, LPARAM);
	virtual LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;

};

class Derived : public Base {
public :
	Derived() {fptr = &Derived::WndProc; init();}

	LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {}

};

#endif 


foo.cpp
1
2
3
4
5
6
7
8
9
10
11
#include "foo.h"

void Base::init() {
	WNDCLASS wc;

	//do things with wc...

	wc.lpfnWndProc = (WNDPROC)*fptr;
	
	//do other things...
}


Note, that foo.h has changed a lot, due to my trying different potential solutions.

Basically, Base has a pure virtual window procedure callback function "WndProc".
It also has a non-static member function pointer "fptr", which is not initialized.

Derived has a temporary body for the WndProc callback, which does nothing.

The idea is that Base represents a generic window class, and Derived is just one possible window class, as there could be any number of other window classes inheriting from the generic one (each one needs it's own WndProc).
However, each derived class needs to be able to assign fptr its own implementation of the WndProc callback, before Base::init() can use it.
Originally, I tried to do this with all kinds of different solutions, all of which are illegal apparently.
At this point, my brain can't even visualize the timeline of my stress properly, but it looked something like this:

1.) Passing default member function pointers to the Base ctor (before init() was conceived)
2.) Weird initializer lists - Something about how you can't initialize base members in derived classes, and how the Derived class wouldn't know what fptr was.
3.) std::tr1::function / bind / lambda / whatever
4.) Killing myself

That's it. I know I'm missing a lot of important details, but I'm really burnt out from this.
The real question is more of a request, which is : if you know a better way of doing this, halpppp.
Last edited on
bind/function won't work because std::functions are their own type and are not function pointers. They're distinct objects.

Your problem here is that member functions need a hidden this parameter to indicate which object the function acts on. The 'this' pointer is part of the function signature, even though it doesn't appear to be (it is implied). Therefore it is impossible to pass a pointer to a non-static member function as a WNDPROC callback. It simply cannot be done.


What you need to do instead is:

1) Call a global function (or a static member in your base class)

2) In that function, do something with the given HWND to identify and obtain a pointer to your window object.

3) Use that pointer to call that object's window handler.



I forget the typical way to do this... but I think there's a way to set some kind of property (in the form of a void pointer) associated with the HWND. You would do this as soon as the window is created... then when you need to obtain that pointer, you do a 'get' to re-obtain that property.

However I forget the exact function calls to accomplish this. I want to say SetWindowLong and GetWindowLong but I don't think those are right. I'll look and will see if I can find it...



EDIT:

Looks like I was close... but you want to use GetWindowLongPtr and SetWindowLongPtr:

Set:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644898%28v=vs.85%29.aspx

Get:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633585%28v=vs.85%29.aspx


So basic idea:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
////////////////
// when the window is created

Base* wnd = /*your window object*/;
HWND hwnd = /*Your WinAPI window handle*/;

SetWindowLongPtr( hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(wnd) );


// ...

// for your callback:
class Base
{
  virtual LRESULT wndProc(...) = 0;

  static LRESULT CALLBACK staticWndProc(HWND wnd /*...*/)
  {
    Base* ptr = reinterpret_cast<Base*>( GetWindowLongPtr( wnd, GWLP_USERDATA ) );
    return ptr->wndProc( ... );
  }
};




EDIT:

Also... casting a polymorphic pointer to/from a void pointer (or in this case... a LONG_PTR) is DANGEROUS. Be sure you cast to/from the same type EVERY TIME (ie: in this example I cast to/from a Base* pointer).

Casting Base* -> LONG_PTR -> Base* is ok

Casting Derived* -> LONG_PTR -> Base* is NOT and may explode on you.
Last edited on
Thanks Disch, even though I didn't quite understand the Set/GetWindowLongPtr example, I now understand why what I was trying to do is illegal.

Your post also gave me some keywords to google, and I found some other very useful posts/articles. Thanks again!
Topic archived. No new replies allowed.