yes,:D .it works well.
Printable View
yes,:D .it works well.
of course,the following is code.but i still cannot decalre the static variable in class scope,when i do it ,the VC7 always report various error.either not define the variable or cannot be interped by metaobject.
Code:
///////////////////////storescpThread.h typedef (*STORESCPCALLBACK)(void *callbackData, char* statusDetail); static unsigned long classAddress; { Q_OBJECT public: ~storescpThread(); protected: void run(); static void emitMsg( unsigned long user_value,char * filename) { storescpThread* pthis = (storescpThread*)user_value; // pthis->setText(state,filename); } void mycallback(); private : QTextEdit * textEdit; static void storeSCPCallback(void *callbackData, char* statusDetail); void setText(char * state,char * name); }; ///////////////////////storeScpThread.cpp { textEdit=txtEdit; classAddress =(unsigned long)this ; } void storescpThread:: storeSCPCallback(void *callbackData, char* statusDetail) { emitMsg(classAddress,statusDetail); return ; } void storescpThread::mycallback() { myThirdCallFunction(storeSCPCallback); //the third party function, which used callback as param }
Oh God.... This is some kind of madness... I won't even ask what happens if you have two instances of the thread class or what happens if you delete the object without unregistering the callback...
Why don't you move the callback method outside the class so that it's a standalone function instead? You can't call any of the nonstatic class member anyway, so what's the point of having this static method part of the thread class?
Implementing some Win32 Callback is quite necessary in some cases to make *good* use of Win32 API.
Found this old thread on google. What I did is to add a global pointer to the current class, like this:
in the header file
Code:
class MyClass { public: MyClass (); ~MyClass (); private: static void CALLBACK MyCallback (int nMsg); void emitMySignal (int nMsg); signals: mySignal (int nMsg); }
in the cpp file, at the beginning define a global pointer to the current class
Code:
MyClass* pThis; MyClass:MyClass () { pThis = this; } void MyClass::MyCallback (int nMsg) { pThis->emitMySignal(nMsg); } void MyClass::emitMySignal (int nMsg) { emit mySignal (nMsg); }
I had a very similar situation with the libusb library. If I wanted to have callbacks and use the async model they have laid out I couldn't figure out a better way.
Is this the best way still, at least when using existing c libraries?
In my experience with callbacks from various libraries, there's usually a method for storing a pointer or user data that is presented to the callback. I've used that capability in the past to pass a pointer to the class instance, so that even though the static member callback function doesn't have a "this" pointer, the method would be able to execute any class functions or class data, etc.
Easier to give you an example. Here's what I've used for libCurl when I've used its callback functions.
header file that declares the static member function:
cpp file that implements the static member functiion:Code:
private: static size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream);
and finally the cpp code that invokes libcurl, specifies the callback, and sets the user data pointer, etc:Code:
size_t libFlickr::write_function( void *ptr, size_t size, size_t nmemb, void *stream) { size_t total = size * nmemb; libFlickr* pFlickr = reinterpret_cast<libFlickr*>(stream); if (pFlickr) { pFlickr->some_public_method(); return total; } else { return 0; } }
In the case of libcurl, it passes the CURLOPT_WRITEDATA value to the callback function as the void* stream argument. Every other use I've had for callback functions has provided a way to pass data that is given back to the callback function, so passing the "this" pointer results in the callback receiving the instance pointer.Code:
m_code = curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, libFlickr::write_function); m_code = curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, (void*)this); m_code = curl_easy_perform(m_pCurl);
Hope that helps.
Strange, I edited it for you.
Cheers,
_
Good stuff. I'm just learning working with this type of library. Appreciate that. I now noticed it does indeed offer a void* user_data parameter in the function to pass through. I just overlooked that completely.