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);
...