CALLBACK and non-static member function problem! 
Author Message
 CALLBACK and non-static member function problem!

Hi all,
Here is my problem. For now, I have a dummy class (Let's call it class A)
which just makes an object of a class (class B)which is inherits CDialog.
Now, B has some private member variables which are accessed by public
accessor methods. I am trying to put a Timer on B which is going to do
something every so often. It cannot compile because I am trying to call a
non-static Get1() and Get2() in TimerProc2(). But, if I convert TimerProc
and ThreadProc to Retrieval::TimerProc and Retrieval::ThreadProc, then I get
the following error.

 "Retrieval.cpp(282) : error C2440: 'type cast' : cannot convert from '' to
'void (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,unsigned
long)'
        None of the functions with this name in scope match the target type
Retrieval.cpp(323) : error C2664: 'CreateThread' : cannot convert parameter
3 from 'unsigned long (void *)' to 'unsigned long (__stdcall *)(void *)'
        None of the functions with this name in scope match the target type
Error executing cl.exe."

Any help would be appreciated.

Thanks,
Sridhar.

CodeSnippet from B.h:

class Retrieval : public CDialog
{
public:
CString Get1();
CString Get2();

private:
 CString var1;
 CString var2;

Quote:
}

Code Snipppet From B.cpp:

CString Get1()
{
 return var1; //Where var1 is a private variable.

Quote:
}

CString Get2()
{
 return var2; //Where var2 is a private variable.

Quote:
}

VOID CALLBACK TimerProc2(
  HWND hwnd,         // handle to window
  UINT uMsg,    // WM_TIMER message
  UINT_PTR idEvent,  // timer identifier
  DWORD dwTime       // current system time
  )
{
 Retrieval::DoSomething(Retrieval::Get1(), Retrieval::Get2());

Quote:
}

DWORD WINAPI ThreadProc(
  LPVOID lpParameter   // thread data
  )
{
 UINT uiTimer = ::SetTimer(NULL, 12, 60000, (TIMERPROC)TimerProc2);
 MSG msg;
 while (GetMessage(&msg, NULL, 0, 0))
 {
  DispatchMessage(&msg);
 }
 ::KillTimer(NULL, uiTimer);
 return 0;

Quote:
}

void Retrieval::OnGetMail()
{
 // TODO: Add your control notification handler code here

 HANDLE hThread = CreateThread(NULL, NULL, ThreadProc, NULL, NULL, NULL);
 CloseHandle(hThread);

 //Sleep(30000);
 this->ShowWindow(SW_SHOWMINIMIZED);

Quote:
}



Mon, 23 Aug 2004 02:08:01 GMT  
 CALLBACK and non-static member function problem!
Uhh...
Make the callback a function static function of your class.

James.
--
www.catch22.uk.net
Free win32 software, sourcecode, and tutorials
------
Please remove "NOSPAM" when replying.


Quote:
> Hi all,
> Here is my problem. For now, I have a dummy class (Let's call it class A)
> which just makes an object of a class (class B)which is inherits CDialog.
> Now, B has some private member variables which are accessed by public
> accessor methods. I am trying to put a Timer on B which is going to do
> something every so often. It cannot compile because I am trying to call a
> non-static Get1() and Get2() in TimerProc2(). But, if I convert TimerProc
> and ThreadProc to Retrieval::TimerProc and Retrieval::ThreadProc, then I
get
> the following error.

>  "Retrieval.cpp(282) : error C2440: 'type cast' : cannot convert from ''
to
> 'void (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,unsigned
> long)'
>         None of the functions with this name in scope match the target
type
> Retrieval.cpp(323) : error C2664: 'CreateThread' : cannot convert
parameter
> 3 from 'unsigned long (void *)' to 'unsigned long (__stdcall *)(void *)'
>         None of the functions with this name in scope match the target
type
> Error executing cl.exe."

> Any help would be appreciated.

> Thanks,
> Sridhar.

> CodeSnippet from B.h:

> class Retrieval : public CDialog
> {
> public:
> CString Get1();
> CString Get2();

> private:
>  CString var1;
>  CString var2;
> }

> Code Snipppet From B.cpp:

> CString Get1()
> {
>  return var1; //Where var1 is a private variable.
> }

> CString Get2()
> {
>  return var2; //Where var2 is a private variable.
> }

> VOID CALLBACK TimerProc2(
>   HWND hwnd,         // handle to window
>   UINT uMsg,    // WM_TIMER message
>   UINT_PTR idEvent,  // timer identifier
>   DWORD dwTime       // current system time
>   )
> {
>  Retrieval::DoSomething(Retrieval::Get1(), Retrieval::Get2());
> }

