私はcにいくつかの関数を持っており、これを.netアプリケーションで使用します。このために、C ++/cliを使用してWrapperクラスを作成しました。
cインターフェースにはコールバック関数があり、これを.netデリゲートでラップします。
しかし、コールバックgcHandleのアンマネージリソースをどのように解放する必要がありますか?ファイナライザーでIsAllocatedとFreeをGCHandleから呼び出すことは許可されていますか?それは管理されたリソースであり、gcがすでにそれをリリースしている可能性があるためですか?
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_;
// ...
};
コードスニペットは安全ですか?これのベストプラクティスは何ですか?
前もって感謝します。