CALLBACK and non-static member function problem!
Author |
Message |
Sridha #1 / 13
|
 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 |
|
 |
James Brow #2 / 13
|
 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 |
|
 |
Sridha #3 / 13
|
 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 |
|
 |
Scot T Brenneck #4 / 13
|
 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 |
|
 |
Jochen Kalmbac #5 / 13
|
 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 |
|
 |
Fred Jackso #6 / 13
|
 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 |
|
 |
Fred Jackso #7 / 13
|
 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 |
|
 |
Fred Jackso #8 / 13
|
 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 |
|
 |
Scot T Brenneck #9 / 13
|
 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 |
|
 |
Scot T Brenneck #10 / 13
|
 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 |
|
 |
Craig Power #11 / 13
|
 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 |
|
 |
Fred Jackso #12 / 13
|
 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 |
|
 |
Fred Jackso #13 / 13
|
 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 |
|
|
|