AndreiM
AndreiM

Reputation: 876

Call native std::function from C++/CLI

I have a native class which receives an std::function as a parameter and at some point in time it calls this callback:

class NativeClass
{
public:
    NativeClass(std::function<void(int, const char*)> callback) : m_callback{callback}
    {
    }

    void DoAction()
    {
        ...
        m_callback(3, "asd");
        ...
    }

private:
    std::function<void(int, const char*)> m_callback;
}

Let's say this resides in a library which is out of my control, so std::function is a given.

Now I have a C++/CLI class where I would like thiss callback to be called:

public ref class ManagedConsumer()
{
public:
    ManagedConsumer()
    {
        m_nativeClass = new NativeClass(std::bind(&ManagedConsumer::OnCallback, this); // errors: 3374, 2672
        m_nativeClass = new NativeClass([this](...){this->OnCallback(...);}); // errors: 3374, 2672
    }
    void OnCallback(int i, const char* str)
    {
        localInt += i; // must access local variable from this
        // consume callback
    }
private:
    NativeClass *m_nativeClass;
    int localInt;
}

Is it even possible to capture the this variable? I cant really change the NativeClass to pass an Interface or something different.

Upvotes: 0

Views: 962

Answers (1)

Oleksandr
Oleksandr

Reputation: 21

you need to use a bit of marshalling over here, as well need to make callback as an delegate.

Content of managed class .h

#pragma once
using namespace System::Runtime::InteropServices;

public delegate void CallbackDelegate(int data);

public ref class ManagedClass
{
    UnmanagedClass* unmanagedClassPtr;
    [MarshalAsAttribute(UnmanagedType::FunctionPtr)]
    CallbackDelegate^ _Delegate;
public:
    ManagedClass()
    {
        unmanagedClassPtr = new UnmanagedClass(); 
        _Delegate = gcnew CallbackDelegate(this, &ManagedClass::MyCallback);
        auto ptr = Marshal::GetFunctionPointerForDelegate(_Delegate).ToPointer();
        unmanagedClassPtr->setCallback(ptr);
    }
    virtual ~ManagedClass()
    {
        delete unmanagedClassPtr;
    }
    void MyCallback(int s) {
        System::Console::WriteLine("hello from unmanaged");
    };
};

Content of unmanaged class .h

#pragma once
#include "callbackType.h"

class UnmanagedClass
{
public:
    void setCallback(void* _callback)
    {
       callback = (callbackType)_callback;
       callback(13);//call it immediately
    };
};

I got this working from next sources: https://www.codeproject.com/Articles/9903/Calling-Managed-Code-from-Unmanaged-Code-and-vice and C++/CLI delegate as function pointer (System.AccessViolationException)

Upvotes: 2

Related Questions