Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

SetTimer() w/Callback to C++ Member Function

831 views
Skip to first unread message

Bret Pehrson

unread,
Jun 27, 1996, 3:00:00 AM6/27/96
to Thomas W. McAlees
Thomas W. McAlees wrote:
> I'm trying to set a windows timer with a callback to a member function in
> my C++ class. The only way I can get this to work is to make the member
> function static. But when I do this I am unable to reference any
> non-static members of the class in the callback function. Is their a way
> to set a timer to callback to a non-static member function?
> Tom McAlees
> CSC <tmca...@csci.csc.com>

Nay, you must have it static. If you are using the timer without a window,
your are going to have some problems solving this one in a clean way. That is
because the standard SetTimer fn does not allow the user specify user-defined
data available to the callback. If you are writing to Win32, you could used
multimedia services timeSetEvent, and pass the class instance (this pointer)
as the user data. Then in the callback, dereference the parameter and access
your class that way.

The other, probably more appropriate method, albeit a bit more convoluted is
to create an internal hidden window with your class, and use the SetTimer with
that window. Create the internal window with 4 extra bytes (sizeof
(YOUR_CLASS FAR *)) and then set those extra bytes to the value of you class
instance (this pointer). Then, in your window proc, get the extra bytes and
dereference to have access to your class instance member data. You can also
accomplish the same thing by using window properties rather than extra bytes.

One other method, it to create a mapping function that maps an arbitrary value
to another arbitrary value. Then, call this function with the id of the timer
you wish to set, as well as with the class instance parameter. Then, in your
timer callback, query the mapped second parameter based on the timer id. Once
again, dereference the returned value and access your class. Be careful when
using this method under Win32, you must take thread-local storage and
synchronizations issues into account.

--
Bret Pehrson mailto:Br...@strata3d.com
*Please respond to newsgroup unless specified otherwise
--

Kit Kauffmann

unread,
Jun 27, 1996, 3:00:00 AM6/27/96
to
In article <01bb6395.c156f8c0$6201...@tmcalees.roc.csci.csc.com> "Thomas W. McAlees" <tmca...@csci.csc.com> writes:

>Help!

>I'm trying to set a windows timer with a callback to a member function in
>my C++ class. The only way I can get this to work is to make the member
>function static. But when I do this I am unable to reference any
>non-static members of the class in the callback function. Is their a way
>to set a timer to callback to a non-static member function?

>Thanks.

>Tom McAlees
>CSC <tmca...@csci.csc.com>


The pattern I've been using for static/global functions to access object data:

The technique I use is to simply store the current 'this' in a static
variable, which the static function can then access. This is, for me,
verging on a pattern:

Problem: Global or static functions (like Windows callbacks) need to access
different objects based on state, current active window, whatever.

Forces: (example) The Windows functions, like EnumChildWindows, perform a
tedious but oft-used capability which you want to use in the context of
objects.

Solution: store 'this' in a static/global variable which the global/static
function can access, thereby gaining access to the 'current object'

Example: I need many of my windows to see the plus/minus keys, to
provide a keyboard alternative to scrollbars. But the ProcessMessageFilter
function (or a SetWindowsHookEx callback - same thing, really) is the easiest
place for me to pick these up. So, all those windows are derived from a
common ancestor, which contains all the machinery to handle those scrolling
keyboard messages, if I could just forward them to the right dialog.

Ignoring the fact that GetActiveWindow tells me that anyway (hey, this is just
an example :), my common ancestor looks like this:

class BaseWindow
{
...
static BOOL MessageFilter( int code, LPMSG lpMsg );

private:

KeyboardScrollingData m_Data;
KeyboardScrollingData* m_pOldData;

static KeyboardScrollingData* m_pData;
};

the BaseWindow ctor saves the current static pointer so the dtor can restore
it, and points the static pointer at the object's data:

BaseWindow::BaseWindow()
{
m_pOldData = m_pData;
m_pData = &m_Data;
}

The dtor just replaces the pointer the ctor saved

BaseWindow::~BaseWindow()
{
m_pData = m_pOldData;
}

The static MessageFilter function now accesses the correct data:

BOOL BaseWindow::MessageFilter( int code, LPMSG lpMsg )
{
if( m_pData )
return m_pData->DoSomething( code, lpMsg );

return FALSE;
}

And then the ProcessMessageFilter (or whatever global/static function it is)
can simply call it like:

if( BaseWindow::MessageFilter( code, pMsg ) )
return TRUE;


Kit Kauffmann - ki...@mudshark.sunquest.com
AKA 73363,447 (Compu$erve)

Madness takes its toll. Please have exact change.

(Finger me for my public key)

Mike Philben

unread,
Jun 28, 1996, 3:00:00 AM6/28/96
to
In article <31D2AE...@strata3d.com>, br...@strata3d.com says...
/
/Thomas W. McAlees wrote:
// I'm trying to set a windows timer with a callback to a member function in
// my C++ class. The only way I can get this to work is to make the member
// function static. But when I do this I am unable to reference any
// non-static members of the class in the callback function. Is their a way
// to set a timer to callback to a non-static member function?
// Tom McAlees
// CSC <tmca...@csci.csc.com>


You need a static -- no choice. In the past, I've set the timer Id to the
'this' pointer of the appropriate class. When the static function sees the
timer fire, it has the pointer to the class.

Mike Philben


Dave Lloyd

unread,
Jun 28, 1996, 3:00:00 AM6/28/96
to Thomas W. McAlees
Thomas W. McAlees wrote:
>
> Help!

>
> I'm trying to set a windows timer with a callback to a member function in
> my C++ class. The only way I can get this to work is to make the member
> function static. But when I do this I am unable to reference any
> non-static members of the class in the callback function. Is their a way
> to set a timer to callback to a non-static member function?
>
> Thanks.
>
> Tom McAlees
> CSC <tmca...@csci.csc.com>

Tom,
I am not a timer expert, but I have run into this type of problem
before. The problem stems from the function interface of the
SetTimer and Timer procedure.

void CALLBACK TimerProc(HWND hwndWindowForTimer,
UINT message,
UINT idTimer,
DWORD dwTime
)


Non-static C++ member functions pass an implicit object pointer
called this as the *very* first paramter, so if you try to use
a non-static member function as a timer proc, windows will barf
at you. I have found a solution that seems to have worked for
me (for the most part). Class CWnd has a static member function
called FromHandle(HWND). You pass the handle the window, and
FromHandle returns a pointer to the CWnd Object that that handle
is attached to. You could call this function inside your
timer proc to get the pointer to the CWnd and access non-static
members.

Hope this helps,
David Lloyd
personal mail - sd...@teal.csn.net
business mail - address from above.

David A. Mair

unread,
Jul 3, 1996, 3:00:00 AM7/3/96
to

"Thomas W. McAlees" <tmca...@csci.csc.com> wrote:

>Help!

>I'm trying to set a windows timer with a callback to a member function in
>my C++ class. The only way I can get this to work is to make the member
>function static. But when I do this I am unable to reference any
>non-static members of the class in the callback function. Is their a way
>to set a timer to callback to a non-static member function?

Tom,

The most common way that I have seen to do this is to provide a means
of mapping some information received in your static function with a
particular instance of the class. For example, in Windows you can
identify the timer with an ID. You can use a static array (or two) in
your class to map timer IDs to pointers to objects of your class.
Then your static WM_TIMER handler can take the ID find out the object
and call a non-static member. For example:

Regards
David.


0 new messages