Unmanaged C code:
typedef void(read_fun_t)(void* user_data, const char* data, int data_len);
int native_consume_all(native_handler handler, void* user_data, read_fun_t* read_fun);
Managed C++ code:
public delegate void ConsumeCallback(String^ str);
public
ref class Example
{
public:
void ConsumeAll(ConsumeCallback^ callback);
}
/* Some unmanaged code is needed so native_consume_all can
* call ConsumeCallback delegate */
#pragma unmanaged
typedef void(*NativeConsumeCallbackBridgeDelegate)(const char*, int);
void ConsumeAllHelper(void* p, const char* data, int data_len)
{
/* Here `p` is a marshalled pointer to ConsumeCallbackBridgeDelegate */
auto callback = static_cast<NativeConsumeCallbackBridgeDelegate>(p);
callback(data, data_len);
}
#pragma managed
public delegate void ConsumeCallbackBridgeDelegate(const char*, int);
/* This class is needed as a bridge between the native function ConsumeAllHelper
* which get a pointer to char, and ConsumeCallback delegate, which handles
* managed String */
ref class ConsumeCallbackBridge {
public:
ConsumeCallback^ callback;
void Call(const char* nativeStr, int nativeStrLen) {
/* Marshal works with null terminated strings, so here we are creating
* a temporary null terminated string */
std::string tmpStr(nativeStr, nativeStr + nativeStrLen);
System::String^ managedStr = msclr::interop::marshal_as<System::String^>(tmpStr.c_str());
callback->Invoke(managedStr);
}
};
void Example::ConsumeAll(ConsumeCallback^ callback)
{
/* To have the delegate ConsumeCallback being called by
* native_consume_all we have to play with pointers.
* ConsumeCallbackBridge is also needed to convert pointer to
* char to a managed String. */
ConsumeCallbackBridge^ bridge = gcnew ConsumeCallbackBridge();
bridge->callback = callback;
ConsumeCallbackBridgeDelegate^ del = gcnew ConsumeCallbackBridgeDelegate(bridge, &ConsumeCallbackBridge::Call);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(del);
/* rfid_manager_consume_all accept a pointer to anything that will be
* passed to the callback as the first parameter. Here we pass the
* delegate as a raw pointer, so it can be cast back to a function
* pointer in ConsumeAllHelper */
native_consume_all(handler, ip.ToPointer(), ConsumeAllHelper);
}