> DWORD WINAPI ThreadProc(
>   LPVOID lpParameter   // thread data
>   )
> {
>  UINT uiTimer = ::SetTimer(NULL, 12, 60000, (TIMERPROC)TimerProc2);
>  MSG msg;
>  while (GetMessage(&msg, NULL, 0, 0))
>  {
>   DispatchMessage(&msg);
>  }
>  ::KillTimer(NULL, uiTimer);
>  return 0;

> }

> void Retrieval::OnGetMail()
> {
>  // TODO: Add your control notification handler code here

>  HANDLE hThread = CreateThread(NULL, NULL, ThreadProc, NULL, NULL, NULL);
>  CloseHandle(hThread);

>  //Sleep(30000);
>  this->ShowWindow(SW_SHOWMINIMIZED);
> }



Mon, 23 Aug 2004 02:33:38 GMT  
 CALLBACK and non-static member function problem!
James,
In that case, I get a "'TimerProc2' : 'static' should not be used on member
functions defined at file scope" error.

Sridhar.


Quote:
> Uhh...
> Make the callback a function static function of your class.

> James.
> --
> www.catch22.uk.net
> Free win32 software, sourcecode, and tutorials
> ------
> Please remove "NOSPAM" when replying.



> > Hi all,
> > Here is my problem. For now, I have a dummy class (Let's call it class
A)
> > which just makes an object of a class (class B)which is inherits
CDialog.
> > Now, B has some private member variables which are accessed by public
> > accessor methods. I am trying to put a Timer on B which is going to do
> > something every so often. It cannot compile because I am trying to call
a
> > non-static Get1() and Get2() in TimerProc2(). But, if I convert
TimerProc
> > and ThreadProc to Retrieval::TimerProc and Retrieval::ThreadProc, then I
> get
> > the following error.

> >  "Retrieval.cpp(282) : error C2440: 'type cast' : cannot convert from ''
> to
> > 'void (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,unsigned
> > long)'
> >         None of the functions with this name in scope match the target
> type
> > Retrieval.cpp(323) : error C2664: 'CreateThread' : cannot convert
> parameter
> > 3 from 'unsigned long (void *)' to 'unsigned long (__stdcall *)(void *)'
> >         None of the functions with this name in scope match the target
> type
> > Error executing cl.exe."

> > Any help would be appreciated.

> > Thanks,
> > Sridhar.

> > CodeSnippet from B.h:

> > class Retrieval : public CDialog
> > {
> > public:
> > CString Get1();
> > CString Get2();

> > private:
> >  CString var1;
> >  CString var2;
> > }

> > Code Snipppet From B.cpp:

> > CString Get1()
> > {
> >  return var1; //Where var1 is a private variable.
> > }

> > CString Get2()
> > {
> >  return var2; //Where var2 is a private variable.
> > }

> > VOID CALLBACK TimerProc2(
> >   HWND hwnd,         // handle to window
> >   UINT uMsg,    // WM_TIMER message
> >   UINT_PTR idEvent,  // timer identifier
> >   DWORD dwTime       // current system time
> >   )
> > {
> >  Retrieval::DoSomething(Retrieval::Get1(), Retrieval::Get2());
> > }

> > DWORD WINAPI ThreadProc(
> >   LPVOID lpParameter   // thread data
> >   )
> > {
> >  UINT uiTimer = ::SetTimer(NULL, 12, 60000, (TIMERPROC)TimerProc2);
> >  MSG msg;
> >  while (GetMessage(&msg, NULL, 0, 0))
> >  {
> >   DispatchMessage(&msg);
> >  }
> >  ::KillTimer(NULL, uiTimer);
> >  return 0;

> > }

> > void Retrieval::OnGetMail()
> > {
> >  // TODO: Add your control notification handler code here

> >  HANDLE hThread = CreateThread(NULL, NULL, ThreadProc, NULL, NULL,
NULL);
> >  CloseHandle(hThread);

> >  //Sleep(30000);
> >  this->ShowWindow(SW_SHOWMINIMIZED);
> > }



Mon, 23 Aug 2004 05:04:53 GMT  
 CALLBACK and non-static member function problem!
Sridhar,
        CALLBACK functions are not prototyped to have the hidden 'this' pointer of a
member function, so cannot access members of a class.  Making the CALLBACK
function a static member of the class doesn't help, because it still has no
'this' to get to object members (there is no object in the context of a
callback).
        For ThreadProcs, you can get around this by passing a pointer to a class object
