在对外部 C 库的调用中封送结构
本文关键字:结构 调用 对外部 | 更新日期: 2023-09-27 18:31:07
我在调用外部库函数时在编组结构时遇到了一些问题。我从调用本身没有收到任何错误,但该函数返回一个错误代码,表明它没有正确理解传入的值。
这是 C 函数的签名
DLLExport int connect(Client handle, connectOptions* options);
这是我的内部功能
[DllImport("some.dll", CharSet = CharSet.Auto, ExactSpelling = false,
CallingConvention = CallingConvention.Cdecl)]
private static extern int connect(IntPtr client, connectOptions options);
这是我正在使用的connectOptions
结构的规范
char struct_id [4]
int struct_version
int keepAliveInterval
int cleansession
int reliable
willOptions * will
char * username
char * password
int connectTimeout
int retryInterval
最后是我的应用程序中的类
[StructLayout(LayoutKind.Sequential)]
public class connectOptions
{
public byte[] struct_id;
public Int32 struct_version;
public Int32 keepAliveInterval;
public Int32 cleansession;
public Int32 reliable;
public willOptions will;
[MarshalAs(UnmanagedType.LPStr, SizeConst = 128)]
public string username;
[MarshalAs(UnmanagedType.LPStr, SizeConst = 128)]
public string password;
public Int32 connectTimeout;
public Int32 retryInterval;
public connectOptions()
{
struct_id = Encoding.ASCII.GetBytes("WXYZ");
struct_version = 0;
keepAliveInterval = 20;
cleansession = 1;
reliable = 0;
username = string.Empty;
password = string.Empty;
connectTimeout = 10;
retryInterval = 1;
will = null;
}
}
[StructLayout(LayoutKind.Sequential)]
public class willOptions
{
public byte[] struct_id;
Int32 struct_version;
[MarshalAs(UnmanagedType.LPStr, SizeConst = 128)]
public string topicName;
[MarshalAs(UnmanagedType.LPStr, SizeConst = 128)]
public string message;
public Int32 retained;
public Int32 qos;
public willOptions()
{
struct_id = Encoding.ASCII.GetBytes("VWXY");
struct_version = 0;
}
}
我认为你必须像这样装饰struct_id
:
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=4, ArraySubType=UnmanagedType.U1)]
public byte[] struct_id;
否则,C# 结构将包含对数组的引用,而C++结构包含实际的 4 字节数组。
您需要
向struct_id
添加一个SizeConst
并将其从username
和password
中删除。 SizeConst
参数指示数组或字符串的内存作为结构内的恒定大小数组存储,而不是作为指针存储。
例如,以下内容是有效的:
三:
struct c_struct {
char value[100];
}
C#:
public struct c_struct {
[MarshalAs(UnmanagedType.LPStr, SizeConst = 128)]
public string value;
}
您的结构定义应该是:
[StructLayout(LayoutKind.Sequential)]
public class connectOptions
{
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=4, ArraySubType=UnmanagedType.U1)]
public byte[] struct_id;
public Int32 struct_version;
public Int32 keepAliveInterval;
public Int32 cleansession;
public Int32 reliable;
public willOptions will;
public string username;
public string password;
public Int32 connectTimeout;
public Int32 retryInterval;
public connectOptions()
{
struct_id = Encoding.ASCII.GetBytes("WXYZ");
struct_version = 0;
keepAliveInterval = 20;
cleansession = 1;
reliable = 0;
username = string.Empty;
password = string.Empty;
connectTimeout = 10;
retryInterval = 1;
will = null;
}
}