简体   繁体   中英

Pass a C++ function pointer to C# with embedded mono

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?

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM