[disclaimer]


This is a personal blog. The opinions expressed here represent my own and not those of any of my employers or customers.

Except if stated otherwise, all the code shared is reusable under a MIT/X11 licence. If a picture is missing a copyright notice, it's probably because I'm owning it.

Friday, March 1, 2013

Working around the reverse callback limitation on Xamarin.iOS

There's one annoying technical limitation of Xamarin.iOS if you have to pass a C# delegate instance to unmanaged code. It's not new, and it's well documented.

But still, having to flag the callback with an attribute and no instance method makes an API hard to use if you don't care that much about the internals of the library you're consuming.

I'm currently polishing the Chipmunk binding for Xamarin.iOS, and the cpSpace has some functions taking callbacks, like cpSpaceEachBody or cpSpaceAddPostStepCallback.



The C# API exposed looks like this (for the PostStep callback):

public class Space {    public void AddPostStepCallBack (Action action, Body body);}
If we could lift the restrictions, it could take lambdas or anonymous methods. This is how I did it behind the scenes:
public class Space {
    delegate void PostStepFunc (IntPtr space, IntPtr obj, IntPtr data);
 
    [MonoTouch.MonoPInvokeCallback (typeof (PostStepFunc))]
    static void PostStepForBody (IntPtr space, IntPtr obj, IntPtr data)
    {
        var handle = GCHandle.FromIntPtr (data);
        var action = (Action)handle.Target;
        handle.Free ();
        action (obj == IntPtr.Zero ? null :  new Body (obj));
    }
 
    [DllImport ("__Internal")]
    extern static void cpSpaceAddPostStepCallback (IntPtr space, PostStepFunc func, IntPtr key, IntPtr data); 
 
    public void AddPostStepCallback (Action action, Body obj)
    {
        var data = GCHandle.ToIntPtr(GCHandle.Alloc (action));
        cpSpaceAddPostStepCallback (Handle.Handle, PostStepForBody, obj.Handle.Handle, data);
    }
}
Static callback? : Check!
Flagged with attribute? : Check!

This is possible because of the free to use data pointer as last argument of the native function call. We don't expose it to the use, and hijack it to pass the GCHandle ptr of the callback provided by the user.

Hope it helps you.



Liked this? Want more? I'm available for contracting, so contact me.




2 comments:

  1. I would like to buy your Xamarin softwere
    but not to be forced to change my full time
    GNOME desktop because you don't provade a
    Linux version.

    Then my question is

    Why post your efforts un something not related
    to GNOME/Linux?

    I found useful your work on Gtk+ and that's
    good news for us, but could be better to
    heart about your plans/work to port Xamarin
    to Gtk3.x and provide a maintener for Windows
    installer and bug fixes.

    ReplyDelete
    Replies
    1. Diego,

      First, Im not employed by Xamarin, I'm just using their great products.

      I am writing about this subject on this blog for the following reasons:
      - this is my blog. I write whatever I want on it. I'm not forcing you to read it, but thanks for doing so.
      - the bindings and the components I'm contributing to Xamarin, and writing about here, are OpenSource and could be of some interest to some readers. Not you apparently.
      - Xamarin Studio works on a GNU Desktop. The fact that you can't develop iOS application from it is due to technical limitations and company focus. Except if you lie on a big pile of money to sponsor this specific rework, don't rant about something you have no lever on. You'll sleep better.
      - I've read that some efforts of providing mono bindings for Gtk+3.x are ongoing. If it's not going fast enough for you, feel free to contribute to them.

      Cheers,

      St├ęphane

      Delete