2009-09-21 25 views
5

私はいくつかのC#interopの作業をしています。私は、次の構造体を持っている:C#:配列を含む構造体をマーシャリングする

#pragma pack(push,1) 
typedef struct 
{ 
    unsigned __int64 Handle; 
    LinkType_t Type; 
    LinkState_t State; 
    unsigned __int64 Settings; 
    signed __int8 Name[MAX_LINK_NAME]; 
    unsigned __int8 DeviceInfo[MAX_LINK_DEVINFO]; 
    unsigned __int8 Reserved[40]; 
} LinkInfo_t; 

これは、C#の構造体に変換する私の試みです:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public struct LinkInfo_t 
{ 
    [MarshalAs(UnmanagedType.U8)] 
    public UInt64 Handle; 
    MarshalAs(UnmanagedType.I4)] 
    public LinkType_t Type; 
    [MarshalAs(UnmanagedType.I4)] 
    public LinkState_t State; 
    [MarshalAs(UnmanagedType.U8)] 
    public UInt64 Settings; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst = MAX_LINK_NAME)] 
    public string Name; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_LINK_DEVINFO, ArraySubType = UnmanagedType.U1)] 
    public byte[] DeviceInfo; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40, ArraySubType = UnmanagedType.U1)] 
    public byte[] Reserved; 
} 

しかし、私は名前、DEVICEINFO、および予約フィールドがすべて設定されている構造体を初期化する時はいつでもnullにするこれをどうやって解決するのですか?

答えて

7

配列の場合、fixed修飾子を使用してみてください:私は構造体 名、DEVICEINFOを初期化するたび

public fixed byte DeviceInfo[MAX_LINK_DEVINFO]; 
    public fixed byte Reserved[40]; 
+0

これは配列に対して機能します。ただし、正しい構文は パブリック固定バイトDeviceInfo [MAX_LINK_DEVINFO]です。 また、構造体が安全でないと宣言する必要があります。 –

+0

あなたは正しいですが、安全ではなく固定された –

3

をし、予約済みフィールドは はすべてnullに設定されている

これは正しかった、あなたの定義は私にはよく見えます(BTWでは、プリミティブフィールドに[MarshalAs]は必要ありません。デフォルトの振る舞いは、あなたが指定したものを実行することです)。配列フィールドはnullなので、マーシャラは構造体をアンマネージメモリにマーシャリングするときは何も行いませんが、アンマーシャリング時には文字列と配列を作成します。

+1

を修正しました。コードは、使用する前にバイト配列を割り当てる必要があります。私は通常、配列が自動的に割り当てられるp/invokeのための構造体のコンストラクタを持っています。 – erict

0

Anton Tykhyyが言うことは正しいと言います。私はいくつかの例を明確にしたい。 '固定'の作品を使用して、それはあなたも '安全でない'を使用するように強制します。私は可能な限り安全でない使用を避けたい。マーシャルを使用すると、そのことを回避する方法です。

まず、次の定義でC言語で作成されたライブラリがあるとします。 C#ので

typedef struct { 
    int messageType; 
    BYTE payload[60]; 
} my_message; 

/** 
* \param[out] msg Where the message will be written to 
*/ 
void receiveMessage(my_message *msg); 

/* 
* \param[in] msg The message that will be sent 
*/ 
void sendMessage(my_message *msg); 

、以下の構造がreceiveMessage(中MSG以来C.

[StructLayout(LayoutKind.Sequential, Size = 64), Serializable] 
struct my_message 
{ 
    int messageType; 
    [MarshalAs(UnmanagedType.ByValArray,SizeConst = 60)] 
    byte[] payload; 

    public initializeArray() 
    { 
     //explicitly initialize the array 
     payload = new byte[60]; 
    } 
} 

の1に相当します)と[出力]文書化されて、あなたは何をする必要はありません。関数に渡す前に、構造体の配列にとって特別なもの。すなわち:のsendMessageでMSGは、()[中]として文書化されているので

my_message msg = new my_message(); 
receiveMessage(ref msg); 
byte payload10 = msg.payload[10]; 

、あなたは関数を呼び出す前に、配列を入力する必要があります。配列を塗りつぶす前に、配列を明示的にインスタンス化してから使用する必要があります。 initializeArray()を呼び出すと、この配列の構造体内に作成された以前に割り当てられた領域の配列がインスタンス化されます。

関連する問題