このサンプルでは、整数および文字列を含む構造体の配列を、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 クラスは UsingMarshaling メソッドを実装します。このメソッドは、配列を渡すために必要なタスクをすべて実行します。 配列には、呼び出し先から呼び出し元にデータを渡すことを示す out キーワード (Visual Basic では ByRef) でマークが付けられます。 この実装は、次に示す Marshal クラス メソッドを使用します。
PtrToStructure は、アンマネージ バッファーからマネージ オブジェクトへとデータをマーシャリングします。
DestroyStructure は、構造体に含まれる文字列用に予約したメモリを解放します。
FreeCoTaskMem は、配列用に予約したメモリを解放します。
前述のように、C# ではアンセーフ コードが使用されますが、Visual Basic 2005 では使用されません。 C# のサンプルの UsingUnsafePointer は、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);
}
// Declares a class member for each structure element.
[StructLayout(LayoutKind::Sequential, CharSet=CharSet::Ansi)]
public ref class MyStruct
{
public:
String^ buffer;
int size;
};
// Declares a structure with a pointer.
[StructLayout(LayoutKind::Sequential)]
public value struct MyUnsafeStruct
{
public:
IntPtr buffer;
int size;
};
public ref class LibWrap
{
public:
// Declares managed prototypes for the unmanaged function.
[DllImport("..\\LIB\\PInvokeLib.dll")]
static void TestOutArrayOfStructs(int% size,
IntPtr% outArray);
[DllImport("..\\LIB\\PInvokeLib.dll")]
static void TestOutArrayOfStructs(int% size,
MyUnsafeStruct** outArray);
};
関数の呼び出し
Public Class App
Public Shared Sub Main()
Console.WriteLine( vbNewLine + "Using marshal class" + vbNewLine)
UsingMarshaling()
'Visual Basic 2005 cannot use unsafe code.
End Sub 'Main
Public Shared Sub UsingMarshaling()
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");
UsingMarshaling();
Console.WriteLine("\nUsing unsafe code\n");
UsingUnsafePointer();
}
public static void UsingMarshaling()
{
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 UsingUnsafePointer()
{
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);
}
}
public ref class App
{
public:
static void Main()
{
Console::WriteLine("\nUsing marshal class\n");
UsingMarshaling();
Console::WriteLine("\nUsing unsafe code\n");
UsingUnsafePointer();
}
static void UsingMarshaling()
{
int size;
IntPtr outArray;
LibWrap::TestOutArrayOfStructs(size, outArray);
array<MyStruct^>^ manArray = gcnew array<MyStruct^>(size);
IntPtr current = outArray;
for (int i = 0; i < size; i++)
{
manArray[i] = gcnew MyStruct();
Marshal::PtrToStructure(current, manArray[i]);
Marshal::DestroyStructure(current, MyStruct::typeid);
//current = (IntPtr)((long)current + Marshal::SizeOf(manArray[i]));
current = current + Marshal::SizeOf(manArray[i]);
Console::WriteLine("Element {0}: {1} {2}", i, manArray[i]->buffer,
manArray[i]->size);
}
Marshal::FreeCoTaskMem(outArray);
}
static void UsingUnsafePointer()
{
int size;
MyUnsafeStruct* pResult;
LibWrap::TestOutArrayOfStructs(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);
}
};