-1

I have a big class from extern library and I need to use a unmanaged callback in managed code. Unmanaged code simplified:

typedef std::function<void(const std::string &, Float)> ProgressCallback;
class MeshGenerator{
public:   
ProgressCallback progress;
/// <summary>
/// set callback
/// </summary>
/// <param name="_callback"></param>
inline void SetCallback(ProgressCallback _callback){ this-> progress =_callback; }   
};

Now my manage Code simplified:

public delegate void CallbackDelegate(String^ cap, float data);
public ref class MeshWrapper
{

private:
MeshGenerator *gen;
public:
[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
CallbackDelegate^ _Delegate;
inline MeshWrapper(){ 
  this->gen = new MeshGenerator();
  _Delegate = gcnew CallbackDelegate(this, &MeshWrapper::Progress);
  auto ptr = Marshal::GetFunctionPointerForDelegate(_Delegate).ToPointer();
  ProgressCallback *p = static_cast<ProgressCallback*>(ptr);
  this->gen->SetCallback(*p);
}   
inline void Progress(String^ cap, float s){ System::Console::WriteLine(cap + s);}
};

this code compile, but in MeshWrapper constructor the static cast ("static_cast<ProgressCallback*>(ptr);") give me an empty delegate.

I'm probably making some conceptual mistakes. Thanks for your help.

3
  • callback to inline ? ... also std::string is not compatible with dotnet string Commented May 10, 2024 at 9:10
  • @Selvin thanks for reply, but i cannot modify unmanaged class... i need to find the way to use ProgressCallback in managed code.. Commented May 10, 2024 at 9:13
  • It was some time since I coded C++, but you should be able to create a unmanaged helper class, that has a gcroot to your meshWrapper. That way you should not need to rely on any automated conversions. Commented May 10, 2024 at 10:01

2 Answers 2

1

You cannot simply cast a function pointer to a std::function pointer, you need to construct a std::function object:

auto pc = ProgressCallback(reinterpret_cast<void(*)(const std::string &, Float)>(ptr));
this->gen->SetCallback(pc);

Alternatively, pass a lambda that performs the cast in-line and maybe fixes up some of the arguments:

this->gen->SetCallback([=](const std::string & s, Float f) {
  auto fn = reinterpret_cast<void(*)(const std::string &, float)>(ptr);
  fn(msclr::interop::marshal_as<String^>(s), f);
});
Sign up to request clarification or add additional context in comments.

1 Comment

thank you, I'm close to solve the problem, the first method work, but when my Managed Progress method is called the string^ cap has wrong value probably because I need conversion from std::string to String^... the second doesn't compile with this message: "C++ local lambda not allowed in a member function of a managed class" ...
0

Thanks to @Botje for help, now I solved my problem like this:

public delegate void CallbackDelegate(std::string& cap, float data);

I changed my Callback delegate in managed Code with std::string&.

The reinterpret_cast is the same of @Botje.

In managed, Progress method changes like this:

void MeshWrapper::Progress(std::string&  cap, float s) {
 // Transform std string in String^!!!!!!
 String^ newSystemString = gcnew String(cap.c_str());   
 // Code that uses newSystemString here :)  
};

Thank you.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.