2

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?

3
  • Try adding extern “C” to the declaration of ObserverCallback, to ensure it follows C calling conventions. Commented Aug 25, 2018 at 17:34
  • And you might need [UnmanagedFunctionPointer(CallingConvention.Cdecl)] on the delegate declaration too. Commented Aug 25, 2018 at 17:43
  • &ObserverCallback is not the correct function pointer. You are missing the function pointer type - see: stackoverflow.com/questions/2298242/callback-functions-in-c Commented Aug 19, 2021 at 18:43

2 Answers 2

1

Easy workaround is a C shim. https://stackoverflow.com/a/31232805/179795 and other answers in that question may also help.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, but I only have this small use case and I feel adopting this would be too big for such a small problem. Currently considering doing it another way entirely.
0

I think Marshal.GetDelegateForFunctionPointer will work if you pass it the address of a function marked static. Pass this as an explicit parameter if necessary.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.