0

I want to pass as callback a C++ member function to a C# project. I have other project in C++/CLI and I want to do it through it.

So, in unmanaged C++ of my C++/CLI project I have a function object:std::function<void(int)>callback;

This function is coming from my C++ project and it works fine, I save it there as example to avoid the previous step. Now, I would like to pass this callback function to my C# project. For this, I create a method in unmanaged C++, pass it to managed C++ and from this point pass it finally to C#. I'd like something like this:

// Unmanaged class
public class Wrapper
{
public:
    std::function<void(int)>callback;

    void ReturnToCallback(int data)
    {
        callback(data);
    }

    void PassCallback()
    {
        NETWrapper netWrapper;
        netWrapper.TestCallback(ReturnToCallback);
    }
};

//Managed class
public ref class NETWrapper
{
public:
    void TestCallback(Action<int>^ callback)
    {
       StartGenerator^ startGen = gcnew StartGenerator(callback);
    }
};

// C# 
public class StartGenerator
{
    private Communication comm;

    public StartGenerator(Action<int> callback)
    {
        comm = Communication.Instance;
        comm.callback = callback;
    }
}

This solution, of course, gives me back an error when compiling:

Error 3 error C3867: 'IfaceXXX::Wrapper::ReturnToCallback': function call missing argument list; use '&IfaceXXX::Wrapper::ReturnToCallback' to create a pointer to member d:\XXX.h

I have tried other ways such as Get the delegate for the function pointer so I can work on Managed C++ and pass it to C# but I am not able to implement it right. What do you think is the best way to try this?

1 Answers1

1
  1. Make Wrapper::callback a pointer to the std::function.
  2. Change Wrapper to a ref class.

That's it.

public ref class Wrapper
{
public:
    std::function<void(int)>* callback;

    void ReturnToCallback(int data)
    {
        (*callback)(data);
    }

    void PassCallback()
    {
        NETWrapper netWrapper;
        netWrapper.TestCallback(gcnew Action<int>(this, &Wrapper::ReturnToCallback));
    }
};

You do then need to manage the lifetime of the std::function now, perhaps my clr_scoped_ptr could show you how to do that.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Hi, I've tried to use your solution for smart pointer but the object is null (the instance of the Wrapper ref class is not) when C# project calls the saved delegate and this pointer is used. clr_scoped_ptr> ptr; public: Wrapper(std::function& callbackptr) : ptr(new std::function(callbackptr)){} – Mario Sanz Gómez Apr 13 '20 at 17:57
  • @MarioSanzGómez: I haven't run into that problem. Check how many Wrapper instances you are creating, maybe you aren't using the one that you associated with the callback pointer. – Ben Voigt Apr 13 '20 at 18:03
  • I've already checked this but no... I only instantiate the wrapper class once. I created another question for this problem here. If you could take a look... https://stackoverflow.com/questions/61170340/system-accessviolationexception-error-when-stored-callback-is-executed – Mario Sanz Gómez Apr 13 '20 at 18:17
  • 1
    You can probably debug this by putting breakpoints on the destructor and finalizer of `clr_scoped_ptr`. You're not looking for bugs in my class, but at what the call stack is when you are unintentionally causing the cleanup to happen too early. – Ben Voigt Apr 13 '20 at 19:06