OutArrayOfStructs のサンプル
更新 : 2007 年 11 月
このサンプルでは、整数および文字列を含む構造体の配列を、Out パラメータとしてアンマネージ関数に渡す方法を示します。サンプルのソース コードは、「プラットフォーム呼び出しの技術サンプル」で提供されています。
このサンプルでは、Marshal クラスおよびアンセーフ コードを使用してネイティブ関数を呼び出す方法を示します。
このサンプルでは、ソース ファイルにも含まれている、PinvokeLib.dll に定義されたラッパー関数とプラットフォーム呼び出しを使用します。使用するのは、TestOutArrayOfStructs 関数と MYSTRSTRUCT2 構造体です。この構造体には次の要素が含まれます。
typedef struct _MYSTRSTRUCT2
{
char* buffer;
UINT size;
} MYSTRSTRUCT2;
MyStruct クラスには ANSI 文字の文字列オブジェクトが含まれます。CharSet フィールドによって ANSI 形式を指定します。MyUnsafeStruct は、文字列の代わりに IntPtr 型を格納している構造体です。
LibWrap クラスには、オーバーロードされた TestOutArrayOfStructs プロトタイプ メソッドが含まれます。メソッドがパラメータとしてポインタを宣言する場合、そのクラスに unsafe キーワードでマークを付ける必要があります。Visual Basic 2005 では保証されないコードを使用できないため、オーバーロードされたメソッド、保証されない修飾子、および構造体 MyUnsafeStruct は不要になります。
App クラスは UsingMarshal メソッドを実装します。このメソッドは、配列を渡すために必要なタスクをすべて実行します。配列には、呼び出し先から呼び出し元にデータを渡すことを示す out キーワード (Visual Basic では ByRef) でマークが付けられます。この実装は、次に示す Marshal クラス メソッドを使用します。
PtrToStructure は、アンマネージ バッファからマネージ オブジェクトへとデータをマーシャリングします。
DestroyStructure は、構造体に含まれる文字列用に予約したメモリを解放します。
FreeCoTaskMem は、配列用に予約したメモリを解放します。
前述のように、C# では保証されないコードが使用されますが、Visual Basic 2005 では使用されません。C# のサンプルの UsingUnsafe は、Marshal クラスの代わりにポインタを使用する代替メソッド実装であり、MyUnsafeStruct 構造体を含む配列を返します。
プロトタイプの宣言
' Declares a class member for each structure element.
< StructLayout( LayoutKind.Sequential, CharSet:=CharSet.Ansi )> _
Public Class MyStruct
Public buffer As String
Public someSize As Integer
End Class 'MyStruct
Public Class LibWrap
' Declares a managed prototype for the unmanaged function.
Declare Sub TestOutArrayOfStructs Lib "..\\LIB\\PinvokeLib.dll" ( _
ByRef arrSize As Integer, ByRef outArray As IntPtr )
End Class 'LibWrap
// Declares a class member for each structure element.
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public class MyStruct
{
public String buffer;
public int size;
}
// Declares a structure with a pointer.
[ StructLayout( LayoutKind.Sequential )]
public struct MyUnsafeStruct
{
public IntPtr buffer;
public int size;
}
public unsafe class LibWrap
{
// Declares managed prototypes for the unmanaged function.
[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern void TestOutArrayOfStructs( out int size,
out IntPtr outArray );
[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern void TestOutArrayOfStructs( out int size,
MyUnsafeStruct** outArray );
}
関数の呼び出し
Public Class App
Public Shared Sub Main()
Console.WriteLine( ControlChars.CrLf & "Using marshal class" & _
ControlChars.CrLf )
UsingMarshal()
'Visual Basic 2005 cannot use unsafe code.
End Sub 'Main
Public Shared Sub UsingMarshal()
Dim arrSize As Integer
Dim outArray As IntPtr
LibWrap.TestOutArrayOfStructs( arrSize, outArray )
Dim manArray(arrSize - 1) As MyStruct
Dim current As IntPtr = outArray
Dim i As Integer
For i = 0 To arrSize - 1
manArray(i) = New MyStruct()
Marshal.PtrToStructure( current, manArray(i))
Marshal.DestroyStructure( current, GetType( MyStruct ))
current = IntPtr.op_explicit( current.ToInt64() _
+ Marshal.SizeOf( manArray(i) ))
Console.WriteLine( "Element {0}: {1} {2}", i, manArray(i)._
buffer, manArray(i).someSize )
Next i
Marshal.FreeCoTaskMem( outArray )
End Sub 'UsingMarshal
End Class 'App
public class App
{
public static void Main()
{
Console.WriteLine( "\nUsing marshal class\n" );
UsingMarshal();
Console.WriteLine( "\nUsing unsafe code\n" );
UsingUnsafe();
}
public static void UsingMarshal()
{
int size;
IntPtr outArray;
LibWrap.TestOutArrayOfStructs( out size, out outArray );
MyStruct[] manArray = new MyStruct[ size ];
IntPtr current = outArray;
for( int i = 0; i < size; i++ )
{
manArray[ i ] = new MyStruct();
Marshal.PtrToStructure( current, manArray[ i ]);
//Marshal.FreeCoTaskMem( (IntPtr)Marshal.ReadInt32( current ));
Marshal.DestroyStructure( current, typeof(MyStruct) );
current = (IntPtr)((long)current +
Marshal.SizeOf( manArray[ i ] ));
Console.WriteLine( "Element {0}: {1} {2}", i,
manArray[ i ].buffer, manArray[ i ].size );
}
Marshal.FreeCoTaskMem( outArray );
}
public static unsafe void UsingUnsafe()
{
int size;
MyUnsafeStruct* pResult;
LibWrap.TestOutArrayOfStructs( out size, &pResult );
MyUnsafeStruct* pCurrent = pResult;
for( int i = 0; i < size; i++, pCurrent++ )
{
Console.WriteLine( "Element {0}: {1} {2}", i,
Marshal.PtrToStringAnsi( pCurrent->buffer ), pCurrent->size );
Marshal.FreeCoTaskMem( pCurrent->buffer );
}
Marshal.FreeCoTaskMem( (IntPtr)pResult );
}
}