C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

calling member functions from WNPROC callback functions

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
PINTS
Guest





PostPosted: Thu Dec 22, 2005 12:19 pm    Post subject: calling member functions from WNPROC callback functions Reply with quote



{Thopugh this, at first glance is Windows specific which would make it
off topic, the actual problem of the call back has more general
application -mod}

I am trying to subclass a window and the I wanna keep the WNPROC as a
non-static member function of the class. The problem is that class
member functions have a "this" pointer as a hidden first parameter
which uniquely identifies a class object (keep in mind that an object
is a specific instantiation of a class). The API callback does not
know how to pass "*this." Is there a solution to this problem or do I
have to make it static? I am using the MSVC compiler.

Thanks


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Heinz Ozwirk
Guest





PostPosted: Fri Dec 23, 2005 2:57 am    Post subject: Re: calling member functions from WNPROC callback functions Reply with quote



Quote:
I am trying to subclass a window and the I wanna keep the WNPROC as a
non-static member function of the class. The problem is that class
member functions have a "this" pointer as a hidden first parameter
which uniquely identifies a class object (keep in mind that an object
is a specific instantiation of a class). The API callback does not
know how to pass "*this." Is there a solution to this problem or do I
have to make it static? I am using the MSVC compiler.

Many callback functions used in the Windows API have a paramter large enough
to hold a pointer. When you install such a function you can specify, which
value should be passed to the callback function. Pass the address of the
object you want to use, and whenever the function is called, you can
(reinterpret_) cast the parameter to a pointer to your class. Of cause, the
callback function must be a stand-alone function or static member of your
class. You cannot use non-static member functions for callbacks.

Alas, the window procedure does not have such an extra parameter. You have
to use some other mechanism to find the object, which should handle
messages. You can create a map<HWND, MyClass*> to assiciate a windows handle
with an instance of a class (like MFC does), or you could write a pointer to
an object directly into the extra space windows structure. Have a look at
GetWindowLong and SetWindowLong.

HTH
Heinz



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
peter steiner
Guest





PostPosted: Fri Dec 23, 2005 3:11 am    Post subject: Re: calling member functions from WNPROC callback functions Reply with quote



PINTS wrote:
Quote:
{Thopugh this, at first glance is Windows specific which would make it
off topic, the actual problem of the call back has more general
application -mod}

I am trying to subclass a window and the I wanna keep the WNPROC as a
non-static member function of the class. The problem is that class
member functions have a "this" pointer as a hidden first parameter
which uniquely identifies a class object (keep in mind that an object
is a specific instantiation of a class). The API callback does not
know how to pass "*this." Is there a solution to this problem or do I
have to make it static? I am using the MSVC compiler.

it is correct that there is no way to simply use a member function
pointer instead of a non-member function pointer because the signatures
do not match.

usually there is some kind of class specific data that you can use to
identify the object instance inside the static callback. either you can
specify user data that is passed into the callback as additional
parameter (afair even called instance data in windows) or there is a
window handle uniquely identifying the object.

the former is probably not the case, as then you would have just passed
the this pointer of the object for further use in the callback...

e.g.

struct Window
{
Window()
{
createWindow(..., &Window::staticCallback, this, ...);
}
static ... staticCallback(..., void* instanceData, ...)
{
Window* instance = reinterpret_cast<Window*>(instanceData);
instance->callback(...);
}
// for convenience and consistency forward all callbacks into this
non-static method
void callback(...)
{
// process the callback message here inside the instance
}
}

if you get some unique identifier like a window handle in the callback
you can use a similar scheme to retrieve the instance from some kind of
map, e.g.:

struct Window
{
std::map<Handle, Window*> mapHandleWindow;
Window()
{
Handle handle = createWindow(..., &Window::staticCallback, this,
....);
mapHandleWindow[handle] = this;
}
static ... staticCallback(..., Handle handle,...)
{
Window* instance = mapHandleWindow[handle];
instance->callback();
}
void callback(...)
{
// process the callback message here inside the instance
}
}

for reusability you could create a template class to implement the
callback and use the curiously recurring template pattern. according to
the second example above:

template <typename ConcreteT>
struct WindowBase
{
std::map<Handle, ConcreteT*> mapHandleWindow;
WindowBase()
{
Handle handle = createWindow(..., &Window::staticCallback, this,
....);
mapHandleWindow[handle] = reinterpret_cast<ConcreteT>(this);
}
virtual ~WindowBase{}
static ... staticCallback(..., Handle handle,...)
{
ConcreteT* instance = mapHandleWindow[handle];
instance->callback();
}
}

you can use this template for any class that implements the callback
member function with matching arguments:

struct Window
: public WindowBase<Window>
{
virtual ~Window() {}
void callback(...)
{
// process messages here
}
}

this simple template works well with callbacks as long as you do not
inherit more than one level deep.

btw, there are still a few things to consider with the sketched code
above.

for example if it would be possible that the callback is triggered
instantly after the api call is finished you would have to ensure that
the concrete Window class is completely constructed before the
callback() member is being called, e.g. by moving the window creation
from the WindowBase constructor into another member function that you
would have to call manually after creating.

-- peter


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Steven E. Harris
Guest





PostPosted: Fri Dec 23, 2005 3:12 am    Post subject: Re: calling member functions from WNPROC callback functions Reply with quote

"PINTS" <rohit.markande (AT) gmail (DOT) com> writes:

Quote:
Is there a solution to this problem or do I have to make it static?

Take a look at the Windows functions SetWindowLongPtr,
GetWindowLongPtr, and the constants GWLP_USERDATA and GWLP_WNDPROC.

Sketching the solution, when your default window procedure receives
the WM_NCCREATE message, set GWLP_USERDATA to your "this" pointer
(probably provided to the window at creation time in a CREATESTRUCT),
and set GWLP_WNDPROC to a second window procedure that reads
GWLP_USERDATA to recover the "this" pointer and dispatches to the
member function.

When this second window procedure receives a WM_NCDESTROY message, it
should unbind GWLP_USERDATA and set GWLP_WNDPROC back to the initial
default window procedure.

Wow, that was exhausting.

--
Steven E. Harris

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Dave Harris
Guest





PostPosted: Fri Dec 23, 2005 3:23 am    Post subject: Re: calling member functions from WNPROC callback functions Reply with quote

[email]rohit.markande (AT) gmail (DOT) com[/email] (PINTS) wrote (abridged):
Quote:
I am trying to subclass a window and the I wanna keep the WNPROC as a
non-static member function of the class. The problem is that class
member functions have a "this" pointer as a hidden first parameter
which uniquely identifies a class object (keep in mind that an object
is a specific instantiation of a class). The API callback does not
know how to pass "*this." Is there a solution to this problem or do I
have to make it static? I am using the MSVC compiler.

To be portable you need to use the static, but you can make it a one-line
forwarding function.

With MSVC you can help efficiency by declaring a calling convention. This
article:

http://blogs.msdn.com/oldnewthing/archive/2004/01/09/49028.aspx

goes into some low-level detail. His recommended solution is like:

class SomeClass {
static DWORD CALLBACK s_ThreadProc(LPVOID lpParameter) {
return ((SomeClass*)lpParameter)->ThreadProc();
}

DWORD __stdcall ThreadProc() {
// ... fun stuff ...
}
};

-- Dave Harris, Nottingham, UK.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.