Marshal C ++ struct array to C#
-
06-07-2019 - |
質問
C ++には次の構造体があります:
#define MAXCHARS 15
typedef struct
{
char data[MAXCHARS];
int prob[MAXCHARS];
} LPRData;
そして、これらの構造の3つの配列を取得するためにp / invokingしている関数:
void GetData(LPRData *data);
C ++では、次のようにします。
LPRData *Results;
Results = (LPRData *)malloc(MAXRESULTS*sizeof(LPRData));
GetData( Results );
そしてそれはうまく動作しますが、C#では動作するように思えません。 次のようなC#構造体を作成しました。
public struct LPRData
{
/// char[15]
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
public string data;
/// int[15]
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
public int[] prob;
}
そして、それらのうち3つの配列(およびそれらのすべてのサブ配列)を初期化し、これに渡す場合:
GetData(LPRData[] data);
成功して戻りますが、LPRData配列のデータは変更されていません。
3つのLPRDataのサイズの生のバイト配列を作成し、次のような関数プロトタイプに渡しました:
GetData(byte [] data);
しかしその場合、「データ」を取得します;最初のLPRData構造からの文字列、ただし「prob」を含むその後同じLPRDataの配列。
これを適切に処理するためのアイデアはありますか?
解決
構造体のデクローレーションにいくつかの属性を追加してみます
[StructLayout(LayoutKind.Sequential, Size=TotalBytesInStruct),Serializable]
public struct LPRData
{
/// char[15]
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
public string data;
/// int[15]
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
public int[] prob;
}
*注TotalBytesInStructは変数を表すことを意図していません
JaredParは、IntPtrクラスを使用するのが役立つ可能性があることも正しいですが、PInvokeを使用してからかなり時間が経ったのでさびています。
他のヒント
ポインターを扱うときの1つのトリックは、IntPtrを使用することです。その後、ポインターでMarshal.PtrToStructureを使用し、構造のサイズに基づいて増分して結果を取得できます。
static extern void GetData([Out] out IntPtr ptr);
LPRData[] GetData()
{
IntPtr value;
LPRData[] array = new LPRData[3];
GetData(out value);
for (int i = 0; i < array.Length; i++)
{
array[i] = Marshal.PtrToStructure(value, typeof(LPRData));
value += Marshal.SizeOf(typeof(LPRData));
}
return array;
}
PInvoke Interop Assistantが役立つ場合があります。 http://clrinterop.codeplex.com/releases/view/14120
GetDataパラメーターを OutAttribute でマークしました?
InAttributeと OutAttributeは特に便利です 配列に適用してフォーマットすると、 非blittable型。発信者は 呼び出し先がこれらのタイプに加える変更 両方の属性を適用する場合のみ。
同様のトピックがこの質問と、結論は、名前付きパラメーター CharSet
を CharSet.Ansi
に設定する必要があるということでした。そうでなければ、 char
配列の代わりに wchar_t
配列を作成します。したがって、正しいコードは次のようになります。
[Serializable]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct LPRData
{
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
public string data;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
public int[] prob;
}