I have some functions in c and I would use this in a .net application. For this, I wrote a Wrapper class with C ++ / cli.
The c-interface has a callback function and is wrapped in a .net delegate.
But how can I free unmanaged resources for the gcHandle callback? Is IsAllocated and Free allowed from GCHandle in the finalizer? Because it is a managed ressource, and is it possible that gc has already released it?
Here is the code for the c interface:
// C functions
And here is the .net wrapper:
// .net wrapper (c++/cli) public ref class MyWrapper { public: MyWrapper() { RegisterCallback(); } // Destructor. ~MyWrapper() { this->!MyWrapper(); } protected: // Finalizer. !MyWrapper() { RemoveCallback(); // <- Is this safe? // ... release other unmanaged ressorces } private: void RegisterCallback() { uint32_t id = 0; callbackDelegate_ = gcnew MyCallbackDelegate(this, &MyWrapper::OnCallback); callbackHandle_ = System::Runtime::InteropServices::GCHandle::Alloc(callbackDelegate_); System::IntPtr delegatePointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(callbackDelegate_); register_callback(static_cast<my_native_callback>(delegatePointer.ToPointer()), &id); callbackId_ = id; } void RemoveCallback() { if (callbackId_) { remove_callback(callbackId_); callbackId_ = 0; } if (callbackHandle_.IsAllocated) // It this safe in the finalizer? { callbackHandle_.Free(); // It this safe in the finalizer? } callbackDelegate_ = nullptr; // It this safe in the finalizer? } void OnCallback(const uint8_t* buffer, uint32_t buffer_len) { // ... } private: [System::Runtime::InteropServices::UnmanagedFunctionPointer(System::Runtime::InteropServices::CallingConvention::Cdecl)] delegate void MyCallbackDelegate(const uint8_t* buffer, uint32_t buffer_len); MyCallbackDelegate^ callbackDelegate_; System::Runtime::InteropServices::GCHandle callbackHandle_; int callbackId_; // ... };
Is the code safe and what is the best fit for this?
Thanks in advance.
source share