Search Unity

Making calls from C to C# with IL2CPP instead of mono_runtime_invoke

Discussion in 'iOS and tvOS' started by frankprogrammer, Feb 3, 2015.

  1. frankprogrammer

    frankprogrammer

    Joined:
    Apr 27, 2009
    Posts:
    17
    I am trying to figure out how to make calls from C to C# with IL2CPP. For Mono, I would do this by calling mono_runtime_invoke from C using the methods described here: http://www.jerrodputman.com/2010/01/10/the-unityobjective-c-divide

    According to the Unity Manual (http://docs.unity3d.com/Manual/iphone-64bit.html):
    I know how to make the delegate call to C from C# with DLLImport, but not sure what signature I would have on the C side for the callback and how I would actually make the calls back. Is this even possible yet with IL2CPP or am I stuck using UnitySendMessage?
     
    Last edited: Feb 4, 2015
  2. frankprogrammer

    frankprogrammer

    Joined:
    Apr 27, 2009
    Posts:
    17
    I also tried passing a function pointer as described here:


    This gave me the runtime error on IL2CPP:
    NotSupportedException: To marshal a manged method, please add an attribute named 'MonoPInvokeCallback' to the method definition

    and built with Mono:
    ExecutionEngineException: Attempting to JIT compile method '(wrapper native-to-managed)

    So I am assuming this method never worked since JIT compiling is not supported on iOS. Question is, what's left?
     
  3. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    Try this.

    C# code:
    Code (csharp):
    1.  
    2. [MonoPInvokeCallback(typeof(AddTwoNumbersDelegate))]
    3. static void AddTwoNumbersInManagedCode(int a, int b)
    4. {
    5.     return a + b;
    6. }
    7.  
    8. delegate void AddTwoNumbersDelegate(int a, int b);
    9.  
    10. [DllImport("__Internal")]
    11. extern static void AddTwoNumbersUsingCallback(int a, int b, AddTwoNumbersDelegate callback);
    12.  
    13. void Start()
    14. {
    15.     Debug.Log(string.Format("{0} + {1} = {2}", 2, 2, AddTwoNumbersUsingCallback(2, 2, AddTwoNumbersInManagedCode));
    16. }
    17.  
    18.  
    C++:

    Code (csharp):
    1.  
    2. typedef void (__stdcall* CallbackFunc)(int a, int b);
    3. extern "C" void __stdcall AddTwoNumbersUsingCallback(int a, int b, CallbackFunc callback)
    4. {
    5.      return callback(a, b);
    6. }
    7.  
     
    bhupiister and frankprogrammer like this.
  4. frankprogrammer

    frankprogrammer

    Joined:
    Apr 27, 2009
    Posts:
    17
    Thanks for the help. Just using MonoPInvokeCallback alone gave me compiler errors but I managed to get it working like this:

    C#:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Runtime.InteropServices;
    4. using AOT;
    5.  
    6. public class Test : MonoBehaviour
    7. {
    8.     public delegate void TestDelegate();
    9.  
    10.     [DllImport("__Internal")]
    11.     public static extern void _UnmanagedTest(TestDelegate callback);
    12.  
    13.     [MonoPInvokeCallback(typeof(TestDelegate))]
    14.     private static void ManagedTest()
    15.     {
    16.         Debug.Log("IT WORKS!!!!");
    17.     }
    18.  
    19.     private void Update()
    20.     {
    21.         if (Input.GetMouseButtonUp(0) == true)
    22.         {
    23.             _UnmanagedTest(ManagedTest);
    24.         }
    25.     }
    26. }
    C++:
    Code (CSharp):
    1. typedef void (*TestCallback)();
    2. extern "C" void _UnmanagedTest(TestCallback testCallback)
    3. {
    4.     testCallback();
    5. }
     
    khaled24, bhupiister, dtaddis and 2 others like this.
  5. hassanalic

    hassanalic

    Joined:
    Aug 15, 2016
    Posts:
    1
    Hi, I have tried to run this code on Unity5.4.0f3 it gave me this error. "IL2CPP does not support marshaling delegates that point to instance methods to native code." Any Idea about that ?
     
  6. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    @hassanalic

    Make sure that the method in managed code is static (note the signature of ManagedTest in the examples from @Frank84 above). IL2CPP (and Mono AOT) cannot handle calling back on a managed instance method from native code - only static methods will work.
     
    EricBeets likes this.
  7. MrLucid72

    MrLucid72

    Joined:
    Jan 12, 2016
    Posts:
    996
    Discord rpc stopped working with il2cpp in Unity 2018.2:

    https://github.com/discordapp/discord-rpc/issues/243 ($50 Bounty!)

    Anyone know how to get this il2cpp working? I tried using the steps above. Their original code looks like this (just listing their Ready func - they have about 5 others):

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void ReadyCallback(ref DiscordUser connectedUser);

    public struct EventHandlers
    {
    public ReadyCallback readyCallback;
    }

    // I believe ReadyCallback triggers after this, but just a guess
    [DllImport("discord-rpc", EntryPoint = "Discord_Initialize", CallingConvention = CallingConvention.Cdecl)]
    public static extern void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId);


    I've been doing some trial-and-error attempts, but no dice.
     
    Last edited: Nov 2, 2018
  8. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    I've posted some comments on the Github issue. Really, the solution discussed there is the proper solution. I don't think we have any other options.
     
  9. MrLucid72

    MrLucid72

    Joined:
    Jan 12, 2016
    Posts:
    996
    Doh, I gave the closed ticket link -- here is the thread revival one -- I'll port your comment. Thanks for that!

    I have been trying to implement the original linked solution that you saw to no success. It's probably 1 small thing I'm doing wrong.

    There's a $50 bounty if you toss up a working template to this new link:

    https://github.com/discordapp/discord-rpc/issues/243

    If you scroll to the bottom, you can see what I attempted to no avail. It may just need 1 or 2 changes! I know it's 3rd party, but you'll be helping tons of Unity il2cpp porters that use or want to use Discord rich presence features ;D
     
  10. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    I've added some more comments to that issue, have a look there, and let me know if the latest changes work.
     
  11. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    I have issues with unicode strings in delegate callbacks. Any way to control the marshalling of that?
     
  12. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    Yes - IL2CPP follows all of the .NET string marshaling rules. The normal C# marshaling directives should work.
     
  13. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    Strange. I use the code on many platforms but on Unity Android il2cpp i only get a callback with one character. Typically a situation when a unicode string is interpreted as ansic C
     
  14. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    Code (CSharp):
    1.  
    2. [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    3. public delegate void EventHandler_OnMessage(string sender ,MessageLevel level, string message);
    4.  
    and

    Code (CSharp):
    1.  
    2. [MonoPInvokeCallback(typeof(EventHandler_OnMessage))]
    3. private static void MessageHandler(string sender, MessageLevel level, string message)
    4. {
    5.      OnMessage?.Invoke(sender, level, message);
    6. }
    7.  
    On Unity 2019.2.12 Android i get ansi C marshall in MessageHandler that are called with wide unicode strings
     
  15. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    You need to use [MarshalAs(UnmanagedType.LPWSTR)] on each string parameter. Otherwise it defaults to UTF8 marshaling.
     
  16. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    How. Can you explain more. The same code works in mono and Windows
     
  17. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
  18. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    Like this:

    Code (csharp):
    1. [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    2. public delegate void EventHandler_OnMessage([MarshalAs(UnmanagedType.LPWStr)] string sender ,MessageLevel level,  [MarshalAs(UnmanagedType.LPWStr)] string message);
    3.  
    4. [MonoPInvokeCallback(typeof(EventHandler_OnMessage))]
    5. private static void MessageHandler([MarshalAs(UnmanagedType.LPWStr)] string sender, MessageLevel level,  [MarshalAs(UnmanagedType.LPWStr)] string message)
    6. {
    7.      OnMessage?.Invoke(sender, level, message);
    8. }
    9.  
    I believe IL2CPP marshals parameters according to what's on the method, rather than the delegate type definition. I could be wrong, though.
     
  19. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    Thanx! Just thought IL2CPP should work like mono and MS C#
     
  20. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    It should :). If you find that it doesn't, we welcome bug reports. A lot of these were tricky to get right and I'm sure there are inconsistencies...
     
  21. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    Actually it doesnt seem to work anyway :-( even if I add your attributes with IL2CPP
     
  22. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    Could you describe what happens when it doesn't work? Did you try debugging what il2cpp does wrong?
     
  23. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    It creates a utf8 string from the sent unicode utf16 instead of constructing it from unicode and stops generation as the first char is taken and the second is a zero so it ends up with a one character string
     
  24. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    As a workaround, you can change the parameter to "IntPtr" so IL2CPP doesn't marshal anything, and then use Marshal.PtrToStringUni to convert IntPtr to a C# string.

    Can you file a bug report for the bad marshaling?
     
  25. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    Filed a demo to the bug reporter
     
  26. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    Still no resolution in 2019.2.17

    Attached a pdf that shows the problem
     

    Attached Files:

  27. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    I don't think we have an active bug report for this issue. Would you mind submitting one? That way we can give you direct feedback when the bug is corrected. Here are details about how to submit bugs:

    https://unity3d.com/unity/qa/bug-reporting
     
  28. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    Case 1201898 submitted 29/11 2019
     
    JoshPeterson likes this.
  29. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    Still no solution in 2019.3.1f1 and the issue 1201898 is removed ?
     
  30. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    It looks like issue 1201898 was incorrectly closed as a duplicate of another issue you reported. I've re-opened 1201898 and updated its notes so that our QA team will handle it correctly.
     
  31. AndersModen

    AndersModen

    Joined:
    Nov 19, 2019
    Posts:
    51
    Great ! Thanx !

    Meanwhile i have changed to use ansi as string encoding so it works but IL2CPP should work as other C# implementations
     
  32. bhupiister

    bhupiister

    Joined:
    Dec 13, 2019
    Posts:
    42
    This really helped me thanks....