C# Managed構造体とUnmanaged構造体のマッピング

Managed構造体とC等のUnmanaged構造体のマッピング

Managed構造体はC等の構造体と異なり、メンバの格納順序が定義順にならなかったり、C等の固定長配列が言語仕様上定義できなかったりする。

これらの点はWindows APIに構造体パラメータを渡したり、共有メモリ等でC等のUnmanaged言語とデータを共有したりする場面で問題が発生する。

そこで、C#(.NET Framework)では、構造体やメンバに対して属性を指定することにより、ManagedとUnmanagedで相互交換を行わせる事ができるようになっている。

例えば、以下のようなCの構造体

struct Info
{
  int    index;
  char    name[128];
  int    statuses[50];
};

とメンバ順序もサイズも同じManaged構造体を定義するには属性を使用して以下のように定義。

[StructLayout(LayoutKind.Sequential)]    // メンバーは定義順に格納される
public struct Info
{
  [MarshalAs(UnmanagedType.I4)]        // Signed int(4Byte)で格納(属性無くても大丈夫です)
  public    int    index;
  [MarshalAs(UnmanagedType.ByvalTStr,SizeConst=128)]    // char[128]で格納
  public    string name;
  [MarshalAs(UnmanagedType.ByvalArray,SizeConst=50)]    // int[50]で格納
  public    int[] statuses;
  // ↑bool, byte, char, short, int, long, sbyte, ushort,
  // uint, ulong, float, double配列の場合は属性を付けずに以下のようにしても良い
  // この場合は配列のインスタンスを作成する必要は無い。→これはunsafeブロック中でしか使えないらしい・・・
  // public fixed int statuses[50];
}

注意しなければならないのは、上記のstatusesは必ず、50要素の配列として配列のインスタンスを作成しなければならない点。(コメントに書いてある表記をした場合を除く)

Info inf;
inf.Statuses = new int[50];

また、Unmanaged構造体のAlignmentにも注意

(Alignmentも属性を使用して定義可能。)

[StructLayout(LayoutKind.Sequential,Pack=4)]    // Alignment = 4

 

このようにManaged側でUnamanaged側に合わせることにより、構造体の相互参照が可能となる。

ちなみに、Managed側からUnmanaged側のポインタへ構造体内容をコピーするにはMarshal.StructureToPtrメソッドを使用する。

static void Marshal.StructureToPtr(object structure, IntPtr dest, bool fDeleteOld)

IntPtr mem = ….    // 共有メモリのマップ等
Marshal.StructureToPtr(inf,mem,true);

 

逆に、UnmanagedからManaged構造体を取得するにはMarshal.PtrToStructureメソッドを使用する。

static object Marshal.PtrToStructure(IntPtr src, Type StructureType)

Info inf = (Info)Marshal.PtrToStructure(mem,typeof(Info));

 

忘れないようにメモ。

たけぞう

たけぞう について

某ソフトウェア開発会社勤務。 開発の仕事は卒業しますた。 ・・・と思ったら、また開発に逆戻り(^^; ・・・と思ったら、また卒業らしい・・・
カテゴリー: .NETフレームワーク, C#, 技術情報 パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です