Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Marshal C# Method to Unity3D with C++

I would like to call a specific method in my Unity3D project within an external plugin. Here is my C++ code:

static void UNITY_INTERFACE_API OnRenderEventThreadSafe(int eventID)
{
    [...] Some C++ code
    //Call C# Method here
}

My C++ code does already work on its own but now I want to call a specific C# method. How can I manage to do this? I tried creating delegates like this

#if UNITY_EDITOR
[DllImport("lib")]
#else
[DllImport ("lib")]
#endif
private static extern void Method(Delegate callback);

private delegate void Delegate(int number);

[MonoPInvokeCallback(typeof(Delegate))]
private static void DelegateMessageReceived(int number)
{
    Debug.Log("MessageReceived " + number);
}

public static void Method2()
{
    Method(DelegateMessageReceived);
}

But I don't think this is the right way... Should have mentioned it earlier, but I'm coding on Linux-Fedora25

like image 484
Aze Avatar asked Mar 10 '26 20:03

Aze


1 Answers

I ran into the-same issue in the past when making rendering plugin but the solution is not really hard.

You need to create a global static function pointer to hold the C# function you want to call from C++. The C++ function pointer must be static. Initialize this variable from the Start or Awake function in C#. After this, you can freely call that function anytime from C++.

C++ (YourCppPlugin.h)

#define DLLExport __declspec(dllexport)

extern "C"
{
    //Create a function pointer and give it a callback alias to shorten it
    typedef void(*FuncCallBack)(int eventID);

    //Create a callback delegate from the alias to hold the function from C#
    static FuncCallBack callbackInstance = nullptr;

    //Create the function that will be called from C# to store the function
    DLLExport void RegisterRenderCallback(FuncCallBack cb);
}

C++ (YourCppPlugin.cpp):

#include "YourCPP.h"

//Save the function we received from C# to the global variable for future use:

void RegisterRenderCallback(FuncCallBack cb) {
    callbackInstance = cb;
}

Done. You can now use the callbackInstance variable to call the C# function anytime from the Unity's UNITY_INTERFACE_API OnRenderEventThreadSafe C++ API function. Just make sure it's not null before calling it like below:

static void UNITY_INTERFACE_API OnRenderEventThreadSafe(int eventID)
{
    [...] Some C++ code

    //Call C# Method here
     if (callbackInstance != nullptr)
        callbackInstance(eventID);
}

Register a function to it first from C# with the RegisterRenderCallback function first before using the callbackInstance variable. See example in the Start function below.


C# side of the code:

// Use this for initialization
void Start()
{
    //Register the OnRenderCallback function to our C++ plugin for a callback
    RegisterRenderCallback(OnRenderCallback);
}

//Function that registers a local C# function to a delegate in C# for later use
[DllImport("YourCppPlugin", CallingConvention = CallingConvention.Cdecl)]
static extern void RegisterRenderCallback(renderCallback cb);

//int param callback delegate that links to the C# function we want to call from C++
delegate void renderCallback(int eventID);

//Function we want to call from C#. Registered in the Start function
[MonoPInvokeCallback(typeof(renderCallback))]
static void OnRenderCallback(int eventID)
{
    Debug.Log("Called from C# with ID: " + eventID);
}

Finally, if you have more than one function to register, you have to use List, array or dictionary to hold them on both C# and C++ side then iterate and call each one when necessary.

like image 91
Programmer Avatar answered Mar 12 '26 09:03

Programmer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!