How to call native C# code from a C library

GingerMcMurrayGingerMcMurray USMember ✭✭

I have a C library that needs pieces of it implemented in Xamarin C#. How can I call C# methods from inside the library?

If I'm using Objective C for iOS I can set up bridge methods. Android's Java has JNI. I assume that WinMo has something similar.

Every search I've tried explains how to call C from C#, but I need to go the opposite direction.

Thanks,
Ginger

Best Answer

Answers

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    I have a C library that needs pieces of it implemented in Xamarin C#. How can I call C# methods from inside the library?

    Are you saying you want the library to be able to call outward to the Xamarin app that is its parent?
    If so... Redesign. It don't work that way. Libraries don't know anything of their parents.

  • GingerMcMurrayGingerMcMurray USMember ✭✭

    @ClintStLaurent said:

    I have a C library that needs pieces of it implemented in Xamarin C#. How can I call C# methods from inside the library?

    Are you saying you want the library to be able to call outward to the Xamarin app that is its parent?
    If so... Redesign. It don't work that way. Libraries don't know anything of their parents.

    Perhaps a simpler question would be to leave libraries out of it entirely and ask "how do I let my C code call my C# methods?"

    Doing it with libraries is completely possible. I'm doing it right now using JNI for Android and Objective C bridges.

    For example, in Android JNI:

    jmethodID getMethodId(const char methodName, const char *signature)
    {
    jmethodID mid = (
    jEnv)->GetMethodID(jEnv, jClass, methodName, signature);
    if (mid == 0){
    fs_UtilDebugPrint("couldn't find method %s %s in obj",
    methodName, signature);
    }

    return mid;
    }

    bool doTheThing(const char Text)
    {
    jmethodID mid = getMethodId("doTheThing", "(Ljava/lang/String;)Z");
    if (0 == mid)
    return FALSE;
    jstring jtext = (
    jEnv)->NewStringUTF(jEnv, Text);
    jboolean result = (*jEnv)->CallBooleanMethod(jEnv, jObj, mid, jtext);
    bool returnValue = (bool) result;

    (*jEnv)->DeleteLocalRef(jEnv, jtext);

    return returnValue;
    }

  • ConwayConway USMember ✭✭

    We use to do a similar thing where we used underlying mono_xxx type methods at the C level to find classes and methods at the C# level, but Xamarin broke that mechanism along the way. When we asked them what happened, they asked why we were doing that. So instead of trying to find out what broke, we switched to passing pointers to static C# class methods (using delegates) down to our C library during initialization. Then the C code uses the function pointers to call up into C# code.

  • GingerMcMurrayGingerMcMurray USMember ✭✭

    @Conway said:
    We use to do a similar thing where we used underlying mono_xxx type methods at the C level to find classes and methods at the C# level, but Xamarin broke that mechanism along the way. When we asked them what happened, they asked why we were doing that. So instead of trying to find out what broke, we switched to passing pointers to static C# class methods (using delegates) down to our C library during initialization. Then the C code uses the function pointers to call up into C# code.

    Can you point me to an example? I'm trying build out a POC to show management that using Xamarin instead of three separate native apps is viable.

  • GingerMcMurrayGingerMcMurray USMember ✭✭

    Awesome, thanks!

  • TonyCeliaTonyCelia USMember ✭✭
    edited November 8

    @Conway - I'm brand new to objective-c, so forgive what may be incorrect terminology. Similar to your "static C# callback function," I am employing a C# class with static method to test callback functionality from objective-C to C#. I'm looking for a way for objective-c to callback to non-static methods in a C# class. It's now a couple of years since your last response. Is it now possible for objective-c to callback to non-static Xamarin.iOS C# methods without creating a binding library? My technique is as follows:

    In C#
    * Define a class that inherits from NSObject (NSObject includes the Class.Handle function)
    * [Register] the class and [Export] the static callback within the class
    * Use 'NSObject.Class.Handle' to get IntPtr to class
    * Marshal the class IntPtr (obtained with NSObject.Class.Handle) to objective-c as 'UnmanagedType.IUnknown'

    In objective-c
    * define a '@protocol' that corresponds to the C# class. The protocol has instance methods that correspond to each static callback function in the C# class
    * cast the marshaled IntPtr (from C#) as a 'id' for the '@protocol'
    * use the id as a delegate to the C# class

    Using this technique, I can pass the class pointer from C# to objective-c, use this class pointer as the id (in objective-c) for the class (in C#) and call back to C# from objective-c.

    Can this same (or similar) method (passing a class instance pointer from C# to objective-c and using this class instance pointer as the id) be employed to call non-static methods from objective-c?

  • TonyCeliaTonyCelia USMember ✭✭

    Even if the technique I described does not permit calling non-static methods, it is convenient to be able to reference the C# class as an objective-c @interface (from within objective-c). After casting the NSObject.Class.Handle IntPtr to a protocol id (in objective-c), objective-c treats the protocol id as a delegate to the C# class with the interface described in the protocol.

  • ConwayConway USMember ✭✭

    @TonyCelia Sorry, I can't help you with Obj-C to C# interoperability. We got it working for the C to C# case, and that's all we needed.

  • TonyCeliaTonyCelia USMember ✭✭

    @Conway - thanks for the quick reply. After rereading the initial post, I understand that the C# interoperability is needed across platforms (not just iOS), so your C# to C makes sense and is very helpful - thank you. Google lead me to this thread when I was performing various objective-c to C# interoperability searches. For other novices like me who land here wanting the same objective-c to C# interoperability, the technique I described may help.

Sign In or Register to comment.