views:

101

answers:

3

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 packet 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

+2  A: 

You can only pass static member functions to a C API.

Paul R
well, this is incorrect, see other answers and answers to the duplicate question. There are ways around this problem, and those ways is what I was after.
ufotds
@ufotds: While it is true that you can use clever tricks to make `static` member functions call non-`static` ones, it is also true that you can only pass (pointers to) `static` member functions to C APIs. So Paul is indeed correct, although there's more to this than he wrote.
sbi
ok, obviously the title of my question should have mentioned a non-static member function... A static function in this respect is about as good (marginally better) as a global function that would call a member function. Don't take things to literally.
ufotds
+1  A: 

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.

sbi
+2  A: 

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

Pardeep