在对外部 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;
    }
}

在对外部 C 库的调用中封送结构

我认为你必须像这样装饰struct_id

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=4, ArraySubType=UnmanagedType.U1)] 
public byte[] struct_id;

否则,C# 结构将包含对数组的引用,而C++结构包含实际的 4 字节数组。

您需要

struct_id添加一个SizeConst并将其从usernamepassword中删除。 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;
    }
}