在调用外部C库时对结构进行编组

时间:2012-04-12 16:41:27

标签: c# .net pinvoke marshalling

在调用外部库函数时,我在编组结构时遇到了一些麻烦。我从调用本身没有错误,但该函数返回一个错误代码,表明它没有正确理解传入的值。

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

2 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

您需要向SizeConst添加struct_id,然后将其从usernamepassword中删除。 SizeConst参数表示数组或字符串的内存在结构内部存储为常量大小的数组而不是指针。

例如,以下内容有效:

C:

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