1

外部ライブラリ関数の呼び出しで構造体をマーシャリングするのに問題があります。呼び出し自体からエラーは発生しませんが、関数は、渡された値を正しく理解していないことを示すエラー コードを返します。

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

2 に答える 2

2

次のように装飾する必要があると思いますstruct_id

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

それ以外の場合、C# 構造体には配列への参照が含まれますが、C++ 構造体には実際の 4 バイト配列が含まれます。

于 2012-04-12T16:47:51.070 に答える
1

に を追加SizeConstし、struct_idと から削除する必要が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;
    }
}
于 2012-04-12T16:52:54.477 に答える