0

我正在尝试通过 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);

所有这些都是由 3rd 方库提供的,因此无法更改。在 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);

其中长度包含no_of_nodes

解组将以这种方式:

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结构而不是做所有这些?

4

0 回答 0