解组包含结构数组的Struct

时间:2013-11-15 08:50:45

标签: c# c pinvoke

我正试图通过P / Invoke从本地C库中取回这个结构:

struct ndb_mgm_cluster_state 
{
    int no_of_nodes;
    struct ndb_mgm_node_state node_states[1];
};

其中ndb_mgm_node_state是:

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;
}; 

该方法的签名是:

 ndb_mgm_cluster_state* WINAPI wrap_ndb_mgm_get_status(HANDLE handle);

所有这些都是由第三方库提供的,因此无法更改任何内容。 在C#中,我有以下定义:

[DllImport("Ndb_CWrapper.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr wrap_ndb_mgm_get_status(IntPtr handle);

结构是:

[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;
  };

我试图解密结果但没有成功(我收到一个奇怪的错误(不是异常)致命错误执行,可能是CLR错误或错误调用P / invoke。

显然原因是我的P / Invoke调用中存在问题

我试过这样的方式: 首先,我解组了ndb_mgm_cluster_state结构:

var res=(ndb_mgm_cluster_state)Marshal.PtrToStructure(
                               tmpPtr, typeof(ndb_mgm_cluster_state));

其中IntPtr是本机调用的结果。 到目前为止,所有“似乎”都要正确完成,但是当我尝试解组时node_states我得到了错误:

ndb_mgm_node_state tmpNode = (ndb_mgm_node_state)Marshal.PtrToStructure(
 status.node_states, typeof(ndb_mgm_node_state));

可能是什么问题?我认为是与ndb_mgm_cluster_state的奇怪声明有关的东西,因为它定义了一个1元素的数组,但它包含几个元素。 (元素数量在no_of_nodes

解决方法:

让我发现一切正常的唯一方法是以这种方式改变签名:

ndb_mgm_node_state* WINAPI wrap_ndb_mgm_get_status(HANDLE handle,int* length);
在C#中

[DllImport("Ndb_CWrapper.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr wrap_ndb_mgm_get_status(IntPtr handle,out int length);

其中length包含no_of_nodes

unmarshall将以这种方式:

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 < 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]);
  }

我知道步数计算在数字上是奇数,但不是那个点。 没有办法让这个东西直接返回ndb_mgm_cluster_state结构而不是完成所有这些吗?

0 个答案:

没有答案