as the LPVOID parameter.  The thread can then cast that back to a class pointer,
and call a public member function to do the actual thread work.
        For TimerProcs, however, there is no good workaround, since you can't pass a
pointer to them.  You'd have to save the object pointer in some file-scope
variable so the TimerProc could get to it.  That would only work if there is
only one object of the class, however.  The better solution is to not use a
TimerProc, but handle the WM_TIMER message instead.  Since you are using MFC,
this is easy.  Just add a handler for WM_TIMER to your class (if it's derived
from CWnd).  Then when the message is sent, your handler code executes within
the context of a class object.


Mon, 23 Aug 2004 13:36:42 GMT  
 CALLBACK and non-static member function problem!

Quote:
> Here is my problem. For now, I have a dummy class (Let's call it class A)
> which just makes an object of a class (class B)which is inherits CDialog.
> Now, B has some private member variables which are accessed by public
> accessor methods. I am trying to put a Timer on B which is going to do
> something every so often. It cannot compile because I am trying to call a
> non-static Get1() and Get2() in TimerProc2(). But, if I convert TimerProc
> and ThreadProc to Retrieval::TimerProc and Retrieval::ThreadProc, then I
get
> the following error.

I dont know if this helps, but you can make callbakcs into a class without
static members. For this you have to use templates... Here is an small
example:

template<class T>
class TCallbacker
{
  typedef void (T::*pFunction)(void);
  pFunction pFunc;
  T *This;

public:
  TCallbacker(T *T,pFunction p)
    : pFunc(p),This(T)
  {
  }
  void call()
  {
    (This->*pFunc)();
  }

Quote:
};

class CallbackClass
{
public:
  virtual void Callback(void)
  {
    _tprintf(_T("Callback called!\n"));
  }

Quote:
};

int _tmain(int argc, _TCHAR* argv[])
{
  CallbackClass a;
  TCallbacker<CallbackClass> b(&a,CallbackClass::Callback);
  b.call();
 return 0;

Quote:
}

Greetings
  Jochen


Mon, 23 Aug 2004 14:52:29 GMT  
 CALLBACK and non-static member function problem!
See below.



Quote:
> Sridhar,
> CALLBACK functions are not prototyped to have the hidden 'this' pointer of
a
> member function, so cannot access members of a class.

Absolutely correct for non-static methods.

Quote:
> Making the CALLBACK
> function a static member of the class doesn't help, because it still has
no
> 'this' to get to object members (there is no object in the context of a
> callback).

If I'm you're claiming what I think you are, this is incorrect.
I use static methods all the time for callbacks and thread procs.
It works fine, and aids encapsulation.  Think about it.  You can
call static methods without having a class instance (using the
class::method() syntax) - so clearly there is no hidden "this"
parameter.

Quote:
> For ThreadProcs, you can get around this by passing a pointer to a class
object
> as the LPVOID parameter.  The thread can then cast that back to a class
pointer,
> and call a public member function to do the actual thread work.

Exactly.  I make the static method call a non-static method
using the "this" pointer thus passed - then the non-static
method can start using class member data and calling other
methods.

Quote:
> For TimerProcs, however, there is no good workaround, since you can't pass
a
> pointer to them.  You'd have to save the object pointer in some file-scope
> variable so the TimerProc could get to it.  That would only work if there
is
> only one object of the class, however.

I know - it's a bad callback design - no user parameter provided
in the function that sets the callback.  BTW, the multimedia
timers (see timeSetEvent) are designed better - a user parameter
is provided.

Quote:
> The better solution is to not use a
> TimerProc, but handle the WM_TIMER message instead.  Since you are using
MFC,
> this is easy.  Just add a handler for WM_TIMER to your class (if it's
derived
> from CWnd).  Then when the message is sent, your handler code executes
within
> the context of a class object.



Mon, 23 Aug 2004 21:40:55 GMT  
 CALLBACK and non-static member function problem!
You have to put the "static" qualifier in the method declaration
inside the class declaration - not in the method definition if
the latter is outside the class declaration.

It doesn't make a difference to your problem, though.  TimerProc2
should work equally well as a standalone function or a static
method.

By the way, if you use any C/C++ runtime library functions in
your thread proc, it won't work safely unless you use
_beginthread or _beginthreadex to start it (instead of
CreateThread).  Otherwise, CreateTHread is OK.


Quote:
> James,
> In that case, I get a "'TimerProc2' : 'static' should not be used on
member
> functions defined at file scope" error.

> Sridhar.



> > Uhh...
> > Make the callback a function static function of your class.

> > James.
> > --
> > www.catch22.uk.net
> > Free win32 software, sourcecode, and tutorials
> > ------
> > Please remove "NOSPAM" when replying.



> > > Hi all,
> > > Here is my problem. For now, I have a dummy class (Let's call it class
> A)
> > > which just makes an object of a class (class B)which is inherits
> CDialog.
> > > Now, B has some private member variables which are accessed by public
> > > accessor methods. I am trying to put a Timer on B which is going to do
> > > something every so often. It cannot compile because I am trying to
call
> a
> > > non-static Get1() and Get2() in TimerProc2(). But, if I convert
> TimerProc
> > > and ThreadProc to Retrieval::TimerProc and Retrieval::ThreadProc, then
I
> > get
> > > the following error.

> > >  "Retrieval.cpp(282) : error C2440: 'type cast' : cannot convert from
''
> > to
> > > 'void (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,unsigned
> > > long)'
> > >         None of the functions with this name in scope match the target
> > type
> > > Retrieval.cpp(323) : error C2664: 'CreateThread' : cannot convert
> > parameter
> > > 3 from 'unsigned long (void *)' to 'unsigned long (__stdcall *)(void
*)'
> > >         None of the functions with this name in scope match the target
> > type
> > > Error executing cl.exe."

