C++には次の構造体があります。
#define MAXCHARS 15
typedef struct
{
char data[MAXCHARS];
int prob[MAXCHARS];
} LPRData;
そして、これらの構造の3つの配列を取得するために私がp /呼び出している関数:
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構造から「データ」文字列を取得しますが、同じLPRDataからの「prob」配列を含めて、その後は何も取得しません。
これを適切に処理する方法のアイデアはありますか?
構造体のデクロレーションにいくつかの属性を追加してみます
[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/1412
GetDataパラメーターを OutAttribute でマークしましたか?
InAttributeとOutAttributeの組み合わせは、配列およびフォーマットされた非blittable型に適用される場合に特に役立ちます。発信者は、両方の属性を適用した場合にのみ、着信者がこれらのタイプに加える変更を確認できます。
同様のトピックが この質問 で議論され、結論の1つは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;
}