我正试图通过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
结构而不是完成所有这些吗?