0

I'm embedding Mono in a C++ app, and then calling a C function from a C# routine via function pointer.

I'm using Marshal.GetDelegateForFunctionPointer for the C native function. I have this working in Windows, but on Android, the C call stack appears to be garbage.

I'm sure it has to do with how Mono is handling the native argument stack. My guess is that JNICALL (Java) is different than __stdcall (Windows), but GetDelegateForFunctionPointer probably requires the __stdcall format? It's a total guess.

What can I change to make this implementation work on both Windows and Android?

Please take a look at SomeFunction() below; it's the call getting garbage argument stack.

C++ (Android NDK)

// function called by C# through GetDelegateForFunctionPointer
extern "C" JNIEXPORT
int JNICALL SomeFunction(int num, float flt, char *msg)
{
    // Windows shows correct arguments, but Android shows garbage arguments
    m_strdup_printf ("Some Function data '%s'.", msg);

    return 0;
}


// calling code using embedded Mono
...
    MonoMethodDesc* sayHelloDesc = mono_method_desc_new("Class1:ManagedMethodSayHello(string,int,intptr)", false);
    MonoMethod* sayHelloMeth     = mono_method_desc_search_in_class(sayHelloDesc, pClass);

    if (!sayHelloMeth)
    {
        result = -1;
        return;
    }

    char *arg = "Hello World";
    int num = 0x64;
    int(JNICALL *func)(int, float, char *) = &SomeFunction;

    void * newArgs[3];

    newArgs[0] = mono_string_new(mono_domain_get(), arg);
    newArgs[1] = #
    newArgs[2] = &func;

    exc = 0;

    ret = mono_runtime_invoke(sayHelloMeth, class1Instance, newArgs, &exc);
...


c#

    // delegate pattern that matches 'SomeFunction' argument list
    delegate int CFuncDelegate(int num, float flt, string msg);

    public interface InterfaceClass1
    {
        IntPtr ManagedMethodSayHello(string arg, int num, IntPtr func);
    }

    public class Class1 : InterfaceClass1 
    {
        Class1()
        {
        }

        public IntPtr ManagedMethodSayHello(string arg, int num, IntPtr func)
        {
            CFuncDelegate myfunc = (CFuncDelegate)Marshal.GetDelegateForFunctionPointer(func, typeof(CFuncDelegate));

            // make the call (Mono handles Marshaling of the string argument in Windows implementation)
            int res = myfunc(55, 3.14f, "Did you see what I did here?");

            return func;
        }

Incidentally, here's the same working method from Windows

int __stdcall SomeFunction(int num, float flt, char *msg)
{
    COutputWnd::Instance->AppendBuild(CA2W(msg));

    return 0;
}


...
    // int ManagedMethodSayHello(string arg, int num, IntPtr func)
    MonoMethodDesc* sayHelloDesc = mono_method_desc_new("Class1:ManagedMethodSayHello(string,int,intptr)", FALSE);
    MonoMethod* sayHelloMeth     = mono_method_desc_search_in_class(sayHelloDesc, pClass);

    if (!sayHelloMeth)
    {
        result = -1;
        return;
    }

    char *arg = "Hello World";
    int num = 0x64;
    int(__stdcall *func)(int num, float flt, char *) = &SomeFunction;

    void * newArgs[3];

    newArgs[0] = mono_string_new(mono_domain_get(), arg);
    newArgs[1] = #
    newArgs[2] = &func;

    exc = 0;
    ret = mono_runtime_invoke(sayHelloMeth, class1Instance, newArgs, &exc);

...
mbelew
  • 1
  • 2
  • Hi, by `the C call stack appears to be garbage.`, it means when you call the C method, you can't get the correct answer? By `Windows`, is it UWP? – Robbit Apr 19 '18 at 08:41
  • It means the argument stack for the method is corrupted- for "int num, float flt, char *msg" I'm expecting num=55, flt=3.14f, msg="Did you see what I did here?". This does work on Windows, but not on Android. I'm not using UWP, but I wouldn't mind using it if there was a way to host the mono runtime from a C++ app and call C functions from the mono environment. This is very much like a C# plugin environment. – mbelew Apr 19 '18 at 15:45

0 Answers0