patterncsharpMinor
Interop between C++ and C# via C++/CLI with callbacks
Viewed 0 times
interopcallbackswithbetweenviacliand
Problem
I want to use an existing C++ library in a C# app. The C++ library will have async callbacks for things like
To begin, I have a simple C++ class:
To communicate with this, I have a C++/CLI wrapper:
```
using namespace System;
using namespace System::Runtime::InteropServices;
namespace CliCpp {
public delegate void OnConnectDelegate(int);
public ref class WrapperClass
{
public:
// C# callback delegates
CliCpp::OnConnectDelegate^ OnConnectHandler;
// Ctor / dtor
WrapperClass()
{
m_native = new CppClass();
// Set OnConnect callback
CliCpp::OnConnectDelegate^ managed_on_connect = gcnew CliCpp::OnConnectDelegate(this, &WrapperClass::OnConnect);
IntPtr stub_ptr = Marshal::GetFunctionPointerForDelegate(managed_on_connect);
CppClass::Callback fptr = static_cast(stub_ptr.ToPointer());
m_native->SetOnCallback(fptr);
GC::KeepAlive(managed_on_connect);
};
~WrapperClass()
{
this->!WrapperClass();
};
!WrapperClass()
{
if (m_native != nullptr)
delete m_native;
};
// Methods
void Connect(String^ conn_info)
{
m_native->Connect(msclr::interop::marshal_as(conn_info));
};
// Event handler from C++ code
void OnConnect(
OnConnect and user updates so I want to reflect this in the eventual C# code. I would appreciate thoughts on the following implementation particularly in the area of memory leaks in the CLI part.To begin, I have a simple C++ class:
#include
class CppClass
{
public:
typedef void(*Callback)(int);
CppClass(){};
~CppClass(){};
void Connect(std::string conn_info)
{
OnConnect();
};
void OnConnect()
{
m_callback(42);
};
void SetOnCallback(Callback callback)
{
m_callback = callback;
};
private:
Callback m_callback;
};To communicate with this, I have a C++/CLI wrapper:
```
using namespace System;
using namespace System::Runtime::InteropServices;
namespace CliCpp {
public delegate void OnConnectDelegate(int);
public ref class WrapperClass
{
public:
// C# callback delegates
CliCpp::OnConnectDelegate^ OnConnectHandler;
// Ctor / dtor
WrapperClass()
{
m_native = new CppClass();
// Set OnConnect callback
CliCpp::OnConnectDelegate^ managed_on_connect = gcnew CliCpp::OnConnectDelegate(this, &WrapperClass::OnConnect);
IntPtr stub_ptr = Marshal::GetFunctionPointerForDelegate(managed_on_connect);
CppClass::Callback fptr = static_cast(stub_ptr.ToPointer());
m_native->SetOnCallback(fptr);
GC::KeepAlive(managed_on_connect);
};
~WrapperClass()
{
this->!WrapperClass();
};
!WrapperClass()
{
if (m_native != nullptr)
delete m_native;
};
// Methods
void Connect(String^ conn_info)
{
m_native->Connect(msclr::interop::marshal_as(conn_info));
};
// Event handler from C++ code
void OnConnect(
Solution
I'm not sure about the callbacks but you are using the destructor/finalizer in a way that might cause problems.
If you are doing this then the descructor should call
Then in your finalizer you should set the
As to the
~WrapperClass()
{
this->!WrapperClass();
};
!WrapperClass()
{
if (m_native != nullptr)
delete m_native;
};If you are doing this then the descructor should call
GC.SuppressFinalize(this); because the finalizer has already been called.Then in your finalizer you should set the
m_native = nullptr; because if the GC calls it again later it will crash as the object has been deleted but it's still pointing to it.!WrapperClass()
{
if (m_native != nullptr)
{
delete m_native;
m_native = nullptr;
}
}As to the
m_native I'd call it _nativePtr.Code Snippets
~WrapperClass()
{
this->!WrapperClass();
};
!WrapperClass()
{
if (m_native != nullptr)
delete m_native;
};!WrapperClass()
{
if (m_native != nullptr)
{
delete m_native;
m_native = nullptr;
}
}Context
StackExchange Code Review Q#137897, answer score: 3
Revisions (0)
No revisions yet.