2


0

64ビットP /呼び出し特異性

P / Invokeの構造体を適切にマーシャリングしようとしていますが、64ビットOSでテストすると奇妙な動作を見つけています。

私は次のように定義された構造体を持っています:

/// http://msdn.microsoft.com/en-us/library/aa366870(v=VS.85).aspx
[StructLayout(LayoutKind.Sequential)]
private struct MIB_IPNETTABLE
{
    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dwNumEntries;
    public IntPtr table; //MIB_IPNETROW[]
}

次に、テーブルのアドレスを取得するために、次のようにMarshal.OffsetOf()呼び出しを実行します。

IntPtr offset = Marshal.OffsetOf(typeof(MIB_IPNETTABLE), "table");

これは4である必要があります。これを確認するためにバッファーのバイトをダンプし、上記の呼び出しをポインター計算でハードコードされた4に置き換えて、正しい結果を得ました。

MIB_IPNETTABLEをインスタンス化し、次の呼び出しを実行すると、予想される4が取得されます。

IntPtr offset = (IntPtr)Marshal.SizeOf(ipNetTable.dwNumEntries);

さて、シーケンシャル構造体では、フィールドのオフセットは前のフィールドのサイズの合計でなければなりません、正しいですか? または、アンマネージ構造の場合、オフセットは実際には8(x64システム上)ですが、マーシャリングマジックの後でのみ4になりますか? OffsetOf()呼び出しを取得して正しいオフセットを取得する方法はありますか? SizeOf()の呼び出しを使用してリンプできますが、OffsetOf()は大きな構造体の方が簡単です。

1 Answer


2


64ビットC / C ++ビルドでは、アライメント要件のために(テーブルを強制しない限り)、「テーブル」フィールドのオフセットは8になります。 CLRがあなたに同じことをしているのではないかと思います。

_ オブジェクトのメンバーは、アンマネージメモリにエクスポートされたときに表示される順序で順番に配置されます。 メンバーは、 `StructLayoutAttribute.Pack`で指定されたパッキングに従ってレイアウトされ、不連続になる場合があります。 _

そのレベルの制御が必要な場合は、その属性を使用するか、各フィールドで FieldOffset`属性とともに LayoutKind.Explicit`属性を使用することができます。