title: Unmarshalling a Struct containing an array of structs
body: <p>I'm trying to get back this struct from a native C library through P/Invoke: </p>
  
  <pre><code>struct ndb_mgm_cluster_state 
  {
      int no_of_nodes;
      struct ndb_mgm_node_state node_states[1];
  };
  </code></pre>
  
  <p>where <code>ndb_mgm_node_state</code> is:</p>
  
  <pre><code>struct ndb_mgm_node_state {   
  
      int node_id;
  
      enum ndb_mgm_node_type   node_type;
  
      enum ndb_mgm_node_status node_status;
  
      int start_phase;
  
      int dynamic_id;
  
      int node_group;
  
      int version;
  
      int connect_count;
  
      char connect_address[sizeof("000.000.000.000")+1    ];
  
      int mysql_version;
  }; 
  </code></pre>
  
  <p>The method's signature is:</p>
  
  <pre><code> ndb_mgm_cluster_state* WINAPI wrap_ndb_mgm_get_status(HANDLE handle);
  </code></pre>
  
  <p>All of this is provided by a 3rd party library, so nothing can be changed.
  In C# i have the follow definitions:</p>
  
  <pre><code>[DllImport("Ndb_CWrapper.dll", CharSet = CharSet.Ansi)]
  private static extern IntPtr wrap_ndb_mgm_get_status(IntPtr handle);
  </code></pre>
  
  <p>the structures are:</p>
  
  <pre><code>[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  public struct ndb_mgm_cluster_state {
  
  public int no_of_nodes;
  
  public IntPtr node_states;
  };
  
  
  [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  public struct ndb_mgm_node_state 
  {
  
      public int node_id;
  
      public ndb_mgm_node_type node_type;
  
      public ndb_mgm_node_status node_status;
  
      public int start_phase;
  
      public int dynamic_id;
  
      public int node_group;
  
      public int version;
  
      public int connect_count;
  
      [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 17)]
      public string connect_address;
  
      public int mysql_version;
    };
  </code></pre>
  
  <p>I tried to unmarshal the results without success (i recieve an oddly error (not an Exception) Fatal error execution, can be a CLR bug or a miscall P/invoke.</p>
  
  <p>Obviously the reason is a problem in my P/Invoke call</p>
  
  <p>I tried in this way:
  First of all i unmarshalled the <code>ndb_mgm_cluster_state</code> structure:</p>
  
  <pre><code>var res=(ndb_mgm_cluster_state)Marshal.PtrToStructure(
                                 tmpPtr, typeof(ndb_mgm_cluster_state));
  </code></pre>
  
  <p>where <code>IntPtr</code> is the result of the native call.
  Up to this step everything "seems" to be done right, but when i try to unmarshall the <code>node_states</code> i get the error:</p>
  
  <pre><code>ndb_mgm_node_state tmpNode = (ndb_mgm_node_state)Marshal.PtrToStructure(
   status.node_states, typeof(ndb_mgm_node_state));
  </code></pre>
  
  <p>What can be the problem? I supposed is something related to the strange declaration of <code>ndb_mgm_cluster_state</code> because is defined an array of 1 element, but it contain several elements. (the number of elements is in <code>no_of_nodes</code>)</p>
  
  <p><strong>WORKAROUND:</strong></p>
  
  <p>The only way to let everything work i found is to change a bit the signature, in this way:</p>
  
  <pre><code>ndb_mgm_node_state* WINAPI wrap_ndb_mgm_get_status(HANDLE handle,int* length);
  </code></pre>
  
  <p>in C#:</p>
  
  <pre><code>[DllImport("Ndb_CWrapper.dll", CharSet = CharSet.Ansi)]
  private static extern IntPtr wrap_ndb_mgm_get_status(IntPtr handle,out int length);
  </code></pre>
  
  <p>where length contains <code>no_of_nodes</code></p>
  
  <p>the unmarshall will be in this way:</p>
  
  <pre><code>IntPtr tmpPtr = wrap_ndb_mgm_get_status(raw,out length);
  ndb_mgm_cluster_state tmpRes = new ndb_mgm_cluster_state();
  tmpRes.no_of_nodes = length;
  tmpRes.node_states = new ndb_mgm_node_state[length];
  int step=0;
  for (int i = 0; i &lt; tmpRes.no_of_nodes; i++) 
    {
     tmpRes.node_states[i] = (ndb_mgm_node_state)Marshal.PtrToStructure(
                           tmpPtr+(step*i),    typeof(ndb_mgm_node_state));
     step = Marshal.SizeOf(tmpRes.node_states[i]);
    }
  </code></pre>
  
  <p>I know the step calculation is odd at the monent, but its not that the point.
  there is no way to let the thing work returning directly the <code>ndb_mgm_cluster_state</code> struct instead of do all of this?</p>