I have a static library (*.a for iOS) that contains some functions that I need to assign to a callback from C#. The code works fine without the callback, but when I add the delegate to the structure, it fails with the following error:
ArgumentException: The specified structure must be blittable or have
layout information. Parameter name: structure at
FMOD_Listener.LoadPlugins () [0x00000] in <filename unknown>:0 at
FMOD_Listener.Initialize () [0x00000] in <filename unknown>:0
(Filename: currently not available on il2cpp Line: -1)
Here is the native code (C):
extern "C" {
typedef void (F_CALLBACK *basic_callback) (int *value1);
typedef struct telephone
{
int area_code;
int number;
basic_callback basic_callbck;
} TELEPHONE;
F_DECLSPEC F_DLLEXPORT void F_STDCALL AigooRegisterPhone(TELEPHONE **telephone);
void F_CALLBACK aigoo_basic_callback(int *value1)
{
*value1 = *value1 * 10 ;
}
F_DECLSPEC F_DLLEXPORT void F_STDCALL AigooRegisterPhone(TELEPHONE **telephone)
{
TELEPHONE* myPhone = new TELEPHONE ();
myPhone->area_code = 929;
myPhone->number = 823;
myPhone->basic_callbck = aigoo_basic_callback;
*telephone = myPhone;
}
}
This is the managed side C#:
public delegate void basic_callback (ref int value1);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct TELEPHONE
{
public int area_code;
public int number;
public basic_callback basic_callbck;
}
public class FMODPlugInHandler {
[DllImport ("__Internal")]
public static extern void AigooRegisterPhone(out IntPtr TelephonePtr);
}
public class FMOD_Listener : MonoBehaviour
{
...
void LoadPlugins()
{
int plugin_result = 0;
if (Application.platform == RuntimePlatform.IPhonePlayer) {
IntPtr PhoneIntPtr;
FMODPlugInHandler.AigooRegisterPhone(out PhoneIntPtr);
plugin_result = 823823823;
myLog = "plugin_result = " + plugin_result + " PhoneIntPtr: " + PhoneIntPtr;
if (PhoneIntPtr != IntPtr.Zero){
TELEPHONE MyPhone = (TELEPHONE)Marshal.PtrToStructure(PhoneIntPtr, typeof(TELEPHONE));
plugin_result = 123456;
myLog = "result = " + plugin_result + " number: " + MyPhone.number ;
int int_cs = 2;
plugin_result = MyPhone.basic_callbck(ref int_cs);
myLog = "result = " + plugin_result + " number: " + MyPhone.number + " int_cs: " + int_cs;
}
}
}
...
}
From MSDN
I think your code must be
Here is the working code based on the suggestion from @Josh Peterson. The C code is the same. Only changed the C# side.
The problem here is that a delegate is not a blittable type (search for "delegate" on this page), so this error started to occur when you added a delegate to the struct.
The first part of the error:
is what matters here. The "layout information" part of the error can be ignored.
The best option is probably to pass an out parameter for the the delegate as a separate argument to
AigooRegisterPhone
or to use anIntPtr
in theTELEPHONE
struct instead of thebasic_callback
type. In the later case, you can callMarshal.GetDelegateForFunctionPointer
to get a C# delegate from the native function pointer.