> > > Any help would be appreciated.

> > > Thanks,
> > > Sridhar.

> > > CodeSnippet from B.h:

> > > class Retrieval : public CDialog
> > > {
> > > public:
> > > CString Get1();
> > > CString Get2();

> > > private:
> > >  CString var1;
> > >  CString var2;
> > > }

> > > Code Snipppet From B.cpp:

> > > CString Get1()
> > > {
> > >  return var1; //Where var1 is a private variable.
> > > }

> > > CString Get2()
> > > {
> > >  return var2; //Where var2 is a private variable.
> > > }

> > > VOID CALLBACK TimerProc2(
> > >   HWND hwnd,         // handle to window
> > >   UINT uMsg,    // WM_TIMER message
> > >   UINT_PTR idEvent,  // timer identifier
> > >   DWORD dwTime       // current system time
> > >   )
> > > {
> > >  Retrieval::DoSomething(Retrieval::Get1(), Retrieval::Get2());
> > > }

> > > DWORD WINAPI ThreadProc(
> > >   LPVOID lpParameter   // thread data
> > >   )
> > > {
> > >  UINT uiTimer = ::SetTimer(NULL, 12, 60000, (TIMERPROC)TimerProc2);
> > >  MSG msg;
> > >  while (GetMessage(&msg, NULL, 0, 0))
> > >  {
> > >   DispatchMessage(&msg);
> > >  }
> > >  ::KillTimer(NULL, uiTimer);
> > >  return 0;

> > > }

> > > void Retrieval::OnGetMail()
> > > {
> > >  // TODO: Add your control notification handler code here

> > >  HANDLE hThread = CreateThread(NULL, NULL, ThreadProc, NULL, NULL,
> NULL);
> > >  CloseHandle(hThread);

> > >  //Sleep(30000);
> > >  this->ShowWindow(SW_SHOWMINIMIZED);
> > > }



Mon, 23 Aug 2004 21:51:46 GMT  
 CALLBACK and non-static member function problem!
Here is how I do this kind of thing in VC6; should work
as well in VC7 (excerpted/adapted from working code but
excerpting edits not rigorously checked):

class CMyClass
{
public:
  /* ctor */            CMyClass();
  ...

private:
  void                  Thread();
  static UINT __stdcall ThreadHelper(void* arg);
  void                  Timer();
  static void CALLBACK  TimerHelper(UINT uID, UINT uMsg,
                                    DWORD dwUser,
                                    DWORD dw1, DWORD dw2);
  HANDLE   m_threadHandle;
  UINT     m_threadId;
  MMRESULT m_timerId;
  ...

Quote:
};

/* ctor */
CMyClass::CMyClass()
{
  unsigned long temp = ::_beginthreadex(NULL, 0, ThreadHelper,
                                        this, 0, &m_ThreadId);
  m_threadHandle = reinterpret_cast<HANDLE>(temp);
  m_timerId = ::timeSetEvent(1, 0, TimerHelper,
                             reinterpret_cast<DWORD>(this),
                             TIME_PERIODIC);
  ...

Quote:
}

// The "real" non-static thread proc method.
void
CMyClass::Thread()
{
  ...

Quote:
}

// The static thread proc helper method.
// Just retrieves the "this" pointer and calls the
// "real" non-static thread proc method.
UINT __stdcall
CMyClass::ThreadHelper(void* arg)
{
  CMyClass* thisPtr = static_cast<CMyClass*>(arg);
  thisPtr->Thread();
  return 0;

Quote:
}

