構造体のサンプル
更新 : 2007 年 11 月
このサンプルでは、第 2 の構造体を指す構造体の渡し方、埋め込み構造体を含む構造体の渡し方、および埋め込み配列を含む構造体の渡し方を示します。
次のコード例のソース コードは、.NET Framework「プラットフォーム呼び出しの技術サンプル」で提供されています。
Structs のサンプルで使用するアンマネージ関数とその関数宣言を次に示します。
PinvokeLib.dll からエクスポートされる TestStructInStruct
int TestStructInStruct(MYPERSON2* pPerson2);
PinvokeLib.dll からエクスポートされる TestStructInStruct3
void TestStructInStruct3(MYPERSON3 person3);
PinvokeLib.dll からエクスポートされる TestArrayInStruct
void TestArrayInStruct( MYARRAYSTRUCT* pStruct );
PinvokeLib.dll はカスタム アンマネージ ライブラリであり、上記の関数および構造体 MYPERSON、MYPERSON2、MYPERSON3、および MYARRAYSTRUCT に関する実装を含みます。これらの構造体には次の要素が含まれます。
typedef struct _MYPERSON
{
char* first;
char* last;
} MYPERSON, *LP_MYPERSON;
typedef struct _MYPERSON2
{
MYPERSON* person;
int age;
} MYPERSON2, *LP_MYPERSON2;
typedef struct _MYPERSON3
{
MYPERSON person;
int age;
} MYPERSON3;
typedef struct _MYARRAYSTRUCT
{
bool flag;
int vals[ 3 ];
} MYARRAYSTRUCT;
マネージ構造体の MyPerson、MyPerson2、MyPerson3、および MyArrayStruct には、次に示す特性があります。
MyPerson には文字列メンバだけが含まれます。CharSet フィールドは、アンマネージ関数に渡されたときに文字列を ANSI 形式に設定します。
MyPerson2 には MyPerson 構造体への IntPtr が含まれます。コードに unsafe マークが付いていない場合、.NET Framework アプリケーションはポインタを使用しないため、アンマネージ構造体を指す元のポインタは IntPtr 型に置き換えられます。
MyPerson3 には埋め込み構造体としての MyPerson が含まれます。別の構造体に埋め込まれた構造体は、埋め込み構造体の要素を主構造体に直接配置して平坦化することも、このサンプルのように埋め込み構造体のままにしておくこともできます。
MyArrayStruct には整数の配列が含まれます。MarshalAsAttribute 属性により、UnmanagedType 列挙値に ByValArray が設定されます。これは、配列に属する要素の数を示すために使用されます。
このサンプルでは、各メンバが出現する順番でメモリ内に順次配列されることを保証するために、すべての構造体に StructLayoutAttribute 属性が適用されます。
LibWrap クラスには App クラスによって呼び出される TestStructInStruct、TestStructInStruct3、および TestArrayInStruct メソッドのマネージ プロトタイプが含まれます。各プロトタイプは、次に示すように 1 つのパラメータを宣言します。
TestStructInStruct は MyPerson2 型への参照を独自のパラメータとして宣言します。
TestStructInStruct3 は MyPerson3 型を独自のパラメータとして宣言し、そのパラメータを値渡しします。
TestArrayInStruct は MyArrayStruct 型への参照を独自のパラメータとして宣言します。
メソッドへの引数としての構造体は、パラメータの中にキーワード ref (Visual Basic では ByRef) が含まれる場合を除き、値渡しされます。たとえば、the TestStructInStruct メソッドは MyPerson2 型のオブジェクトへの参照 (アドレスの値) をアンマネージ コードに渡します。MyPerson2 が指す構造体を操作するには、サンプルでは、指定したサイズのバッファを作成し、Marshal.AllocCoTaskMem メソッドと Marshal.SizeOf メソッドを組み合わせることにより、そのアドレスを返します。次に、マネージ構造体の内容をアンマネージ バッファにコピーします。最後に、Marshal.PtrToStructure メソッドによってアンマネージ バッファからマネージ オブジェクトへとデータをマーシャリングし、Marshal.FreeCoTaskMem メソッドによってメモリのアンマネージ ブロックを解放します。
プロトタイプの宣言
' Declares a managed structure for each unmanaged structure.
< StructLayout( LayoutKind.Sequential, CharSet := CharSet.Ansi )> _
Public Structure MyPerson
Public first As String
Public last As String
End Structure 'MyPerson
< StructLayout( LayoutKind.Sequential )> _
Public Structure MyPerson2
Public person As IntPtr
Public age As Integer
End Structure 'MyPerson2
< StructLayout( LayoutKind.Sequential )> _
Public Structure MyPerson3
Public person As MyPerson
Public age As Integer
End Structure 'MyPerson3
< StructLayout( LayoutKind.Sequential )> _
Public Structure MyArrayStruct
Public flag As Boolean
< MarshalAs( UnmanagedType.ByValArray, SizeConst:=3 )> _
Public vals As Integer()
End Structure 'MyArrayStruct
Public Class LibWrap
' Declares managed prototypes for unmanaged functions.
Declare Function TestStructInStruct Lib "..\LIB\PinvokeLib.dll" ( _
ByRef person2 As MyPerson2 ) As Integer
Declare Function TestStructInStruct3 Lib "..\LIB\PinvokeLib.dll" ( _
ByVal person3 As MyPerson3 ) As Integer
Declare Function TestArrayInStruct Lib "..\LIB\PinvokeLib.dll" ( _
ByRef myStruct As MyArrayStruct ) As Integer
End Class 'LibWrap
// Declares a managed structure for each unmanaged structure.
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public struct MyPerson
{
public String first;
public String last;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyPerson2
{
public IntPtr person;
public int age;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyPerson3
{
public MyPerson person;
public int age;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyArrayStruct
{
public bool flag;
[ MarshalAs( UnmanagedType.ByValArray, SizeConst=3 )]
public int[] vals;
}
public class LibWrap
{
// Declares a managed prototype for unmanaged function.
[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern int TestStructInStruct( ref MyPerson2 person2 );
[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern int TestStructInStruct3( MyPerson3 person3 );
[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern int TestArrayInStruct( ref MyArrayStruct
myStruct );
}
関数の呼び出し
Public Class App
Public Shared Sub Main()
' Structure with a pointer to another structure.
Dim personName As MyPerson
personName.first = "Mark"
personName.last = "Lee"
Dim personAll As MyPerson2
personAll.age = 30
Dim buffer As IntPtr = Marshal.AllocCoTaskMem( Marshal.SizeOf( _
personName ))
Marshal.StructureToPtr( personName, buffer, False )
personAll.person = buffer
Console.WriteLine( ControlChars.CrLf & "Person before call:" )
Console.WriteLine( "first = {0}, last = {1}, age = {2}", _
personName.first, personName.last, personAll.age )
Dim res As Integer = LibWrap.TestStructInStruct( personAll )
Dim personRes As MyPerson = _
CType( Marshal.PtrToStructure( personAll.person, _
GetType( MyPerson )), MyPerson )
Marshal.FreeCoTaskMem( buffer )
Console.WriteLine( "Person after call:" )
Console.WriteLine( "first = {0}, last = {1}, age = {2}", _
personRes.first, _
personRes.last, personAll.age )
' Structure with an embedded structure.
Dim person3 As New MyPerson3()
person3.person.first = "John"
person3.person.last = "Evens"
person3.age = 27
LibWrap.TestStructInStruct3( person3 )
' Structure with an embedded array.
Dim myStruct As New MyArrayStruct()
myStruct.flag = False
Dim array( 2 ) As Integer
myStruct.vals = array
myStruct.vals( 0 ) = 1
myStruct.vals( 1 ) = 4
myStruct.vals( 2 ) = 9
Console.WriteLine( ControlChars.CrLf & "Structure with array _
before call:" )
Console.WriteLine( myStruct.flag )
Console.WriteLine( "{0} {1} {2}", myStruct.vals( 0 ), _
myStruct.vals( 1 ), myStruct.vals( 2 ) )
LibWrap.TestArrayInStruct( myStruct )
Console.WriteLine( ControlChars.CrLf & "Structure with array _
after call:" )
Console.WriteLine( myStruct.flag )
Console.WriteLine( "{0} {1} {2}", myStruct.vals( 0 ), _
myStruct.vals( 1 ), myStruct.vals( 2 ) )
End Sub 'Main
End Class 'App
public class App
{
public static void Main()
{
// Structure with a pointer to another structure.
MyPerson personName;
personName.first = "Mark";
personName.last = "Lee";
MyPerson2 personAll;
personAll.age = 30;
IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf(
personName ));
Marshal.StructureToPtr( personName, buffer, false );
personAll.person = buffer;
Console.WriteLine( "\nPerson before call:" );
Console.WriteLine( "first = {0}, last = {1}, age = {2}",
personName.first, personName.last, personAll.age );
int res = LibWrap.TestStructInStruct( ref personAll );
MyPerson personRes =
(MyPerson)Marshal.PtrToStructure( personAll.person,
typeof( MyPerson ));
Marshal.FreeCoTaskMem( buffer );
Console.WriteLine( "Person after call:" );
Console.WriteLine( "first = {0}, last = {1}, age = {2}",
personRes.first, personRes.last, personAll.age );
// Structure with an embedded structure.
MyPerson3 person3 = new MyPerson3();
person3.person.first = "John";
person3.person.last = "Evens";
person3.age = 27;
LibWrap.TestStructInStruct3( person3 );
// Structure with an embedded array.
MyArrayStruct myStruct = new MyArrayStruct();
myStruct.flag = false;
myStruct.vals = new int[ 3 ];
myStruct.vals[ 0 ] = 1;
myStruct.vals[ 1 ] = 4;
myStruct.vals[ 2 ] = 9;
Console.WriteLine( "\nStructure with array before call:" );
Console.WriteLine( myStruct.flag );
Console.WriteLine( "{0} {1} {2}", myStruct.vals[ 0 ],
myStruct.vals[ 1 ], myStruct.vals[ 2 ] );
LibWrap.TestArrayInStruct( ref myStruct );
Console.WriteLine( "\nStructure with array after call:" );
Console.WriteLine( myStruct.flag );
Console.WriteLine( "{0} {1} {2}", myStruct.vals[ 0 ],
myStruct.vals[ 1 ], myStruct.vals[ 2 ] );
}
}