我在 C 语言中有一些函数,想在 .net 应用程序中使用它们。为此,我编写了一个 C++/cli 的包装类。
C 语言接口中有一个回调函数,并将其包装在 .net 委托中。
但是如何释放回调 gcHandle 的非托管资源呢? 可以在终结器中调用 GCHandle 的 IsAllocated 和 Free 吗? 因为它是托管资源,可能已经被垃圾回收器释放了。
以下是 C 语言接口的代码:
// C functions
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*my_native_callback)(const uint8_t buffer[], uint32_t buffer_len);
void register_callback(my_native_callback c, uint32_t* id);
void remove_callback(uint32_t id);
#ifdef __cplusplus
}
#endif
以下是 .net 封装:
// .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_;
// ...
};
这段代码是否安全?最佳实践是什么?谢谢。
pin_ptr
可以将委托固定,但不是必需的”,对吧? - Tarc