30330


dllの関数をBindingして実装をすすめているのですが、  
実行してみると、null例外が発生する変数がでてきました。  
（下記のコード ※部分）  
例外が発生しない変数（配列)もあるため、違いがわからず、原因がわからない状況です。  
どなたか、現象の理由or原因をご指摘いただけないでしょうか。

・補足  
\- Xamarinを利用して、iOSのFrameworkを組み込み(ただし、ObjectiveCのAPIはなく、C関数のみ)

### C - dll

[code]

    ※構造体部分は割愛
    void dllMethod( void (*callback)(STR_A *) );
    
[/code]

### C# - 実装

[code]

    [StructLayout (LayoutKind.Sequential)]
    public struct STR_A
    {
        [StructLayout (LayoutKind.Explicit)]
        public struct uni
        {
            [FieldOffset (0)]
            public byte filed_a;
    
            [FieldOffset (0)]
            public STR_X str_x;
        }
        public uni data;
    
    }
    
    [StructLayout (LayoutKind.Sequential)]
    public struct STR_X
    {
        [MarshalAs(UnmanagedType.ByValArray,SizeConst=8)]
        public byte[] buff;
    
        public STR_Z str_z;
    }
    
    [StructLayout (LayoutKind.Sequential)]
    public struct STR_Z
    {
        public uint id;
    
        [MarshalAs(UnmanagedType.ByValArray,SizeConst=64)]
        public byte[] buff;
    }
    
    [DllImport ("__Internal")]
    static public extern unsafe int methodCallbyDll (Action<IntPtr> callback);
    
    
    //dllMethodに渡す Action<IntPtr> callbackの実装部分
    static void CtrlCallback (IntPtr ptr)
    {
        var str_a = (STR_A)Marshal.PtrToStructure (ptr, typeof(STR_A));
    
        var p_str_x = str_a.data.str_x;
    
        //null例外が発生せず、配列のデータを参照可能
        Debug.WriteLine("p_str_x.str_z.buff[0]=" + p_str_x.str_z.buff[0]);
    
        //System.NullReferenceExceptionが発生 - ※
        Debug.WriteLine("p_str_x.buff[0]=" + p_str_x.buff[0]);
    
    }
    
[/code]


CC BY-SA 3.0
2016-11-11T12:15:43.163
30329
2016-11-14T10:09:26.757
2016-11-14T10:09:26.757
3766
3766
question
ios c# c xamarin xamarin-native
C# - Binding時、構造体内の配列が nullになる場合の原因について


.NET
Frameworkの仕様としては`STR_A`は`byte`とカスタム型がオーバーラップしているため無効ですが、`STR_X`としてなら読み出せるのが正しいです。おそらくXamarin固有の問題ではないかと思います。

固定長配列が2か所存在しているのが想定外なのではないかという印象を受けるため、`STR_X.buff`を`byte`型フィールド8個や`long`などに変更して、必要時にメソッドで`byte[]`へ変換するような仕様に変えると回避できるかもしれません。

また場当たり的ですが自力で`IntPtr`から読みだしてみることもできます。

[code]

    STR_X p_str_x;
    p_str_x.buff = new byte[8];
    Marshal.Copy(ptr, p_str_x.buff, 0, 8);
    
    p_str_x.str_z.id = (uint)Marshal.ReadInt32(ptr, 8);
    
    p_str_x.str_z.buff = new byte[64];
    Marshal.Copy(ptr + 12, p_str_x.str_z.buff, 0, 64);
    
[/code]


CC BY-SA 3.0
2016-11-11T12:52:30.510
30330
2016-11-11T13:00:33.430
2016-11-11T13:00:33.430
5750
5750
30329
answer