Possible Duplicate:
Using a C++ class member function as a C callback function
I'm writing an object-oriented library using a C library (winpcap). I need to pass the callback function that is called when a network p开发者_开发技巧acket arrives as a function pointer. I would like to pass a member function pointer to winpcap, to keep my design object oriented and to allow for different objects to receive different packets. However member functions as far as I understand have a different calling convention, and thus cannot be passed to a C function. Is there a way to fix this. My experiments with boost::bind (which I hardly manage to use other than trial and error) are not fruitful.
Is there a way to change the calling convention of a member function?
This is the definition of the callback function I use now and the actual passing of it to winpcap
void pcapCallback( byte* param, const struct pcap_pkthdr* header, const byte* pkt_data );
pcap_loop( adhandle, 0, pcapCallback, NULL );
The pcap_loop just takes the name of the function (which is on the global scope at the moment). This is the definition of the function pointer parameter (3rd parameter of pcap_loop). Since this is third party code I can't really change this. I would have to have a member function that can take this form:
typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *);
As far as I understand it, the member function will be using thiscall and the c function pointer wants a cdecl
Kindly refer to detailed topic about
How to Implement a Callback to a static C++ Member Function ?
How to Implement a Callback to a non-static C++ Member Function ?
http://www.newty.de/fpt/callback.html
You can only pass static
member functions to a C API.
If you want to have a C API call a member function, you have to pass two pieces of data: the (static member) function and the object for which it is to be invoked.
Usually, C API callbacks have some form of "user data", often a void*
, through which you can tunnel your object's address:
// Beware, brain-compiled code ahead!
typedef void (*callback)(int data, void* user_data);
void f(callback cb, void* user_data);
class cpp_callback {
public:
virtual ~cpp_callback() {} // sometimes needed
void cb(int data) = 0;
callback* get_callback() const {return &cb_;}
private
static void cb_(int data, void* user_data)
{
cpp_callback* that = reinterpret_cast<my_cpp_callback*>(user_Data);
that->cb(data);
}
};
class my_callback {
public:
void cb(int data)
{
// deal with data
}
};
void g()
{
my_callback cb;
f(cb.get_callback(), &cb);
}
That pcapCallback
doesn't look as if it has user data, though, unless that's what param
is. If that's indeed the case, you'll have to store the callback object's address in some global variable before calling the API. Something like this:
// Beware, brain-compiled code ahead!
typedef void (*callback)(int data);
void f(callback cb);
class cpp_callback {
public:
cpp_callback() : the_old_cb_(this) {std::swap(the_cb_,the_old_cb_);}
virtual ~cpp_callback() {std::swap(the_cb_,the_old_cb_);}
void cb(int data) = 0;
callback* get_callback() const {return &cb_;}
private
static cpp_callback* the_cb_;
cpp_callback* the_old_cb_;
static void cb_(int data, void* user_data)
{
the_cb_->cb(data);
}
};
class my_callback {
public:
void cb(int data) { /* deal with data */ }
};
void g()
{
my_callback cb;
f(cb.get_callback(), &cb);
}
As always with global data, this is perilous if more than one instance of the callback is alive. I have tried to minimize the harm so that it works if their lifetimes are nested. Anything else, though, will hurt.
精彩评论