I have a C# method that looks like this:
public delegate void VariableObserver(string variableName, object newValue);
public void ObserveVariable(string variableName, VariableObserver observer)
{
// stuff
}
This code is embedded into a c++ application and I want to call the ObserveVariable
function from C++, passing a function pointer or something equivalent as the VariableObserver
delegate. The intention is then that the C# code can call the delegate and the C++ function will be invoked.
I'm used to using mono_runtime_invoke
for calling C# functions, and it works great. However I can't find any useful examples of documentation of how you can pass a function pointer/delegate. Do you need to box it up like you do with some types like strings etc? If so how do you do this? is it even possible?
I found the Marshal.GetDelegateFromFunctionPointer
method while searching around, and I figured I could use that in C# to get the delgate and carry on as normal, however these docs says this is now obsolete.
Edit: some more things I discovered. There's this newer Marshal function: Marshal.GetDelegateForFunctionPointer<TDelegate>(IntPtr)
which looked promising, but it says explicitly "You cannot use this method with function pointers obtained through C++ or from the GetFunctionPointer method." :(
Edit2: I've tried the suggestion of just using GetDelegateForFunctionPointer, but it doesn't look like the function pointer is marshalled correctly. Take a look:
C# code:
delegate void TestObserver(int num);
public void BindObserver(IntPtr observerFuncPtr)
{
TestObserver obs = Marshal.GetDelegateForFunctionPointer<TestObserver>(observerFuncPtr);
obs(1337);
}
C++ code:
static void ObserverCallback(int num)
{
printf("WE GOT A CALLBACK %d", num);
}
// inside a function I call
void* params[1];
params[0] = &ObserverCallback;
MonoObject* exception;
mono_runtime_invoke(theMonoMethod, theMonoInstance, params, &exception);
However doing this results in this error from C#:
Runtime Exception : System.NullReferenceException: Object reference not set to an instance of an object
at (wrapper managed-to-native) System.Object:wrapper_native_8348575608244C89 (int)
at InkGlue.GlueStory.BindObserver (System.IntPtr observerFuncPtr) [0x00006] in <78fcd644f8db43978f6f7b1655d0ab2f>:0
Which leads me to believe that the function pointer is not successfully being passed to C#. Any info on how to do this correctly?