Unions のサンプル
更新 : 2007 年 11 月
このサンプルでは、値型だけを含む構造体、および値型と文字列を含む構造体をパラメータとして、共用体を要求するアンマネージ関数に渡す方法を示します。共用体は、2 つ以上の変数で共有できるメモリの位置を表します。
Unions のサンプルで使用するアンマネージ関数とその関数宣言を次に示します。
PinvokeLib.dll からエクスポートされる TestUnion
void TestUnion(MYUNION u, int type);
PinvokeLib.dll はカスタム アンマネージ ライブラリであり、上記の関数および 2 つの共用体 MYUNION および MYUNION2 に関する実装を含んでいます。この共用体には次の要素が含まれます。
union MYUNION
{
int number;
double d;
}
union MYUNION2
{
int i;
char str[128];
};
マネージ コードの中で、共用体を構造体として定義します。MyUnion 構造体には 2 つの値型、つまり整数型および倍精度浮動小数点数型がメンバとして含まれます。各データ メンバの位置を正確に制御するために、StructLayoutAttribute 属性を設定します。FieldOffsetAttribute 属性により、共用体のアンマネージ表現におけるフィールドの物理的な位置が与えられます。どちらのメンバも、オフセット値が同じあることに注意してください。したがって、同じメモリ部分を定義できます。
MyUnion2_1 および MyUnion2_2 には、値型 (整数) および文字列が含まれます。マネージ コードの中で、値型と参照型が重複することは許されません。このサンプルでは、メソッド オーバーロードを使用することで、同じアンマネージ関数を呼び出すときに呼び出し元が両方の型を使用できるようにしています。MyUnion2_1 のレイアウトは明示的であり、正確なオフセット値を持ちます。対照的に、MyUnion2_2 はシーケンシャル レイアウトを持ちます。参照型の場合には明示的なレイアウトが許されないからです。MarshalAsAttribute 属性は UnmanagedType 列挙体に ByValTStr を設定します。これは、共用体のアンマネージ表現内に出現するインラインの固定長文字配列を識別するために使用されます。
LibWrap クラスには、TestUnion メソッドと TestUnion2 メソッド用のプロトタイプが含まれます。MyUnion2_1 または MyUnion2_2 をパラメータとして宣言するために TestUnion2 がオーバーロードされます。
次のコード例のソース コードは、.NET Framework「プラットフォーム呼び出しの技術サンプル」で提供されています。
プロトタイプの宣言
' Declares managed structures instead of unions.
< StructLayout( LayoutKind.Explicit )> _
Public Structure MyUnion
< FieldOffset( 0 )> Public i As Integer
< FieldOffset( 0 )> Public d As Double
End Structure 'MyUnion
< StructLayout( LayoutKind.Explicit, Size := 128 )> _
Public Structure MyUnion2_1
< FieldOffset( 0 )> Public i As Integer
End Structure 'MyUnion2_1
< StructLayout( LayoutKind.Sequential )> _
Public Structure MyUnion2_2
< MarshalAs( UnmanagedType.ByValTStr, SizeConst := 128 )> _
Public str As String
End Structure 'MyUnion2_2
Public Class LibWrap
' Declares managed prototypes for unmanaged function.
Declare Sub TestUnion Lib "..\LIB\PinvokeLib.dll" ( _
ByVal u As MyUnion, ByVal type As Integer )
Overloads Declare Sub TestUnion2 Lib "..\LIB\PinvokeLib.dll" ( _
ByVal u As MyUnion2_1, ByVal type As Integer )
Overloads Declare Sub TestUnion2 Lib "..\LIB\PinvokeLib.dll" ( _
ByVal u As MyUnion2_2, ByVal type As Integer )
End Class 'LibWrap
// Declares managed structures instead of unions.
[ StructLayout( LayoutKind.Explicit )]
public struct MyUnion
{
[ FieldOffset( 0 )]
public int i;
[ FieldOffset( 0 )]
public double d;
}
[ StructLayout( LayoutKind.Explicit, Size=128 )]
public struct MyUnion2_1
{
[ FieldOffset( 0 )]
public int i;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyUnion2_2
{
[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )]
public String str;
}
public class LibWrap
{
// Declares managed prototypes for unmanaged function.
[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern void TestUnion( MyUnion u, int type );
[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern void TestUnion2( MyUnion2_1 u, int type );
[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern void TestUnion2( MyUnion2_2 u, int type );
}
関数の呼び出し
Public Class App
Public Shared Sub Main()
Dim mu As New MyUnion()
mu.i = 99
LibWrap.TestUnion( mu, 1 )
mu.d = 99.99
LibWrap.TestUnion( mu, 2 )
Dim mu2_1 As New MyUnion2_1()
mu2_1.i = 99
LibWrap.TestUnion2( mu2_1, 1 )
Dim mu2_2 As New MyUnion2_2()
mu2_2.str = "*** string ***"
LibWrap.TestUnion2( mu2_2, 2 )
End Sub 'Main
End Class 'App
public class App
{
public static void Main()
{
MyUnion mu = new MyUnion();
mu.i = 99;
LibWrap.TestUnion( mu, 1 );
mu.d = 99.99;
LibWrap.TestUnion( mu, 2 );
MyUnion2_1 mu2_1 = new MyUnion2_1();
mu2_1.i = 99;
LibWrap.TestUnion2( mu2_1, 1 );
MyUnion2_2 mu2_2 = new MyUnion2_2();
mu2_2.str = "*** string ***";
LibWrap.TestUnion2( mu2_2, 2 );
}
}