// The "real" non-static timer proc method.
void
CMyClass::Timer()
{
  ...

Quote:
}

// The static timer proc helper method.
// Just retrieves the "this" pointer and calls the
// "real" non-static timer proc method.
void CALLBACK
CMyClass::TimerHelper(UINT uID, UINT uMsg, DWORD dwUser,
                      DWORD dw1, DWORD dw2)
{
  CMyClass* thisPtr = reinterpret_cast<CMyClass*>(dwUser);
  thisPtr->Timer();
Quote:
}



Tue, 24 Aug 2004 00:06:59 GMT  
 CALLBACK and non-static member function problem!
I'm not implying that you can't use a static member for a TimerProc, only that
it doesn't help solve the problem of accessing object member-specific data from
the callback function.  This is because, as you acknowledged later in your
reply, the SetTimer doesn't provide for a 32-bit user value to be passed back
(except for the timer ID).  Your solution of using a multimedia timer
(timeSetEvent) instead is clever.
Quote:
>> Making the CALLBACK
>> function a static member of the class doesn't help, because it still has no
>> 'this' to get to object members (there is no object in the context of a
>> callback).

> If I'm you're claiming what I think you are, this is incorrect.
> I use static methods all the time for callbacks and thread procs.
> It works fine, and aids encapsulation.  Think about it.  You can
> call static methods without having a class instance (using the
> class::method() syntax) - so clearly there is no hidden "this"
> parameter.



Tue, 24 Aug 2004 02:38:48 GMT  
 CALLBACK and non-static member function problem!
Jochen,
        Can you show how this method would assist in the case of the SetTimer callback
problem?

Is it just a coincidence that your name, Kalmbach, sounds like Callback?  ;)



Tue, 24 Aug 2004 02:42:54 GMT  
 CALLBACK and non-static member function problem!

Quote:

> I'm not implying that you can't use a static member for a TimerProc, only that
> it doesn't help solve the problem of accessing object member-specific data from
> the callback function.  This is because, as you acknowledged later in your
> reply, the SetTimer doesn't provide for a 32-bit user value to be passed back
> (except for the timer ID).

A workaround for this is to generate a map of timer IDs to class
instances.  This is how I dealt with the issue in a VB implementation.


Tue, 24 Aug 2004 03:48:48 GMT  
 CALLBACK and non-static member function problem!
OK, I was misinterpreting what you said.  We are definitely
in sync.



Quote:
> I'm not implying that you can't use a static member for a TimerProc, only
that
> it doesn't help solve the problem of accessing object member-specific data
from
> the callback function.  This is because, as you acknowledged later in your
> reply, the SetTimer doesn't provide for a 32-bit user value to be passed
back
> (except for the timer ID).  Your solution of using a multimedia timer
> (timeSetEvent) instead is clever.

> >> Making the CALLBACK
> >> function a static member of the class doesn't help, because it still
has no
> >> 'this' to get to object members (there is no object in the context of a
> >> callback).

> > If I'm you're claiming what I think you are, this is incorrect.
> > I use static methods all the time for callbacks and thread procs.
> > It works fine, and aids encapsulation.  Think about it.  You can
> > call static methods without having a class instance (using the
> > class::method() syntax) - so clearly there is no hidden "this"
> > parameter.



Tue, 24 Aug 2004 04:56:56 GMT  
 CALLBACK and non-static member function problem!
Wow, that's right!  std::map would work.


Quote:

> > I'm not implying that you can't use a static member for a TimerProc,
only that
> > it doesn't help solve the problem of accessing object member-specific
data from
> > the callback function.  This is because, as you acknowledged later in
your
> > reply, the SetTimer doesn't provide for a 32-bit user value to be passed
back
> > (except for the timer ID).

> A workaround for this is to generate a map of timer IDs to class
> instances.  This is how I dealt with the issue in a VB implementation.



Tue, 24 Aug 2004 04:59:32 GMT  
 
 [ 13 post ] 

 Relevant Pages 

1. Getting pointer to non-static member function from C callback function

2. Using Non-Static Callback Functions as member Functions VC5.0

3. Using Non-Static Callbacks as member functions VC 5.0

4. One Problem in Calling Static function from Non static function

5. illegal call of non-static member function

6. using non-static member functions using delegates

7. illegal call of non-static member function

8. illegal call of non-static member function *HELP*

9. iilegal call of non-static member function

10. illegal call of non-static member function

11. Illegal call of non-static member function (error)?

12. illegal call of non-static member function

 

 
Powered by phpBB® Forum Software